summaryrefslogtreecommitdiffstats
path: root/lib/libc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/Makefile.inc3
-rw-r--r--lib/libc/gen/Makefile.inc2
-rw-r--r--lib/libc/gen/getgrent.336
-rw-r--r--lib/libc/gen/getgrent.c903
-rw-r--r--lib/libc/gen/getpwent.332
-rw-r--r--lib/libc/gen/getpwent.c1665
-rw-r--r--lib/libc/gen/getusershell.326
-rw-r--r--lib/libc/gen/getusershell.c249
-rw-r--r--lib/libc/gen/pw_scan.c56
-rw-r--r--lib/libc/gen/pw_scan.h5
-rw-r--r--lib/libc/net/Makefile.inc28
-rw-r--r--lib/libc/net/getaddrinfo.34
-rw-r--r--lib/libc/net/getaddrinfo.c486
-rw-r--r--lib/libc/net/gethostbydns.c65
-rw-r--r--lib/libc/net/gethostbyht.c29
-rw-r--r--lib/libc/net/gethostbyname.317
-rw-r--r--lib/libc/net/gethostbynis.c62
-rw-r--r--lib/libc/net/gethostnamadr.c166
-rw-r--r--lib/libc/net/getipnodebyname.35
-rw-r--r--lib/libc/net/getnameinfo.34
-rw-r--r--lib/libc/net/getnetbydns.c41
-rw-r--r--lib/libc/net/getnetbyht.c27
-rw-r--r--lib/libc/net/getnetbynis.c50
-rw-r--r--lib/libc/net/getnetent.320
-rw-r--r--lib/libc/net/getnetnamadr.c174
-rw-r--r--lib/libc/net/hesiod.3136
-rw-r--r--lib/libc/net/hesiod.c572
-rw-r--r--lib/libc/net/name6.c264
-rw-r--r--lib/libc/net/nsdispatch.3231
-rw-r--r--lib/libc/net/nsdispatch.c270
-rw-r--r--lib/libc/net/nslexer.l116
-rw-r--r--lib/libc/net/nsparser.y175
32 files changed, 4010 insertions, 1909 deletions
diff --git a/lib/libc/Makefile.inc b/lib/libc/Makefile.inc
index 318ca70..2994f0e 100644
--- a/lib/libc/Makefile.inc
+++ b/lib/libc/Makefile.inc
@@ -39,6 +39,9 @@ NOASM=
CFLAGS+= -DYP
.include "${.CURDIR}/../libc/yp/Makefile.inc"
.endif
+.if !defined(NO_HESIOD_LIBC)
+CFLAGS+= -DHESIOD
+.endif
# If there are no machine dependent sources, append all the
# machine-independent sources:
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc
index 9d5452a..c63edcd 100644
--- a/lib/libc/gen/Makefile.inc
+++ b/lib/libc/gen/Makefile.inc
@@ -19,7 +19,7 @@ SRCS+= _rand48.c _spinlock_stub.c alarm.c arc4random.c assert.c \
lockf.c lrand48.c mrand48.c msgctl.c \
msgget.c msgrcv.c msgsnd.c nice.c \
nlist.c nrand48.c ntp_gettime.c opendir.c \
- pause.c popen.c psignal.c pwcache.c raise.c readdir.c rewinddir.c \
+ pause.c popen.c psignal.c pw_scan.c pwcache.c raise.c readdir.c rewinddir.c \
posixshm.c \
scandir.c seed48.c seekdir.c semconfig.c semctl.c semget.c semop.c \
setdomainname.c sethostname.c setjmperr.c setmode.c setproctitle.c \
diff --git a/lib/libc/gen/getgrent.3 b/lib/libc/gen/getgrent.3
index bb3f560..d070d8c 100644
--- a/lib/libc/gen/getgrent.3
+++ b/lib/libc/gen/getgrent.3
@@ -125,25 +125,6 @@ The
.Fn endgrent
function
closes any open files.
-.Sh YP/NIS INTERACTION
-When the
-.Xr yp 4
-group database is enabled, the
-.Fn getgrnam
-and
-.Fn getgrgid
-functions use the YP maps
-.Dq Li group.byname
-and
-.Dq Li group.bygid ,
-respectively, if the requested group is not found in the local
-.Pa /etc/group
-file. The
-.Fn getgrent
-function will step through the YP map
-.Dq Li group.byname
-if the entire map is enabled as described in
-.Xr group 5 .
.Sh RETURN VALUES
The functions
.Fn getgrent ,
@@ -171,7 +152,8 @@ group database file
.Sh SEE ALSO
.Xr getpwent 3 ,
.Xr yp 4 ,
-.Xr group 5
+.Xr group 5 ,
+.Xr nsswitch.conf 5
.Sh HISTORY
The functions
.Fn endgrent ,
@@ -206,3 +188,17 @@ a pointer to that object.
Subsequent calls to
the same function
will modify the same object.
+.Pp
+The functions
+.Fn getgrent ,
+.Fn endgrent ,
+.Fn setgroupent ,
+and
+.Fn setgrent
+are fairly useless in a networked environment and should be
+avoided, if possible.
+.Fn getgrent
+makes no attempt to suppress duplicate information if multiple
+sources are specified in
+.Xr nsswitch.conf 5 .
+
diff --git a/lib/libc/gen/getgrent.c b/lib/libc/gen/getgrent.c
index 5b5c9da..1f98864 100644
--- a/lib/libc/gen/getgrent.c
+++ b/lib/libc/gen/getgrent.c
@@ -1,6 +1,9 @@
+/* $NetBSD: getgrent.c,v 1.34.2.1 1999/04/27 14:10:58 perry Exp $ */
+
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
+ * Portions Copyright (c) 1994, Jason Downs. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,76 +34,95 @@
* SUCH DAMAGE.
*/
+#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)getgrent.c 8.2 (Berkeley) 3/21/94";
+static char rcsid[] =
+ "$FreeBSD$";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
+
+#include <errno.h>
+#include <grp.h>
+#include <limits.h>
+#include <nsswitch.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <grp.h>
+#include <syslog.h>
-static FILE *_gr_fp;
-static struct group _gr_group;
-static int _gr_stayopen;
-static int grscan(), start_gr();
+#ifdef HESIOD
+#include <hesiod.h>
+#include <arpa/nameser.h>
+#endif
#ifdef YP
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
-static int _gr_stepping_yp;
-static int _gr_yp_enabled;
-static int _getypgroup(struct group *, const char *, char *);
-static int _nextypgroup(struct group *);
#endif
+#if defined(YP) || defined(HESIOD)
+#define _GROUP_COMPAT
+#endif
+
+static FILE *_gr_fp;
+static struct group _gr_group;
+static int _gr_stayopen;
+static int _gr_filesdone;
+
+static void grcleanup __P((void));
+static int grscan __P((int, gid_t, const char *));
+static char *getline __P((void));
+static int copyline __P((const char*));
+static int matchline __P((int, gid_t, const char *));
+static int start_gr __P((void));
+
+
+
+
/* initial size for malloc and increase steps for realloc */
#define MAXGRP 64
#define MAXLINELENGTH 256
-static char **members; /* list of group members */
-static int maxgrp; /* current length of **mebers */
-static char *line; /* temp buffer for group line */
-static int maxlinelength; /* current length of *line */
+#ifdef HESIOD
+#if MAXLINELENGTH < NS_MAXLABEL + 1
+#error "MAXLINELENGTH must be at least NS_MAXLABEL + 1"
+#endif
+#endif
-/*
- * Lines longer than MAXLINELENGTHLIMIT will be count as an error.
+static char **members; /* list of group members */
+static int maxgrp; /* current length of **members */
+static char *line; /* buffer for group line */
+static int maxlinelength; /* current length of *line */
+
+/*
+ * Lines longer than MAXLINELENGTHLIMIT will be counted as an error.
* <= 0 disable check for maximum line length
* 256K is enough for 64,000 uids
*/
#define MAXLINELENGTHLIMIT (256 * 1024)
-#define GROUP_IGNORE_COMMENTS 1 /* allow comments in /etc/group */
-
-struct group *
-getgrent()
-{
- if (!_gr_fp && !start_gr()) {
- return NULL;
- }
#ifdef YP
- if (_gr_stepping_yp) {
- if (_nextypgroup(&_gr_group))
- return(&_gr_group);
- }
-tryagain:
+static char *__ypcurrent, *__ypdomain;
+static int __ypcurrentlen;
+static int _gr_ypdone;
#endif
- if (!grscan(0, 0, NULL))
- return(NULL);
-#ifdef YP
- if(_gr_group.gr_name[0] == '+' && _gr_group.gr_name[1]) {
- _getypgroup(&_gr_group, &_gr_group.gr_name[1],
- "group.byname");
- } else if(_gr_group.gr_name[0] == '+') {
- if (!_nextypgroup(&_gr_group))
- goto tryagain;
- else
- return(&_gr_group);
- }
+#ifdef HESIOD
+static int _gr_hesnum;
+#endif
+
+#ifdef _GROUP_COMPAT
+enum _grmode { GRMODE_NONE, GRMODE_FULL, GRMODE_NAME };
+static enum _grmode __grmode;
#endif
- return(&_gr_group);
+
+struct group *
+getgrent()
+{
+ if ((!_gr_fp && !start_gr()) || !grscan(0, 0, NULL))
+ return (NULL);
+ return &_gr_group;
}
struct group *
@@ -110,106 +132,71 @@ getgrnam(name)
int rval;
if (!start_gr())
- return(NULL);
-#ifdef YP
- tryagain:
-#endif
+ return NULL;
rval = grscan(1, 0, name);
-#ifdef YP
- if(rval == -1 && (_gr_yp_enabled < 0 || (_gr_yp_enabled &&
- _gr_group.gr_name[0] == '+'))) {
- if (!(rval = _getypgroup(&_gr_group, name, "group.byname")))
- goto tryagain;
- }
-#endif
if (!_gr_stayopen)
endgrent();
- return(rval ? &_gr_group : NULL);
+ return (rval) ? &_gr_group : NULL;
}
struct group *
-#ifdef __STDC__
-getgrgid(gid_t gid)
-#else
getgrgid(gid)
gid_t gid;
-#endif
{
int rval;
if (!start_gr())
- return(NULL);
-#ifdef YP
- tryagain:
-#endif
+ return NULL;
rval = grscan(1, gid, NULL);
-#ifdef YP
- if(rval == -1 && _gr_yp_enabled) {
- char buf[16];
- snprintf(buf, sizeof buf, "%d", (unsigned)gid);
- if (!(rval = _getypgroup(&_gr_group, buf, "group.bygid")))
- goto tryagain;
- }
-#endif
if (!_gr_stayopen)
endgrent();
- return(rval ? &_gr_group : NULL);
+ return (rval) ? &_gr_group : NULL;
}
-static int
-start_gr()
+void
+grcleanup()
{
- if (_gr_fp) {
- rewind(_gr_fp);
- return(1);
- }
- _gr_fp = fopen(_PATH_GROUP, "r");
- if(!_gr_fp) return 0;
+ _gr_filesdone = 0;
#ifdef YP
- /*
- * This is a disgusting hack, used to determine when YP is enabled.
- * This would be easier if we had a group database to go along with
- * the password database.
- */
- {
- char *line;
- size_t linelen;
- _gr_yp_enabled = 0;
- while((line = fgetln(_gr_fp, &linelen)) != NULL) {
- if(line[0] == '+') {
- if(line[1] && line[1] != ':' && !_gr_yp_enabled) {
- _gr_yp_enabled = 1;
- } else {
- _gr_yp_enabled = -1;
- break;
- }
- }
- }
- rewind(_gr_fp);
- }
+ if (__ypcurrent)
+ free(__ypcurrent);
+ __ypcurrent = NULL;
+ _gr_ypdone = 0;
+#endif
+#ifdef HESIOD
+ _gr_hesnum = 0;
+#endif
+#ifdef _GROUP_COMPAT
+ __grmode = GRMODE_NONE;
#endif
+}
+static int
+start_gr()
+{
+ grcleanup();
if (maxlinelength == 0) {
- if ((line = (char *)malloc(sizeof(char) *
- MAXLINELENGTH)) == NULL)
- return(0);
- maxlinelength += MAXLINELENGTH;
+ if ((line = (char *)malloc(MAXLINELENGTH)) == NULL)
+ return 0;
+ maxlinelength = MAXLINELENGTH;
}
-
if (maxgrp == 0) {
- if ((members = (char **)malloc(sizeof(char **) *
+ if ((members = (char **) malloc(sizeof(char**) *
MAXGRP)) == NULL)
- return(0);
- maxgrp += MAXGRP;
+ return 0;
+ maxgrp = MAXGRP;
}
-
- return 1;
+ if (_gr_fp) {
+ rewind(_gr_fp);
+ return 1;
+ }
+ return (_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0;
}
int
-setgrent()
+setgrent(void)
{
- return(setgroupent(0));
+ return setgroupent(0);
}
int
@@ -217,337 +204,503 @@ setgroupent(stayopen)
int stayopen;
{
if (!start_gr())
- return(0);
+ return 0;
_gr_stayopen = stayopen;
-#ifdef YP
- _gr_stepping_yp = 0;
-#endif
- return(1);
+ return 1;
}
void
endgrent()
{
-#ifdef YP
- _gr_stepping_yp = 0;
-#endif
+ grcleanup();
if (_gr_fp) {
(void)fclose(_gr_fp);
_gr_fp = NULL;
}
}
+
+static int _local_grscan __P((void *, void *, va_list));
+
+/*ARGSUSED*/
static int
-grscan(search, gid, name)
- register int search, gid;
- register char *name;
+_local_grscan(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
{
- register char *cp, **m;
- char *bp;
-
+ int search = va_arg(ap, int);
+ gid_t gid = va_arg(ap, gid_t);
+ const char *name = va_arg(ap, const char *);
-#ifdef YP
- int _ypfound;
-#endif
+ if (_gr_filesdone)
+ return NS_NOTFOUND;
for (;;) {
-#ifdef YP
- _ypfound = 0;
-#endif
- if (fgets(line, maxlinelength, _gr_fp) == NULL)
- return(0);
-
- if (!index(line, '\n')) {
- do {
- if (feof(_gr_fp))
- return(0);
-
- /* don't allocate infinite memory */
- if (MAXLINELENGTHLIMIT > 0 &&
- maxlinelength >= MAXLINELENGTHLIMIT)
- return(0);
-
- if ((line = (char *)reallocf(line,
- sizeof(char) *
- (maxlinelength + MAXLINELENGTH))) == NULL)
- return(0);
-
- if (fgets(line + maxlinelength - 1,
- MAXLINELENGTH + 1, _gr_fp) == NULL)
- return(0);
-
- maxlinelength += MAXLINELENGTH;
- } while (!index(line + maxlinelength -
- MAXLINELENGTH - 1, '\n'));
+ if (getline() == NULL) {
+ if (!search)
+ _gr_filesdone = 1;
+ return NS_NOTFOUND;
}
+ if (matchline(search, gid, name))
+ return NS_SUCCESS;
+ }
+ /* NOTREACHED */
+}
-#ifdef GROUP_IGNORE_COMMENTS
- /*
- * Ignore comments: ^[ \t]*#
- */
- for (cp = line; *cp != '\0'; cp++)
- if (*cp != ' ' && *cp != '\t')
- break;
- if (*cp == '#' || *cp == '\0')
- continue;
-#endif
+#ifdef HESIOD
+static int _dns_grscan __P((void *, void *, va_list));
- bp = line;
+/*ARGSUSED*/
+static int
+_dns_grscan(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+ int search = va_arg(ap, int);
+ gid_t gid = va_arg(ap, gid_t);
+ const char *name = va_arg(ap, const char *);
- if ((_gr_group.gr_name = strsep(&bp, ":\n")) == NULL)
- break;
-#ifdef YP
- /*
- * XXX We need to be careful to avoid proceeding
- * past this point under certain circumstances or
- * we risk dereferencing null pointers down below.
- */
- if (_gr_group.gr_name[0] == '+') {
- if (strlen(_gr_group.gr_name) == 1) {
- switch(search) {
- case 0:
- return(1);
- case 1:
- return(-1);
- default:
- return(0);
- }
- } else {
- cp = &_gr_group.gr_name[1];
- if (search && name != NULL)
- if (strcmp(cp, name))
- continue;
- if (!_getypgroup(&_gr_group, cp,
- "group.byname"))
- continue;
- if (search && name == NULL)
- if (gid != _gr_group.gr_gid)
- continue;
- /* We're going to override -- tell the world. */
- _ypfound++;
- }
+ char **hp;
+ void *context;
+ int r;
+ size_t sz;
+
+ r = NS_UNAVAIL;
+ if (!search && _gr_hesnum == -1)
+ return NS_NOTFOUND;
+ if (hesiod_init(&context) == -1)
+ return (r);
+
+ for (;;) {
+ if (search) {
+ if (name)
+ strlcpy(line, name, maxlinelength);
+ else
+ snprintf(line, maxlinelength, "%u",
+ (unsigned int)gid);
+ } else {
+ snprintf(line, maxlinelength, "group-%u", _gr_hesnum);
+ _gr_hesnum++;
}
-#else
- if (_gr_group.gr_name[0] == '+')
- continue;
-#endif /* YP */
- if (search && name) {
- if(strcmp(_gr_group.gr_name, name)) {
- continue;
+
+ hp = hesiod_resolve(context, line, "group");
+ if (hp == NULL) {
+ if (errno == ENOENT) {
+ if (!search)
+ _gr_hesnum = -1;
+ r = NS_NOTFOUND;
}
+ break;
}
-#ifdef YP
- if ((cp = strsep(&bp, ":\n")) == NULL)
- if (_ypfound)
- return(1);
- else
- break;
- if (strlen(cp) || !_ypfound)
- _gr_group.gr_passwd = cp;
-#else
- if ((_gr_group.gr_passwd = strsep(&bp, ":\n")) == NULL)
+
+ /* only check first elem */
+ if (copyline(hp[0]) == 0)
+ return NS_UNAVAIL;
+ hesiod_free_list(context, hp);
+ if (matchline(search, gid, name)) {
+ r = NS_SUCCESS;
break;
-#endif
- if (!(cp = strsep(&bp, ":\n")))
-#ifdef YP
- if (_ypfound)
- return(1);
- else
-#endif
- continue;
-#ifdef YP
- /*
- * Hurm. Should we be doing this? We allow UIDs to
- * be overridden -- what about GIDs?
- */
- if (!_ypfound)
-#endif
- _gr_group.gr_gid = atoi(cp);
- if (search && name == NULL && _gr_group.gr_gid != gid)
- continue;
- cp = NULL;
- if (bp == NULL) /* !!! Must check for this! */
+ } else if (search) {
+ r = NS_NOTFOUND;
break;
+ }
+ }
+ hesiod_end(context);
+ return (r);
+}
+#endif
+
#ifdef YP
- if ((cp = strsep(&bp, ":\n")) == NULL)
+static int _nis_grscan __P((void *, void *, va_list));
+
+/*ARGSUSED*/
+static int
+_nis_grscan(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+ int search = va_arg(ap, int);
+ gid_t gid = va_arg(ap, gid_t);
+ const char *name = va_arg(ap, const char *);
+
+ char *key, *data;
+ int keylen, datalen;
+ int r;
+ size_t sz;
+
+ if(__ypdomain == NULL) {
+ switch (yp_get_default_domain(&__ypdomain)) {
+ case 0:
break;
+ case YPERR_RESRC:
+ return NS_TRYAGAIN;
+ default:
+ return NS_UNAVAIL;
+ }
+ }
- if (!strlen(cp) && _ypfound)
- return(1);
+ if (search) { /* specific group or gid */
+ if (name)
+ strlcpy(line, name, maxlinelength);
else
- members[0] = NULL;
- bp = cp;
- cp = NULL;
-#endif
- for (m = members; ; bp++) {
- if (m == (members + maxgrp - 1)) {
- if ((members = (char **)
- reallocf(members,
- sizeof(char **) *
- (maxgrp + MAXGRP))) == NULL)
- return(0);
- m = members + maxgrp - 1;
- maxgrp += MAXGRP;
- }
- if (*bp == ',') {
- if (cp) {
- *bp = '\0';
- *m++ = cp;
- cp = NULL;
- }
- } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
- if (cp) {
- *bp = '\0';
- *m++ = cp;
- }
+ snprintf(line, maxlinelength, "%u", (unsigned int)gid);
+ data = NULL;
+ r = yp_match(__ypdomain,
+ (name) ? "group.byname" : "group.bygid",
+ line, (int)strlen(line), &data, &datalen);
+ switch (r) {
+ case 0:
+ break;
+ case YPERR_KEY:
+ if (data)
+ free(data);
+ return NS_NOTFOUND;
+ default:
+ if (data)
+ free(data);
+ return NS_UNAVAIL;
+ }
+ data[datalen] = '\0'; /* clear trailing \n */
+ if (copyline(data) == 0)
+ return NS_UNAVAIL;
+ free(data);
+ if (matchline(search, gid, name))
+ return NS_SUCCESS;
+ else
+ return NS_NOTFOUND;
+ }
+
+ /* ! search */
+ if (_gr_ypdone)
+ return NS_NOTFOUND;
+ for (;;) {
+ data = NULL;
+ if(__ypcurrent) {
+ key = NULL;
+ r = yp_next(__ypdomain, "group.byname",
+ __ypcurrent, __ypcurrentlen,
+ &key, &keylen, &data, &datalen);
+ free(__ypcurrent);
+ switch (r) {
+ case 0:
break;
- } else if (cp == NULL)
- cp = bp;
-
+ case YPERR_NOMORE:
+ __ypcurrent = NULL;
+ if (key)
+ free(key);
+ if (data)
+ free(data);
+ _gr_ypdone = 1;
+ return NS_NOTFOUND;
+ default:
+ if (key)
+ free(key);
+ if (data)
+ free(data);
+ return NS_UNAVAIL;
+ }
+ __ypcurrent = key;
+ __ypcurrentlen = keylen;
+ } else {
+ if (yp_first(__ypdomain, "group.byname",
+ &__ypcurrent, &__ypcurrentlen,
+ &data, &datalen)) {
+ if (data);
+ free(data);
+ return NS_UNAVAIL;
+ }
}
- _gr_group.gr_mem = members;
- *m = NULL;
- return(1);
+ data[datalen] = '\0'; /* clear trailing \n */
+ if (copyline(data) == 0)
+ return NS_UNAVAIL;
+ free(data);
+ if (matchline(search, gid, name))
+ return NS_SUCCESS;
}
/* NOTREACHED */
- return (0);
}
+#endif
-#ifdef YP
+#ifdef _GROUP_COMPAT
+/*
+ * log an error if "files" or "compat" is specified in group_compat database
+ */
+static int _bad_grscan __P((void *, void *, va_list));
+/*ARGSUSED*/
static int
-_gr_breakout_yp(struct group *gr, char *result)
+_bad_grscan(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
{
- char *s, *cp;
- char **m;
+ static int warned;
- /*
- * XXX If 's' ends up being a NULL pointer, punt on this group.
- * It means the NIS group entry is badly formatted and should
- * be skipped.
- */
- if ((s = strsep(&result, ":")) == NULL) return 0; /* name */
- gr->gr_name = s;
+ if (!warned) {
+ syslog(LOG_ERR,
+ "nsswitch.conf group_compat database can't use '%s'",
+ (char *)cb_data);
+ }
+ warned = 1;
+ return NS_UNAVAIL;
+}
- if ((s = strsep(&result, ":")) == NULL) return 0; /* password */
- gr->gr_passwd = s;
+/*
+ * when a name lookup in compat mode is required, look it up in group_compat
+ * nsswitch database. only Hesiod and NIS is supported - it doesn't make
+ * sense to lookup compat names from 'files' or 'compat'
+ */
- if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */
- gr->gr_gid = atoi(s);
+static int __grscancompat __P((int, gid_t, const char *));
+
+static int
+__grscancompat(search, gid, name)
+ int search;
+ gid_t gid;
+ const char *name;
+{
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_bad_grscan, "files")
+ NS_DNS_CB(_dns_grscan, NULL)
+ NS_NIS_CB(_nis_grscan, NULL)
+ NS_COMPAT_CB(_bad_grscan, "compat")
+ { 0 }
+ };
+ static const ns_src defaultnis[] = {
+ { NSSRC_NIS, NS_SUCCESS },
+ { 0 }
+ };
+
+ return (nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "grscancompat",
+ defaultnis, search, gid, name));
+}
+#endif
- if ((s = result) == NULL) return 0;
- cp = 0;
- for (m = members; ; s++) {
- if (m == members + maxgrp - 1) {
- if ((members = (char **)reallocf(members,
- sizeof(char **) * (maxgrp + MAXGRP))) == NULL)
- return(0);
- m = members + maxgrp - 1;
+static int _compat_grscan __P((void *, void *, va_list));
+
+/*ARGSUSED*/
+static int
+_compat_grscan(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+ int search = va_arg(ap, int);
+ gid_t gid = va_arg(ap, gid_t);
+ const char *name = va_arg(ap, const char *);
+
+#ifdef _GROUP_COMPAT
+ static char *grname = NULL;
+#endif
+
+ for (;;) {
+#ifdef _GROUP_COMPAT
+ if(__grmode != GRMODE_NONE) {
+ int r;
+
+ switch(__grmode) {
+ case GRMODE_FULL:
+ r = __grscancompat(search, gid, name);
+ if (r == NS_SUCCESS)
+ return r;
+ __grmode = GRMODE_NONE;
+ break;
+ case GRMODE_NAME:
+ if(grname == (char *)NULL) {
+ __grmode = GRMODE_NONE;
+ break;
+ }
+ r = __grscancompat(1, 0, grname);
+ free(grname);
+ grname = (char *)NULL;
+ if (r != NS_SUCCESS)
+ break;
+ if (!search)
+ return NS_SUCCESS;
+ if (name) {
+ if (! strcmp(_gr_group.gr_name, name))
+ return NS_SUCCESS;
+ } else {
+ if (_gr_group.gr_gid == gid)
+ return NS_SUCCESS;
+ }
+ break;
+ case GRMODE_NONE:
+ abort();
+ }
+ continue;
+ }
+#endif /* _GROUP_COMPAT */
+
+ if (getline() == NULL)
+ return NS_NOTFOUND;
+
+#ifdef _GROUP_COMPAT
+ if (line[0] == '+') {
+ char *tptr, *bp;
+
+ switch(line[1]) {
+ case ':':
+ case '\0':
+ case '\n':
+ __grmode = GRMODE_FULL;
+ break;
+ default:
+ __grmode = GRMODE_NAME;
+ bp = line;
+ tptr = strsep(&bp, ":\n");
+ grname = strdup(tptr + 1);
+ break;
+ }
+ continue;
+ }
+#endif /* _GROUP_COMPAT */
+ if (matchline(search, gid, name))
+ return NS_SUCCESS;
+ }
+ /* NOTREACHED */
+}
+
+static int
+grscan(search, gid, name)
+ int search;
+ gid_t gid;
+ const char *name;
+{
+ int r;
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_local_grscan, NULL)
+ NS_DNS_CB(_dns_grscan, NULL)
+ NS_NIS_CB(_nis_grscan, NULL)
+ NS_COMPAT_CB(_compat_grscan, NULL)
+ { 0 }
+ };
+ static const ns_src compatsrc[] = {
+ { NSSRC_COMPAT, NS_SUCCESS },
+ { 0 }
+ };
+
+ r = nsdispatch(NULL, dtab, NSDB_GROUP, "grscan", compatsrc,
+ search, gid, name);
+ return (r == NS_SUCCESS) ? 1 : 0;
+}
+
+static int
+matchline(search, gid, name)
+ int search;
+ gid_t gid;
+ const char *name;
+{
+ unsigned long id;
+ char **m;
+ char *cp, *bp, *ep;
+
+ if (line[0] == '+')
+ return 0; /* sanity check to prevent recursion */
+ bp = line;
+ _gr_group.gr_name = strsep(&bp, ":\n");
+ if (search && name && strcmp(_gr_group.gr_name, name))
+ return 0;
+ _gr_group.gr_passwd = strsep(&bp, ":\n");
+ if (!(cp = strsep(&bp, ":\n")))
+ return 0;
+ id = strtoul(cp, &ep, 10);
+ if (*ep != '\0')
+ return 0;
+ _gr_group.gr_gid = (gid_t)id;
+ if (search && name == NULL && _gr_group.gr_gid != gid)
+ return 0;
+ cp = NULL;
+ if (bp == NULL)
+ return 0;
+ for (_gr_group.gr_mem = m = members;; bp++) {
+ if (m == &members[maxgrp - 1]) {
+ members = (char **) reallocf(members, sizeof(char **) *
+ (maxgrp + MAXGRP));
+ if (members == NULL)
+ return 0;
+ _gr_group.gr_mem = members;
+ m = &members[maxgrp - 1];
maxgrp += MAXGRP;
}
- if (*s == ',') {
+ if (*bp == ',') {
if (cp) {
- *s = '\0';
+ *bp = '\0';
*m++ = cp;
cp = NULL;
}
- } else if (*s == '\0' || *s == '\n' || *s == ' ') {
+ } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
if (cp) {
- *s = '\0';
+ *bp = '\0';
*m++ = cp;
}
break;
- } else if (cp == NULL) {
- cp = s;
- }
- }
- _gr_group.gr_mem = members;
+ } else if (cp == NULL)
+ cp = bp;
+ }
*m = NULL;
-
- return 1;
+ return 1;
}
-static char *_gr_yp_domain;
-
-static int
-_getypgroup(struct group *gr, const char *name, char *map)
+static char *
+getline(void)
{
- char *result, *s;
- static char resultbuf[YPMAXRECORD + 2];
- int resultlen;
+ const char *cp;
- if(!_gr_yp_domain) {
- if(yp_get_default_domain(&_gr_yp_domain))
- return 0;
+ tryagain:
+ if (fgets(line, maxlinelength, _gr_fp) == NULL)
+ return NULL;
+ if (index(line, '\n') == NULL) {
+ do {
+ if (feof(_gr_fp))
+ return NULL;
+ if (MAXLINELENGTHLIMIT > 0 &&
+ maxlinelength >= MAXLINELENGTHLIMIT)
+ return NULL;
+ line = (char *)reallocf(line, maxlinelength +
+ MAXLINELENGTH);
+ if (line == NULL)
+ return NULL;
+ if (fgets(line + maxlinelength - 1,
+ MAXLINELENGTH + 1, _gr_fp) == NULL)
+ return NULL;
+ maxlinelength += MAXLINELENGTH;
+ } while (index(line + maxlinelength - MAXLINELENGTH - 1,
+ '\n') == NULL);
}
- if(yp_match(_gr_yp_domain, map, name, strlen(name),
- &result, &resultlen))
- return 0;
-
- s = strchr(result, '\n');
- if(s) *s = '\0';
- if(resultlen >= sizeof resultbuf) return 0;
- strncpy(resultbuf, result, resultlen);
- resultbuf[resultlen] = '\0';
- free(result);
- return(_gr_breakout_yp(gr, resultbuf));
+ /*
+ * Ignore comments: ^[ \t]*#
+ */
+ for (cp = line; *cp != '\0'; cp++)
+ if (*cp != ' ' && *cp != '\t')
+ break;
+ if (*cp == '#' || *cp == '\0')
+ goto tryagain;
+ if (cp != line) /* skip white space at beginning of line */
+ bcopy(cp, line, strlen(cp));
+
+ return line;
}
-
static int
-_nextypgroup(struct group *gr)
+copyline(const char *src)
{
- static char *key;
- static int keylen;
- char *lastkey, *result;
- static char resultbuf[YPMAXRECORD + 2];
- int resultlen;
- int rv;
-
- if(!_gr_yp_domain) {
- if(yp_get_default_domain(&_gr_yp_domain))
- return 0;
- }
+ size_t sz;
- if(!_gr_stepping_yp) {
- if(key) free(key);
- rv = yp_first(_gr_yp_domain, "group.byname",
- &key, &keylen, &result, &resultlen);
- if(rv) {
- return 0;
- }
- _gr_stepping_yp = 1;
- goto unpack;
- } else {
-tryagain:
- lastkey = key;
- rv = yp_next(_gr_yp_domain, "group.byname", key, keylen,
- &key, &keylen, &result, &resultlen);
- free(lastkey);
-unpack:
- if(rv) {
- _gr_stepping_yp = 0;
+ sz = strlen(src);
+ if (sz > maxlinelength - 1) {
+ sz = ((sz/MAXLINELENGTH)+1) * MAXLINELENGTH;
+ if ((line = (char *) reallocf(line, sz)) == NULL)
return 0;
- }
-
- if(resultlen > sizeof(resultbuf)) {
- free(result);
- goto tryagain;
- }
-
- strncpy(resultbuf, result, resultlen);
- resultbuf[resultlen] = '\0';
- free(result);
- if((result = strchr(resultbuf, '\n')) != NULL)
- *result = '\0';
- if (_gr_breakout_yp(gr, resultbuf))
- return(1);
- else
- goto tryagain;
+ maxlinelength = sz;
}
+ strlcpy(line, src, maxlinelength);
+ return 1;
}
-#endif /* YP */
diff --git a/lib/libc/gen/getpwent.3 b/lib/libc/gen/getpwent.3
index 4084289..b606b44 100644
--- a/lib/libc/gen/getpwent.3
+++ b/lib/libc/gen/getpwent.3
@@ -137,24 +137,6 @@ If the process which calls them has an effective uid of 0, the encrypted
password will be returned, otherwise, the password field of the returned
structure will point to the string
.Ql * .
-.Sh YP/NIS INTERACTION
-When the
-.Xr yp 4
-password database is enabled, the
-.Fn getpwnam
-and
-.Fn getpwuid
-functions use the YP maps
-.Dq Li passwd.byname
-and
-.Dq Li passwd.byuid ,
-respectively, if the requested password entry is not found in the
-local database. The
-.Fn getpwent
-function will step through the YP map
-.Dq Li passwd.byname
-if the entire map is enabled as described in
-.Xr passwd 5 .
.Sh RETURN VALUES
The functions
.Fn getpwent ,
@@ -187,6 +169,7 @@ A Version 7 format password file
.Xr getlogin 2 ,
.Xr getgrent 3 ,
.Xr yp 4 ,
+.Xr nsswitch.conf 5 ,
.Xr passwd 5 ,
.Xr pwd_mkdb 8 ,
.Xr vipw 8
@@ -220,3 +203,16 @@ a pointer to that object.
Subsequent calls to
the same function
will modify the same object.
+.Pp
+The functions
+.Fn getpwent ,
+.Fn endpwent ,
+.Fn setpassent ,
+and
+.Fn setpwent
+are fairly useless in a networked environment and should be
+avoided, if possible.
+.Fn getpwent
+makes no attempt to suppress duplicate information if multiple
+sources are specified in
+.Xr nsswitch.conf 5
diff --git a/lib/libc/gen/getpwent.c b/lib/libc/gen/getpwent.c
index 00e6ca3..3c8620e 100644
--- a/lib/libc/gen/getpwent.c
+++ b/lib/libc/gen/getpwent.c
@@ -1,6 +1,9 @@
+/* $NetBSD: getpwent.c,v 1.40.2.2 1999/04/27 22:09:45 perry Exp $ */
+
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
+ * Portions Copyright (c) 1994, 1995, Jason Downs. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,15 +32,14 @@
* 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$
*/
+#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)getpwent.c 8.2 (Berkeley) 4/27/95";
+static const char *rcsid[] =
+ "$FreeBSD$";
#endif /* LIBC_SCCS and not lint */
-#include <stdio.h>
#include <sys/param.h>
#include <fcntl.h>
#include <db.h>
@@ -49,11 +51,27 @@ static char sccsid[] = "@(#)getpwent.c 8.2 (Berkeley) 4/27/95";
#include <stdlib.h>
#include <string.h>
#include <limits.h>
-#include <grp.h>
+#include <nsswitch.h>
+#ifdef HESIOD
+#include <hesiod.h>
+#endif
+#ifdef YP
+#include <machine/param.h>
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+
+extern void setnetgrent __P((char *));
+extern int getnetgrent __P((char **, char **, char **));
+extern int innetgr __P((const char *, const char *, const char *, const char *));
-extern void setnetgrent __P(( char * ));
-extern int getnetgrent __P(( char **, char **, char ** ));
-extern int innetgr __P(( const char *, const char *, const char *, const char * ));
+#include "pw_scan.h"
+
+#if defined(YP) || defined(HESIOD)
+#define _PASSWD_COMPAT
+#endif
/*
* The lookup techniques and data extraction code here must be kept
@@ -62,799 +80,1096 @@ extern int innetgr __P(( const char *, const char *, const char *, const char *
static struct passwd _pw_passwd; /* password structure */
static DB *_pw_db; /* password database */
-static int _pw_keynum; /* key counter */
+static int _pw_keynum; /* key counter. no more records if -1 */
static int _pw_stayopen; /* keep fd's open */
-#ifdef YP
-#include <rpc/rpc.h>
-#include <rpcsvc/yp_prot.h>
-#include <rpcsvc/ypclnt.h>
+static int _pw_flags; /* password flags */
-static struct passwd _pw_copy;
-static DBT empty = { NULL, 0 };
-static DB *_ypcache = (DB *)NULL;
-static int _yp_exclusions = 0;
-static int _yp_enabled = -1;
-static int _pw_stepping_yp; /* set true when stepping thru map */
-static char _ypnam[YPMAXRECORD];
-#define YP_HAVE_MASTER 2
-#define YP_HAVE_ADJUNCT 1
-#define YP_HAVE_NONE 0
-static int _gotmaster;
-static char *_pw_yp_domain;
-static inline int unwind __P(( char * ));
-static void _ypinitdb __P(( void ));
-static int _havemaster __P((char *));
-static int _getyppass __P((struct passwd *, const char *, const char * ));
-static int _nextyppass __P((struct passwd *));
-static inline int lookup __P((const char *));
-static inline void store __P((const char *));
-static inline int ingr __P((const char *, const char*));
-static inline int verf __P((const char *));
-static char * _get_adjunct_pw __P((const char *));
-#endif
-static int __hashpw(DBT *);
-static int __initdb(void);
-
-struct passwd *
-getpwent()
-{
- DBT key;
- char bf[sizeof(_pw_keynum) + 1];
- int rv;
+static int __hashpw __P((DBT *));
+static int __initdb __P((void));
- if (!_pw_db && !__initdb())
- return((struct passwd *)NULL);
+static const ns_src compatsrc[] = {
+ { NSSRC_COMPAT, NS_SUCCESS },
+ { 0 }
+};
#ifdef YP
- if(_pw_stepping_yp) {
- _pw_passwd = _pw_copy;
- if (unwind((char *)&_ypnam))
- return(&_pw_passwd);
- }
+static char *__ypcurrent, *__ypdomain;
+static int __ypcurrentlen;
+static int _pw_ypdone; /* non-zero if no more yp records */
#endif
-tryagain:
- ++_pw_keynum;
- bf[0] = _PW_KEYBYNUM;
- bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
- key.data = (u_char *)bf;
- key.size = sizeof(_pw_keynum) + 1;
- rv = __hashpw(&key);
- if(!rv) return (struct passwd *)NULL;
-#ifdef YP
- if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') {
- if (_yp_enabled == -1)
- _ypinitdb();
- bzero((char *)&_ypnam, sizeof(_ypnam));
- bcopy(_pw_passwd.pw_name, _ypnam,
- strlen(_pw_passwd.pw_name));
- _pw_copy = _pw_passwd;
- if (unwind((char *)&_ypnam) == 0)
- goto tryagain;
- else
- return(&_pw_passwd);
- }
-#else
- /* Ignore YP password file entries when YP is disabled. */
- if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') {
- goto tryagain;
- }
+#ifdef HESIOD
+static int _pw_hesnum; /* hes counter. no more records if -1 */
#endif
- return(&_pw_passwd);
-}
-struct passwd *
-getpwnam(name)
+#ifdef _PASSWD_COMPAT
+enum _pwmode { PWMODE_NONE, PWMODE_FULL, PWMODE_USER, PWMODE_NETGRP };
+static enum _pwmode __pwmode;
+
+enum _ypmap { YPMAP_NONE, YPMAP_ADJUNCT, YPMAP_MASTER };
+
+static struct passwd *__pwproto = (struct passwd *)NULL;
+static int __pwproto_flags;
+static char line[1024];
+static long prbuf[1024 / sizeof(long)];
+static DB *__pwexclude = (DB *)NULL;
+
+static int __pwexclude_add __P((const char *));
+static int __pwexclude_is __P((const char *));
+static void __pwproto_set __P((void));
+static int __ypmaptype __P((void));
+static int __pwparse __P((struct passwd *, char *));
+
+ /* macros for deciding which YP maps to use. */
+#define PASSWD_BYNAME (__ypmaptype() == YPMAP_MASTER \
+ ? "master.passwd.byname" : "passwd.byname")
+#define PASSWD_BYUID (__ypmaptype() == YPMAP_MASTER \
+ ? "master.passwd.byuid" : "passwd.byuid")
+
+/*
+ * add a name to the compat mode exclude list
+ */
+static int
+__pwexclude_add(name)
const char *name;
{
DBT key;
- int len, rval;
- char bf[UT_NAMESIZE + 2];
+ DBT data;
- if (!_pw_db && !__initdb())
- return((struct passwd *)NULL);
+ /* initialize the exclusion table if needed. */
+ if(__pwexclude == (DB *)NULL) {
+ __pwexclude = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL);
+ if(__pwexclude == (DB *)NULL)
+ return 1;
+ }
- bf[0] = _PW_KEYBYNAME;
- len = strlen(name);
- if (len > UT_NAMESIZE)
- return(NULL);
- bcopy(name, bf + 1, len);
- key.data = (u_char *)bf;
- key.size = len + 1;
- rval = __hashpw(&key);
+ /* set up the key */
+ key.size = strlen(name);
+ /* LINTED key does not get modified */
+ key.data = (char *)name;
-#ifdef YP
- if (!rval) {
- if (_yp_enabled == -1)
- _ypinitdb();
- if (_yp_enabled)
- rval = _getyppass(&_pw_passwd, name, "passwd.byname");
- }
-#endif
- /*
- * Prevent login attempts when YP is not enabled but YP entries
- * are in /etc/master.passwd.
- */
- if (rval && (_pw_passwd.pw_name[0] == '+'||
- _pw_passwd.pw_name[0] == '-')) rval = 0;
+ /* data is nothing. */
+ data.data = NULL;
+ data.size = 0;
- if (!_pw_stayopen)
- endpwent();
- return(rval ? &_pw_passwd : (struct passwd *)NULL);
+ /* store it */
+ if((__pwexclude->put)(__pwexclude, &key, &data, 0) == -1)
+ return 1;
+
+ return 0;
}
-struct passwd *
-getpwuid(uid)
- uid_t uid;
+/*
+ * test if a name is on the compat mode exclude list
+ */
+static int
+__pwexclude_is(name)
+ const char *name;
{
DBT key;
- int keyuid, rval;
- char bf[sizeof(keyuid) + 1];
-
- if (!_pw_db && !__initdb())
- return((struct passwd *)NULL);
+ DBT data;
- bf[0] = _PW_KEYBYUID;
- keyuid = uid;
- bcopy(&keyuid, bf + 1, sizeof(keyuid));
- key.data = (u_char *)bf;
- key.size = sizeof(keyuid) + 1;
- rval = __hashpw(&key);
+ if(__pwexclude == (DB *)NULL)
+ return 0; /* nothing excluded */
-#ifdef YP
- if (!rval) {
- if (_yp_enabled == -1)
- _ypinitdb();
- if (_yp_enabled) {
- char ypbuf[16]; /* big enough for 32-bit uids */
- snprintf(ypbuf, sizeof ypbuf, "%u", (unsigned)uid);
- rval = _getyppass(&_pw_passwd, ypbuf, "passwd.byuid");
- }
- }
-#endif
- /*
- * Prevent login attempts when YP is not enabled but YP entries
- * are in /etc/master.passwd.
- */
- if (rval && (_pw_passwd.pw_name[0] == '+'||
- _pw_passwd.pw_name[0] == '-')) rval = 0;
+ /* set up the key */
+ key.size = strlen(name);
+ /* LINTED key does not get modified */
+ key.data = (char *)name;
- if (!_pw_stayopen)
- endpwent();
- return(rval ? &_pw_passwd : (struct passwd *)NULL);
+ if((__pwexclude->get)(__pwexclude, &key, &data, 0) == 0)
+ return 1; /* excluded */
+
+ return 0;
}
-int
-setpassent(stayopen)
- int stayopen;
+/*
+ * setup the compat mode prototype template
+ */
+static void
+__pwproto_set()
{
- _pw_keynum = 0;
-#ifdef YP
- _pw_stepping_yp = 0;
- if (stayopen)
- setgroupent(1);
-#endif
- _pw_stayopen = stayopen;
- return(1);
+ char *ptr;
+ struct passwd *pw = &_pw_passwd;
+
+ /* make this the new prototype */
+ ptr = (char *)(void *)prbuf;
+
+ /* first allocate the struct. */
+ __pwproto = (struct passwd *)(void *)ptr;
+ ptr += sizeof(struct passwd);
+
+ /* name */
+ if(pw->pw_name && (pw->pw_name)[0]) {
+ ptr = (char *)ALIGN((u_long)ptr);
+ memmove(ptr, pw->pw_name, strlen(pw->pw_name) + 1);
+ __pwproto->pw_name = ptr;
+ ptr += (strlen(pw->pw_name) + 1);
+ } else
+ __pwproto->pw_name = (char *)NULL;
+
+ /* password */
+ if(pw->pw_passwd && (pw->pw_passwd)[0]) {
+ ptr = (char *)ALIGN((u_long)ptr);
+ memmove(ptr, pw->pw_passwd, strlen(pw->pw_passwd) + 1);
+ __pwproto->pw_passwd = ptr;
+ ptr += (strlen(pw->pw_passwd) + 1);
+ } else
+ __pwproto->pw_passwd = (char *)NULL;
+
+ /* uid */
+ __pwproto->pw_uid = pw->pw_uid;
+
+ /* gid */
+ __pwproto->pw_gid = pw->pw_gid;
+
+ /* change (ignored anyway) */
+ __pwproto->pw_change = pw->pw_change;
+
+ /* class (ignored anyway) */
+ __pwproto->pw_class = "";
+
+ /* gecos */
+ if(pw->pw_gecos && (pw->pw_gecos)[0]) {
+ ptr = (char *)ALIGN((u_long)ptr);
+ memmove(ptr, pw->pw_gecos, strlen(pw->pw_gecos) + 1);
+ __pwproto->pw_gecos = ptr;
+ ptr += (strlen(pw->pw_gecos) + 1);
+ } else
+ __pwproto->pw_gecos = (char *)NULL;
+
+ /* dir */
+ if(pw->pw_dir && (pw->pw_dir)[0]) {
+ ptr = (char *)ALIGN((u_long)ptr);
+ memmove(ptr, pw->pw_dir, strlen(pw->pw_dir) + 1);
+ __pwproto->pw_dir = ptr;
+ ptr += (strlen(pw->pw_dir) + 1);
+ } else
+ __pwproto->pw_dir = (char *)NULL;
+
+ /* shell */
+ if(pw->pw_shell && (pw->pw_shell)[0]) {
+ ptr = (char *)ALIGN((u_long)ptr);
+ memmove(ptr, pw->pw_shell, strlen(pw->pw_shell) + 1);
+ __pwproto->pw_shell = ptr;
+ ptr += (strlen(pw->pw_shell) + 1);
+ } else
+ __pwproto->pw_shell = (char *)NULL;
+
+ /* expire (ignored anyway) */
+ __pwproto->pw_expire = pw->pw_expire;
+
+ /* flags */
+ __pwproto_flags = _pw_flags;
}
-void
-setpwent()
+static int
+__ypmaptype()
{
- (void)setpassent(0);
-}
+ static int maptype = -1;
+ int order, r;
-void
-endpwent()
-{
- _pw_keynum = 0;
-#ifdef YP
- _pw_stepping_yp = 0;
-#endif
- if (_pw_db) {
- (void)(_pw_db->close)(_pw_db);
- _pw_db = (DB *)NULL;
- }
-#ifdef YP
- if (_ypcache) {
- (void)(_ypcache->close)(_ypcache);
- _ypcache = (DB *)NULL;
- _yp_exclusions = 0;
- }
- /* Fix for PR #12008 */
- _yp_enabled = -1;
-#endif
-}
+ if (maptype != -1)
+ return (maptype);
-static int
-__initdb()
-{
- static int warned;
- char *p;
+ maptype = YPMAP_NONE;
+ if (geteuid() != 0)
+ return (maptype);
- p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
- _pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
- if (_pw_db)
- return(1);
- if (!warned++)
- syslog(LOG_ERR, "%s: %m", p);
- return(0);
-}
+ if (!__ypdomain) {
+ if( _yp_check(&__ypdomain) == 0)
+ return (maptype);
+ }
-static int
-__hashpw(key)
- DBT *key;
-{
- register char *p, *t;
- static u_int max;
- static char *line;
- DBT data;
+ r = yp_order(__ypdomain, "master.passwd.byname", &order);
+ if (r == 0) {
+ maptype = YPMAP_MASTER;
+ return (maptype);
+ }
- if ((_pw_db->get)(_pw_db, key, &data, 0))
- return(0);
- p = (char *)data.data;
+ /*
+ * NIS+ in YP compat mode doesn't support
+ * YPPROC_ORDER -- no point in continuing.
+ */
+ if (r == YPERR_YPERR)
+ return (maptype);
- /* Increase buffer size for long lines if necessary. */
- if (data.size > max) {
- max = data.size + 1024;
- if (!(line = reallocf(line, max)))
- return(0);
+ /* master.passwd doesn't exist -- try passwd.adjunct */
+ if (r == YPERR_MAP) {
+ r = yp_order(__ypdomain, "passwd.adjunct.byname", &order);
+ if (r == 0)
+ maptype = YPMAP_ADJUNCT;
+ return (maptype);
}
- /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
- t = line;
-#define EXPAND(e) e = t; while ( (*t++ = *p++) );
-#define SCALAR(v) memmove(&(v), p, sizeof v); p += sizeof v
- EXPAND(_pw_passwd.pw_name);
- EXPAND(_pw_passwd.pw_passwd);
- SCALAR(_pw_passwd.pw_uid);
- SCALAR(_pw_passwd.pw_gid);
- SCALAR(_pw_passwd.pw_change);
- EXPAND(_pw_passwd.pw_class);
- EXPAND(_pw_passwd.pw_gecos);
- EXPAND(_pw_passwd.pw_dir);
- EXPAND(_pw_passwd.pw_shell);
- SCALAR(_pw_passwd.pw_expire);
- bcopy(p, (char *)&_pw_passwd.pw_fields, sizeof _pw_passwd.pw_fields);
- p += sizeof _pw_passwd.pw_fields;
- return(1);
+ return (maptype);
}
-#ifdef YP
-
-static void
-_ypinitdb()
+/*
+ * parse a passwd file line (from NIS or HESIOD).
+ * assumed to be `old-style' if maptype != YPMAP_MASTER.
+ */
+static int
+__pwparse(pw, s)
+ struct passwd *pw;
+ char *s;
{
- DBT key, data;
- char buf[] = { _PW_KEYYPENABLED };
- key.data = buf;
- key.size = 1;
- _yp_enabled = 0;
- if ((_pw_db->get)(_pw_db, &key, &data, 0) == 0) {
- _yp_enabled = (int)*((char *)data.data) - 2;
- /* Don't even bother with this if we aren't root. */
- if (!geteuid()) {
- if (!_pw_yp_domain)
- if (yp_get_default_domain(&_pw_yp_domain))
- return;
- _gotmaster = _havemaster(_pw_yp_domain);
- } else _gotmaster = YP_HAVE_NONE;
- /*
- * Create a DB hash database in memory. Bet you didn't know you
- * could do a dbopen() with a NULL filename, did you.
- */
- if (_ypcache == (DB *)NULL)
- _ypcache = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL);
+ static char adjunctpw[YPMAXRECORD + 2];
+ int flags, maptype;
+
+ maptype = __ypmaptype();
+ flags = 0;
+ if (maptype == YPMAP_MASTER)
+ flags |= _PWSCAN_MASTER;
+ if (! __pw_scan(s, pw, flags))
+ return 1;
+
+ /* now let the prototype override, if set. */
+ if(__pwproto != (struct passwd *)NULL) {
+#ifdef PW_OVERRIDE_PASSWD
+ if(__pwproto_flags & _PWF_PASSWD)
+ pw->pw_passwd = __pwproto->pw_passwd;
+#endif
+ if(__pwproto_flags & _PWF_UID)
+ pw->pw_uid = __pwproto->pw_uid;
+ if(__pwproto_flags & _PWF_GID)
+ pw->pw_gid = __pwproto->pw_gid;
+ if(__pwproto_flags & _PWF_GECOS)
+ pw->pw_gecos = __pwproto->pw_gecos;
+ if(__pwproto_flags & _PWF_DIR)
+ pw->pw_dir = __pwproto->pw_dir;
+ if(__pwproto_flags & _PWF_SHELL)
+ pw->pw_shell = __pwproto->pw_shell;
}
+ if ((maptype == YPMAP_ADJUNCT) &&
+ (strstr(pw->pw_passwd, "##") != NULL)) {
+ char *data, *bp;
+ int datalen;
+
+ if (yp_match(__ypdomain, "passwd.adjunct.byname", pw->pw_name,
+ (int)strlen(pw->pw_name), &data, &datalen) == 0) {
+ if (datalen > sizeof(adjunctpw) - 1)
+ datalen = sizeof(adjunctpw) - 1;
+ strncpy(adjunctpw, data, (size_t)datalen);
+
+ /* skip name to get password */
+ if ((bp = strsep(&data, ":")) != NULL &&
+ (bp = strsep(&data, ":")) != NULL)
+ pw->pw_passwd = bp;
+ }
+ }
+ return 0;
}
+#endif /* _PASSWD_COMPAT */
/*
- * See if a user is in the blackballed list.
+ * local files implementation of getpw*()
+ * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
*/
-static inline int
-lookup(name)
- const char *name;
+static int _local_getpw __P((void *, void *, va_list));
+
+/*ARGSUSED*/
+static int
+_local_getpw(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
{
- DBT key;
+ DBT key;
+ char bf[/*CONSTCOND*/ MAX(MAXLOGNAME, sizeof(_pw_keynum)) + 1];
+ uid_t uid;
+ int search, len, rval;
+ const char *name;
- if (!_yp_exclusions)
- return(0);
+ if (!_pw_db && !__initdb())
+ return NS_UNAVAIL;
+
+ search = va_arg(ap, int);
+ bf[0] = search;
+ switch (search) {
+ case _PW_KEYBYNUM:
+ if (_pw_keynum == -1)
+ return NS_NOTFOUND; /* no more local records */
+ ++_pw_keynum;
+ memmove(bf + 1, &_pw_keynum, sizeof(_pw_keynum));
+ key.size = sizeof(_pw_keynum) + 1;
+ break;
+ case _PW_KEYBYNAME:
+ name = va_arg(ap, const char *);
+ len = strlen(name);
+ memmove(bf + 1, name, (size_t)MIN(len, MAXLOGNAME));
+ key.size = len + 1;
+ break;
+ case _PW_KEYBYUID:
+ uid = va_arg(ap, uid_t);
+ memmove(bf + 1, &uid, sizeof(len));
+ key.size = sizeof(uid) + 1;
+ break;
+ default:
+ abort();
+ }
- key.data = (char *)name;
- key.size = strlen(name);
+ key.data = (u_char *)bf;
+ rval = __hashpw(&key);
+ if (rval == NS_NOTFOUND && search == _PW_KEYBYNUM)
+ _pw_keynum = -1; /* flag `no more local records' */
- if ((_ypcache->get)(_ypcache, &key, &empty, 0)) {
- return(0);
+ if (!_pw_stayopen && (search != _PW_KEYBYNUM)) {
+ (void)(_pw_db->close)(_pw_db);
+ _pw_db = (DB *)NULL;
}
-
- return(1);
+ return (rval);
}
+#ifdef HESIOD
/*
- * Store a blackballed user in an in-core hash database.
+ * hesiod implementation of getpw*()
+ * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
*/
-static inline void
-store(key)
- const char *key;
-{
- DBT lkey;
-/*
- if (lookup(key))
- return;
-*/
-
- _yp_exclusions = 1;
+static int _dns_getpw __P((void *, void *, va_list));
- lkey.data = (char *)key;
- lkey.size = strlen(key);
+/*ARGSUSED*/
+static int
+_dns_getpw(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+ const char *name;
+ uid_t uid;
+ int search;
+
+ const char *map;
+ char **hp;
+ void *context;
+ int r;
+
+ search = va_arg(ap, int);
+ nextdnsbynum:
+ switch (search) {
+ case _PW_KEYBYNUM:
+ if (_pw_hesnum == -1)
+ return NS_NOTFOUND; /* no more hesiod records */
+ snprintf(line, sizeof(line) - 1, "passwd-%u", _pw_hesnum);
+ _pw_hesnum++;
+ map = "passwd";
+ break;
+ case _PW_KEYBYNAME:
+ name = va_arg(ap, const char *);
+ strncpy(line, name, sizeof(line));
+ map = "passwd";
+ break;
+ case _PW_KEYBYUID:
+ uid = va_arg(ap, uid_t);
+ snprintf(line, sizeof(line), "%u", (unsigned int)uid);
+ map = "uid"; /* XXX this is `passwd' on ultrix */
+ break;
+ default:
+ abort();
+ }
+ line[sizeof(line) - 1] = '\0';
+
+ r = NS_UNAVAIL;
+ if (hesiod_init(&context) == -1)
+ return (r);
+
+ hp = hesiod_resolve(context, line, map);
+ if (hp == NULL) {
+ if (errno == ENOENT) {
+ /* flag `no more hesiod records' */
+ if (search == _PW_KEYBYNUM)
+ _pw_hesnum = -1;
+ r = NS_NOTFOUND;
+ }
+ goto cleanup_dns_getpw;
+ }
- (void)(_ypcache->put)(_ypcache, &lkey, &empty, R_NOOVERWRITE);
+ strncpy(line, hp[0], sizeof(line)); /* only check first elem */
+ line[sizeof(line) - 1] = '\0';
+ hesiod_free_list(context, hp);
+ if (__pwparse(&_pw_passwd, line)) {
+ if (search == _PW_KEYBYNUM)
+ goto nextdnsbynum; /* skip dogdy entries */
+ r = NS_UNAVAIL;
+ } else
+ r = NS_SUCCESS;
+ cleanup_dns_getpw:
+ hesiod_end(context);
+ return (r);
}
+#endif
+#ifdef YP
/*
- * Parse the + entries in the password database and do appropriate
- * NIS lookups. While ugly to look at, this is optimized to do only
- * as many lookups as are absolutely necessary in any given case.
- * Basically, the getpwent() function will feed us + and - lines
- * as they appear in the database. For + lines, we do netgroup/group
- * and user lookups to find all usernames that match the rule and
- * extract them from the NIS passwd maps. For - lines, we save the
- * matching names in a database and a) exlude them, and b) make sure
- * we don't consider them when processing other + lines that appear
- * later.
+ * nis implementation of getpw*()
+ * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
*/
-static inline int
-unwind(grp)
- char *grp;
+static int _nis_getpw __P((void *, void *, va_list));
+
+/*ARGSUSED*/
+static int
+_nis_getpw(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
{
- char *user, *host, *domain;
- static int latch = 0;
- static struct group *gr = NULL;
- int rv = 0;
-
- if (grp[0] == '+') {
- if (strlen(grp) == 1) {
- return(_nextyppass(&_pw_passwd));
+ const char *name;
+ uid_t uid;
+ int search;
+ char *key, *data;
+ char *map;
+ int keylen, datalen, r, rval;
+
+ if(__ypdomain == NULL) {
+ if(_yp_check(&__ypdomain) == 0)
+ return NS_UNAVAIL;
+ }
+
+ map = PASSWD_BYNAME;
+ search = va_arg(ap, int);
+ switch (search) {
+ case _PW_KEYBYNUM:
+ break;
+ case _PW_KEYBYNAME:
+ name = va_arg(ap, const char *);
+ strncpy(line, name, sizeof(line));
+ break;
+ case _PW_KEYBYUID:
+ uid = va_arg(ap, uid_t);
+ snprintf(line, sizeof(line), "%u", (unsigned int)uid);
+ map = PASSWD_BYUID;
+ break;
+ default:
+ abort();
+ }
+ line[sizeof(line) - 1] = '\0';
+ rval = NS_UNAVAIL;
+ if (search != _PW_KEYBYNUM) {
+ data = NULL;
+ r = yp_match(__ypdomain, map, line, (int)strlen(line),
+ &data, &datalen);
+ if (r == YPERR_KEY)
+ rval = NS_NOTFOUND;
+ if (r != 0) {
+ if (data)
+ free(data);
+ return (rval);
}
- if (grp[1] == '@') {
- _pw_stepping_yp = 1;
-grpagain:
- if (gr != NULL) {
- if (*gr->gr_mem != NULL) {
- if (lookup(*gr->gr_mem)) {
- gr->gr_mem++;
- goto grpagain;
- }
- rv = _getyppass(&_pw_passwd,
- *gr->gr_mem,
- "passwd.byname");
- gr->gr_mem++;
- return(rv);
- } else {
- latch = 0;
- _pw_stepping_yp = 0;
- gr = NULL;
- return(0);
- }
- }
- if (!latch) {
- setnetgrent(grp+2);
- latch++;
- }
-again:
- if (getnetgrent(&host, &user, &domain) == 0) {
- if ((gr = getgrnam(grp+2)) != NULL)
- goto grpagain;
- latch = 0;
- _pw_stepping_yp = 0;
- return(0);
- } else {
- if (lookup(user))
- goto again;
- if (_getyppass(&_pw_passwd, user,
- "passwd.byname"))
- return(1);
- else
- goto again;
+ data[datalen] = '\0'; /* clear trailing \n */
+ strncpy(line, data, sizeof(line));
+ line[sizeof(line) - 1] = '\0';
+ free(data);
+ if (__pwparse(&_pw_passwd, line))
+ return NS_UNAVAIL;
+ return NS_SUCCESS;
+ }
+
+ if (_pw_ypdone)
+ return NS_NOTFOUND;
+ for (;;) {
+ data = key = NULL;
+ if (__ypcurrent) {
+ r = yp_next(__ypdomain, map,
+ __ypcurrent, __ypcurrentlen,
+ &key, &keylen, &data, &datalen);
+ free(__ypcurrent);
+ switch (r) {
+ case 0:
+ __ypcurrent = key;
+ __ypcurrentlen = keylen;
+ break;
+ case YPERR_NOMORE:
+ __ypcurrent = NULL;
+ /* flag `no more yp records' */
+ _pw_ypdone = 1;
+ rval = NS_NOTFOUND;
}
} else {
- if (lookup(grp+1))
- return(0);
- return(_getyppass(&_pw_passwd, grp+1, "passwd.byname"));
+ r = yp_first(__ypdomain, map, &__ypcurrent,
+ &__ypcurrentlen, &data, &datalen);
}
- } else {
- if (grp[1] == '@') {
- setnetgrent(grp+2);
- rv = 0;
- while(getnetgrent(&host, &user, &domain) != 0) {
- store(user);
- rv++;
- }
- if (!rv && (gr = getgrnam(grp+2)) != NULL) {
- while(*gr->gr_mem) {
- store(*gr->gr_mem);
- gr->gr_mem++;
- }
- }
- } else {
- store(grp+1);
+ if (r != 0) {
+ if (key)
+ free(key);
+ if (data)
+ free(data);
+ return (rval);
}
+ data[datalen] = '\0'; /* clear trailing \n */
+ strncpy(line, data, sizeof(line));
+ line[sizeof(line) - 1] = '\0';
+ free(data);
+ if (! __pwparse(&_pw_passwd, line))
+ return NS_SUCCESS;
}
- return(0);
-}
+ /* NOTREACHED */
+} /* _nis_getpw */
+#endif
+#ifdef _PASSWD_COMPAT
/*
- * See if a user is a member of a particular group.
+ * See if the compat token is in the database. Only works if pwd_mkdb knows
+ * about the token.
*/
-static inline int
-ingr(grp, name)
- const char *grp;
- const char *name;
+static int __has_compatpw __P((void));
+
+static int
+__has_compatpw()
{
- register struct group *gr;
+ DBT key, data;
+ DBT pkey, pdata;
+ char bf[MAXLOGNAME];
+ u_char cyp[] = { _PW_KEYYPENABLED };
- if ((gr = getgrnam(grp)) == NULL)
- return(0);
+ /*LINTED*/
+ key.data = cyp;
+ key.size = 1;
- while(*gr->gr_mem) {
- if (!strcmp(*gr->gr_mem, name))
- return(1);
- gr->gr_mem++;
- }
+ /* Pre-token database support. */
+ bf[0] = _PW_KEYBYNAME;
+ bf[1] = '+';
+ pkey.data = (u_char *)bf;
+ pkey.size = 2;
- return(0);
+ if ((_pw_db->get)(_pw_db, &key, &data, 0)
+ && (_pw_db->get)(_pw_db, &pkey, &pdata, 0))
+ return 0; /* No compat token */
+ return 1;
}
/*
- * Check a user against the +@netgroup/-@netgroup lines listed in
- * the local password database. Also checks +user/-user lines.
- * If no netgroup exists that matches +@netgroup/-@netgroup,
- * try searching regular groups with the same name.
+ * log an error if "files" or "compat" is specified in passwd_compat database
*/
-static inline int
-verf(name)
- const char *name;
-{
- DBT key;
- char bf[sizeof(_pw_keynum) + 1];
- int keynum = 0;
+static int _bad_getpw __P((void *, void *, va_list));
-again:
- ++keynum;
- bf[0] = _PW_KEYYPBYNUM;
- bcopy((char *)&keynum, bf + 1, sizeof(keynum));
- key.data = (u_char *)bf;
- key.size = sizeof(keynum) + 1;
- if (!__hashpw(&key)) {
- /* Try again using old format */
- bf[0] = _PW_KEYBYNUM;
- bcopy((char *)&keynum, bf + 1, sizeof(keynum));
- key.data = (u_char *)bf;
- if (!__hashpw(&key))
- return(0);
- }
- if (_pw_passwd.pw_name[0] != '+' && (_pw_passwd.pw_name[0] != '-'))
- goto again;
- if (_pw_passwd.pw_name[0] == '+') {
- if (strlen(_pw_passwd.pw_name) == 1) /* Wildcard */
- return(1);
- if (_pw_passwd.pw_name[1] == '@') {
- if ((innetgr(_pw_passwd.pw_name+2, NULL, name,
- _pw_yp_domain) ||
- ingr(_pw_passwd.pw_name+2, name)) && !lookup(name))
- return(1);
- else
- goto again;
- } else {
- if (!strcmp(name, _pw_passwd.pw_name+1) &&
- !lookup(name))
- return(1);
- else
- goto again;
- }
- }
- if (_pw_passwd.pw_name[0] == '-') {
- /* Note that a minus wildcard is a no-op. */
- if (_pw_passwd.pw_name[1] == '@') {
- if (innetgr(_pw_passwd.pw_name+2, NULL, name,
- _pw_yp_domain) ||
- ingr(_pw_passwd.pw_name+2, name)) {
- store(name);
- return(0);
- } else
- goto again;
- } else {
- if (!strcmp(name, _pw_passwd.pw_name+1)) {
- store(name);
- return(0);
- } else
- goto again;
- }
-
+/*ARGSUSED*/
+static int
+_bad_getpw(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+ static int warned;
+ if (!warned) {
+ syslog(LOG_ERR,
+ "nsswitch.conf passwd_compat database can't use '%s'",
+ (char *)cb_data);
}
- return(0);
+ warned = 1;
+ return NS_UNAVAIL;
}
-static char *
-_get_adjunct_pw(name)
- const char *name;
-{
- static char adjunctbuf[YPMAXRECORD+2];
- int rval;
- char *result;
- int resultlen;
- char *map = "passwd.adjunct.byname";
- char *s;
-
- if ((rval = yp_match(_pw_yp_domain, map, name, strlen(name),
- &result, &resultlen)))
- return(NULL);
-
- strncpy(adjunctbuf, result, resultlen);
- adjunctbuf[resultlen] = '\0';
- free(result);
- result = (char *)&adjunctbuf;
-
- /* Don't care about the name. */
- if ((s = strsep(&result, ":")) == NULL)
- return (NULL); /* name */
- if ((s = strsep(&result, ":")) == NULL)
- return (NULL); /* password */
+/*
+ * when a name lookup in compat mode is required (e.g., '+name', or a name in
+ * '+@netgroup'), look it up in the 'passwd_compat' nsswitch database.
+ * only Hesiod and NIS is supported - it doesn't make sense to lookup
+ * compat names from 'files' or 'compat'.
+ */
+static int __getpwcompat __P((int, uid_t, const char *));
- return(s);
+static int
+__getpwcompat(type, uid, name)
+ int type;
+ uid_t uid;
+ const char *name;
+{
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_bad_getpw, "files")
+ NS_DNS_CB(_dns_getpw, NULL)
+ NS_NIS_CB(_nis_getpw, NULL)
+ NS_COMPAT_CB(_bad_getpw, "compat")
+ { 0 }
+ };
+ static const ns_src defaultnis[] = {
+ { NSSRC_NIS, NS_SUCCESS },
+ { 0 }
+ };
+
+ switch (type) {
+ case _PW_KEYBYNUM:
+ return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "getpwcompat",
+ defaultnis, type);
+ case _PW_KEYBYNAME:
+ return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "getpwcompat",
+ defaultnis, type, name);
+ case _PW_KEYBYUID:
+ return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "getpwcompat",
+ defaultnis, type, uid);
+ default:
+ abort();
+ /*NOTREACHED*/
+ }
}
+#endif /* _PASSWD_COMPAT */
+
+/*
+ * compat implementation of getpwent()
+ * varargs (ignored):
+ * type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
+ */
+static int _compat_getpwent __P((void *, void *, va_list));
+/*ARGSUSED*/
static int
-_pw_breakout_yp(struct passwd *pw, char *res, int resultlen, int master)
+_compat_getpwent(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
{
- char *s, *result;
- static char resbuf[YPMAXRECORD+2];
+ DBT key;
+ int rval;
+ char bf[sizeof(_pw_keynum) + 1];
+#ifdef _PASSWD_COMPAT
+ static char *name = NULL;
+ char *user, *host, *dom;
+ int has_compatpw;
+#endif
- /*
- * Be triple, ultra super-duper paranoid: reject entries
- * that start with a + or -. yp_mkdb and /var/yp/Makefile
- * are _both_ supposed to strip these out, but you never
- * know.
- */
- if (*res == '+' || *res == '-')
- return 0;
+ if (!_pw_db && !__initdb())
+ return NS_UNAVAIL;
- /*
- * The NIS protocol definition limits the size of an NIS
- * record to YPMAXRECORD bytes. We need to do a copy to
- * a static buffer here since the memory pointed to by
- * res will be free()ed when this function returns.
- */
- strncpy((char *)&resbuf, res, resultlen);
- resbuf[resultlen] = '\0';
- result = (char *)&resbuf;
+#ifdef _PASSWD_COMPAT
+ has_compatpw = __has_compatpw();
- /*
- * XXX Sanity check: make sure all fields are valid (no NULLs).
- * If we find a badly formatted entry, we punt.
- */
- if ((s = strsep(&result, ":")) == NULL) return 0; /* name */
- /*
- * We don't care what pw_fields says: we _always_ want the
- * username returned to us by NIS.
- */
- pw->pw_name = s;
- pw->pw_fields |= _PWF_NAME;
-
- if ((s = strsep(&result, ":")) == NULL) return 0; /* password */
- if(!(pw->pw_fields & _PWF_PASSWD)) {
- /* SunOS passwd.adjunct hack */
- if (master == YP_HAVE_ADJUNCT && strstr(s, "##") != NULL) {
- char *realpw;
- realpw = _get_adjunct_pw(pw->pw_name);
- if (realpw == NULL)
- pw->pw_passwd = s;
- else
- pw->pw_passwd = realpw;
- } else {
- pw->pw_passwd = s;
+again:
+ if (has_compatpw && (__pwmode != PWMODE_NONE)) {
+ int r;
+
+ switch (__pwmode) {
+ case PWMODE_FULL:
+ r = __getpwcompat(_PW_KEYBYNUM, 0, NULL);
+ if (r == NS_SUCCESS)
+ return r;
+ __pwmode = PWMODE_NONE;
+ break;
+
+ case PWMODE_NETGRP:
+ r = getnetgrent(&host, &user, &dom);
+ if (r == 0) { /* end of group */
+ endnetgrent();
+ __pwmode = PWMODE_NONE;
+ break;
+ }
+ if (!user || !*user)
+ break;
+ r = __getpwcompat(_PW_KEYBYNAME, 0, user);
+ if (r == NS_SUCCESS)
+ return r;
+ break;
+
+ case PWMODE_USER:
+ if (name == NULL) {
+ __pwmode = PWMODE_NONE;
+ break;
+ }
+ r = __getpwcompat(_PW_KEYBYNAME, 0, name);
+ free(name);
+ name = NULL;
+ if (r == NS_SUCCESS)
+ return r;
+ break;
+
+ case PWMODE_NONE:
+ abort();
}
- pw->pw_fields |= _PWF_PASSWD;
+ goto again;
}
+#endif
- if ((s = strsep(&result, ":")) == NULL) return 0; /* uid */
- if(!(pw->pw_fields & _PWF_UID)) {
- pw->pw_uid = atoi(s);
- pw->pw_fields |= _PWF_UID;
- }
+ if (_pw_keynum == -1)
+ return NS_NOTFOUND; /* no more local records */
+ ++_pw_keynum;
+ bf[0] = _PW_KEYBYNUM;
+ memmove(bf + 1, &_pw_keynum, sizeof(_pw_keynum));
+ key.data = (u_char *)bf;
+ key.size = sizeof(_pw_keynum) + 1;
+ rval = __hashpw(&key);
+ if (rval == NS_NOTFOUND)
+ _pw_keynum = -1; /* flag `no more local records' */
+ else if (rval == NS_SUCCESS) {
+#ifdef _PASSWD_COMPAT
+ /* if we don't have YP at all, don't bother. */
+ if (has_compatpw) {
+ if(_pw_passwd.pw_name[0] == '+') {
+ /* set the mode */
+ switch(_pw_passwd.pw_name[1]) {
+ case '\0':
+ __pwmode = PWMODE_FULL;
+ break;
+ case '@':
+ __pwmode = PWMODE_NETGRP;
+ setnetgrent(_pw_passwd.pw_name + 2);
+ break;
+ default:
+ __pwmode = PWMODE_USER;
+ name = strdup(_pw_passwd.pw_name + 1);
+ break;
+ }
- if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */
- if(!(pw->pw_fields & _PWF_GID)) {
- pw->pw_gid = atoi(s);
- pw->pw_fields |= _PWF_GID;
+ /* save the prototype */
+ __pwproto_set();
+ goto again;
+ } else if(_pw_passwd.pw_name[0] == '-') {
+ /* an attempted exclusion */
+ switch(_pw_passwd.pw_name[1]) {
+ case '\0':
+ break;
+ case '@':
+ setnetgrent(_pw_passwd.pw_name + 2);
+ while(getnetgrent(&host, &user, &dom)) {
+ if(user && *user)
+ __pwexclude_add(user);
+ }
+ endnetgrent();
+ break;
+ default:
+ __pwexclude_add(_pw_passwd.pw_name + 1);
+ break;
+ }
+ goto again;
+ }
+ }
+#endif
}
+ return (rval);
+}
- if (master == YP_HAVE_MASTER) {
- if ((s = strsep(&result, ":")) == NULL) return 0; /* class */
- if(!(pw->pw_fields & _PWF_CLASS)) {
- pw->pw_class = s;
- pw->pw_fields |= _PWF_CLASS;
- }
+/*
+ * compat implementation of getpwnam() and getpwuid()
+ * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
+ */
+static int _compat_getpw __P((void *, void *, va_list));
- if ((s = strsep(&result, ":")) == NULL) return 0; /* change */
- if(!(pw->pw_fields & _PWF_CHANGE)) {
- pw->pw_change = atol(s);
- pw->pw_fields |= _PWF_CHANGE;
- }
+static int
+_compat_getpw(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+#ifdef _PASSWD_COMPAT
+ DBT key;
+ int search, rval, r, s, keynum;
+ uid_t uid;
+ char bf[sizeof(keynum) + 1];
+ char *name, *host, *user, *dom;
+#endif
- if ((s = strsep(&result, ":")) == NULL) return 0; /* expire */
- if(!(pw->pw_fields & _PWF_EXPIRE)) {
- pw->pw_expire = atol(s);
- pw->pw_fields |= _PWF_EXPIRE;
- }
- }
+ if (!_pw_db && !__initdb())
+ return NS_UNAVAIL;
- if ((s = strsep(&result, ":")) == NULL) return 0; /* gecos */
- if(!(pw->pw_fields & _PWF_GECOS)) {
- pw->pw_gecos = s;
- pw->pw_fields |= _PWF_GECOS;
+ /*
+ * If there isn't a compat token in the database, use files.
+ */
+#ifdef _PASSWD_COMPAT
+ if (! __has_compatpw())
+#endif
+ return (_local_getpw(rv, cb_data, ap));
+
+#ifdef _PASSWD_COMPAT
+ search = va_arg(ap, int);
+ uid = 0;
+ name = NULL;
+ rval = NS_NOTFOUND;
+ switch (search) {
+ case _PW_KEYBYNAME:
+ name = va_arg(ap, char *);
+ break;
+ case _PW_KEYBYUID:
+ uid = va_arg(ap, uid_t);
+ break;
+ default:
+ abort();
}
- if ((s = strsep(&result, ":")) == NULL) return 0; /* dir */
- if(!(pw->pw_fields & _PWF_DIR)) {
- pw->pw_dir = s;
- pw->pw_fields |= _PWF_DIR;
+ for (s = -1, keynum = 1 ; ; keynum++) {
+ bf[0] = _PW_KEYBYNUM;
+ memmove(bf + 1, &keynum, sizeof(keynum));
+ key.data = (u_char *)bf;
+ key.size = sizeof(keynum) + 1;
+ if(__hashpw(&key) != NS_SUCCESS)
+ break;
+ switch(_pw_passwd.pw_name[0]) {
+ case '+':
+ /* save the prototype */
+ __pwproto_set();
+
+ switch(_pw_passwd.pw_name[1]) {
+ case '\0':
+ r = __getpwcompat(search, uid, name);
+ if (r != NS_SUCCESS)
+ continue;
+ break;
+ case '@':
+pwnam_netgrp:
+#if 0 /* XXX: is this a hangover from pre-nsswitch? */
+ if(__ypcurrent) {
+ free(__ypcurrent);
+ __ypcurrent = NULL;
+ }
+#endif
+ if (s == -1) /* first time */
+ setnetgrent(_pw_passwd.pw_name + 2);
+ s = getnetgrent(&host, &user, &dom);
+ if (s == 0) { /* end of group */
+ endnetgrent();
+ s = -1;
+ continue;
+ }
+ if (!user || !*user)
+ goto pwnam_netgrp;
+
+ r = __getpwcompat(_PW_KEYBYNAME, 0, user);
+
+ if (r == NS_UNAVAIL)
+ return r;
+ if (r == NS_NOTFOUND) {
+ /*
+ * just because this user is bad
+ * it doesn't mean they all are.
+ */
+ goto pwnam_netgrp;
+ }
+ break;
+ default:
+ user = _pw_passwd.pw_name + 1;
+ r = __getpwcompat(_PW_KEYBYNAME, 0, user);
+
+ if (r == NS_UNAVAIL)
+ return r;
+ if (r == NS_NOTFOUND)
+ continue;
+ break;
+ }
+ if(__pwexclude_is(_pw_passwd.pw_name)) {
+ if(s == 1) /* inside netgroup */
+ goto pwnam_netgrp;
+ continue;
+ }
+ break;
+ case '-':
+ /* attempted exclusion */
+ switch(_pw_passwd.pw_name[1]) {
+ case '\0':
+ break;
+ case '@':
+ setnetgrent(_pw_passwd.pw_name + 2);
+ while(getnetgrent(&host, &user, &dom)) {
+ if(user && *user)
+ __pwexclude_add(user);
+ }
+ endnetgrent();
+ break;
+ default:
+ __pwexclude_add(_pw_passwd.pw_name + 1);
+ break;
+ }
+ break;
+ }
+ if ((search == _PW_KEYBYNAME &&
+ strcmp(_pw_passwd.pw_name, name) == 0)
+ || (search == _PW_KEYBYUID && _pw_passwd.pw_uid == uid)) {
+ rval = NS_SUCCESS;
+ break;
+ }
+ if(s == 1) /* inside netgroup */
+ goto pwnam_netgrp;
+ continue;
}
+ __pwproto = (struct passwd *)NULL;
- if ((s = strsep(&result, ":")) == NULL) return 0; /* shell */
- if(!(pw->pw_fields & _PWF_SHELL)) {
- pw->pw_shell = s;
- pw->pw_fields |= _PWF_SHELL;
+ if (!_pw_stayopen) {
+ (void)(_pw_db->close)(_pw_db);
+ _pw_db = (DB *)NULL;
}
-
- /* Be consistent. */
- if ((s = strchr(pw->pw_shell, '\n'))) *s = '\0';
-
- return 1;
+ if(__pwexclude != (DB *)NULL) {
+ (void)(__pwexclude->close)(__pwexclude);
+ __pwexclude = (DB *)NULL;
+ }
+ return rval;
+#endif /* _PASSWD_COMPAT */
}
-static int
-_havemaster(char *_yp_domain)
+struct passwd *
+getpwent()
{
- int order;
- int rval;
+ int r;
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_local_getpw, NULL)
+ NS_DNS_CB(_dns_getpw, NULL)
+ NS_NIS_CB(_nis_getpw, NULL)
+ NS_COMPAT_CB(_compat_getpwent, NULL)
+ { 0 }
+ };
+
+ r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent", compatsrc,
+ _PW_KEYBYNUM);
+ if (r != NS_SUCCESS)
+ return (struct passwd *)NULL;
+ return &_pw_passwd;
+}
- if (!(rval = yp_order(_yp_domain, "master.passwd.byname", &order)))
- return(YP_HAVE_MASTER);
+struct passwd *
+getpwnam(name)
+ const char *name;
+{
+ int r;
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_local_getpw, NULL)
+ NS_DNS_CB(_dns_getpw, NULL)
+ NS_NIS_CB(_nis_getpw, NULL)
+ NS_COMPAT_CB(_compat_getpw, NULL)
+ { 0 }
+ };
+
+ if (name == NULL || name[0] == '\0')
+ return (struct passwd *)NULL;
+
+ r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam", compatsrc,
+ _PW_KEYBYNAME, name);
+ return (r == NS_SUCCESS ? &_pw_passwd : (struct passwd *)NULL);
+}
- /*
- * NIS+ in YP compat mode doesn't support
- * YPPROC_ORDER -- no point in continuing.
- */
- if (rval == YPERR_YPERR)
- return(YP_HAVE_NONE);
+struct passwd *
+getpwuid(uid)
+ uid_t uid;
+{
+ int r;
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_local_getpw, NULL)
+ NS_DNS_CB(_dns_getpw, NULL)
+ NS_NIS_CB(_nis_getpw, NULL)
+ NS_COMPAT_CB(_compat_getpw, NULL)
+ { 0 }
+ };
+
+ r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid", compatsrc,
+ _PW_KEYBYUID, uid);
+ return (r == NS_SUCCESS ? &_pw_passwd : (struct passwd *)NULL);
+}
- /* master.passwd doesn't exist -- try passwd.adjunct */
- if (rval == YPERR_MAP) {
- rval = yp_order(_yp_domain, "passwd.adjunct.byname", &order);
- if (!rval)
- return(YP_HAVE_ADJUNCT);
+int
+setpassent(stayopen)
+ int stayopen;
+{
+ _pw_keynum = 0;
+ _pw_stayopen = stayopen;
+#ifdef YP
+ __pwmode = PWMODE_NONE;
+ if(__ypcurrent)
+ free(__ypcurrent);
+ __ypcurrent = NULL;
+ _pw_ypdone = 0;
+#endif
+#ifdef HESIOD
+ _pw_hesnum = 0;
+#endif
+#ifdef _PASSWD_COMPAT
+ if(__pwexclude != (DB *)NULL) {
+ (void)(__pwexclude->close)(__pwexclude);
+ __pwexclude = (DB *)NULL;
}
+ __pwproto = (struct passwd *)NULL;
+#endif
+ return 1;
+}
- return (YP_HAVE_NONE);
+void
+setpwent()
+{
+ (void) setpassent(0);
}
-static int
-_getyppass(struct passwd *pw, const char *name, const char *map)
+void
+endpwent()
{
- char *result, *s;
- int resultlen;
- int rv;
- char mastermap[YPMAXRECORD];
-
- if(!_pw_yp_domain) {
- if(yp_get_default_domain(&_pw_yp_domain))
- return 0;
+ _pw_keynum = 0;
+ if (_pw_db) {
+ (void)(_pw_db->close)(_pw_db);
+ _pw_db = (DB *)NULL;
}
-
- if (_gotmaster == YP_HAVE_MASTER)
- snprintf(mastermap, sizeof(mastermap), "master.%s", map);
- else
- snprintf(mastermap, sizeof(mastermap), "%s", map);
-
- if(yp_match(_pw_yp_domain, (char *)&mastermap, name, strlen(name),
- &result, &resultlen)) {
- if (_gotmaster != YP_HAVE_MASTER)
- return 0;
- snprintf(mastermap, sizeof(mastermap), "%s", map);
- if (yp_match(_pw_yp_domain, (char *)&mastermap,
- name, strlen(name), &result, &resultlen))
- return 0;
- _gotmaster = YP_HAVE_NONE;
+#ifdef _PASSWD_COMPAT
+ __pwmode = PWMODE_NONE;
+#endif
+#ifdef YP
+ if(__ypcurrent)
+ free(__ypcurrent);
+ __ypcurrent = NULL;
+ _pw_ypdone = 0;
+#endif
+#ifdef HESIOD
+ _pw_hesnum = 0;
+#endif
+#ifdef _PASSWD_COMPAT
+ if(__pwexclude != (DB *)NULL) {
+ (void)(__pwexclude->close)(__pwexclude);
+ __pwexclude = (DB *)NULL;
}
+ __pwproto = (struct passwd *)NULL;
+#endif
+}
- if (!_pw_stepping_yp) {
- s = strchr(result, ':');
- if (s) {
- *s = '\0';
- } else {
- /* Must be a malformed entry if no colons. */
- free(result);
- return(0);
- }
-
- if (!verf(result)) {
- *s = ':';
- free(result);
- return(0);
- }
+static int
+__initdb()
+{
+ static int warned;
+ char *p;
- *s = ':'; /* Put back the colon we previously replaced with a NUL. */
+#ifdef _PASSWD_COMPAT
+ __pwmode = PWMODE_NONE;
+#endif
+ if (geteuid() == 0) {
+ _pw_db = dbopen((p = _PATH_SMP_DB), O_RDONLY, 0, DB_HASH, NULL);
+ if (_pw_db)
+ return(1);
}
-
- rv = _pw_breakout_yp(pw, result, resultlen, _gotmaster);
- free(result);
- return(rv);
+ _pw_db = dbopen((p = _PATH_MP_DB), O_RDONLY, 0, DB_HASH, NULL);
+ if (_pw_db)
+ return 1;
+ if (!warned)
+ syslog(LOG_ERR, "%s: %m", p);
+ warned = 1;
+ return 0;
}
static int
-_nextyppass(struct passwd *pw)
+__hashpw(key)
+ DBT *key;
{
- static char *key;
- static int keylen;
- char *lastkey, *result, *s;
- int resultlen;
- int rv;
- char *map = "passwd.byname";
-
- if(!_pw_yp_domain) {
- if(yp_get_default_domain(&_pw_yp_domain))
- return 0;
- }
-
- if (_gotmaster == YP_HAVE_MASTER)
- map = "master.passwd.byname";
+ char *p, *t;
+ static u_int max;
+ static char *buf;
+ DBT data;
- if(!_pw_stepping_yp) {
- if(key) free(key);
- rv = yp_first(_pw_yp_domain, map,
- &key, &keylen, &result, &resultlen);
- if(rv) {
- return 0;
- }
- _pw_stepping_yp = 1;
- goto unpack;
- } else {
-tryagain:
- lastkey = key;
- rv = yp_next(_pw_yp_domain, map, key, keylen,
- &key, &keylen, &result, &resultlen);
- free(lastkey);
-unpack:
- if(rv) {
- _pw_stepping_yp = 0;
- return 0;
- }
+ switch ((_pw_db->get)(_pw_db, key, &data, 0)) {
+ case 0:
+ break; /* found */
+ case 1:
+ return NS_NOTFOUND;
+ case -1:
+ return NS_UNAVAIL; /* error in db routines */
+ default:
+ abort();
+ }
- s = strchr(result, ':');
- if (s) {
- *s = '\0';
- } else {
- /* Must be a malformed entry if no colons. */
- free(result);
- goto tryagain;
- }
+ p = (char *)data.data;
+ if (data.size > max && !(buf = realloc(buf, (max += 1024))))
+ return NS_UNAVAIL;
- if (lookup(result)) {
- *s = ':';
- free(result);
- goto tryagain;
- }
+ /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
+ t = buf;
+#define EXPAND(e) e = t; while ((*t++ = *p++));
+#define SCALAR(v) memmove(&(v), p, sizeof v); p += sizeof v
+ EXPAND(_pw_passwd.pw_name);
+ EXPAND(_pw_passwd.pw_passwd);
+ SCALAR(_pw_passwd.pw_uid);
+ SCALAR(_pw_passwd.pw_gid);
+ SCALAR(_pw_passwd.pw_change);
+ EXPAND(_pw_passwd.pw_class);
+ EXPAND(_pw_passwd.pw_gecos);
+ EXPAND(_pw_passwd.pw_dir);
+ EXPAND(_pw_passwd.pw_shell);
+ SCALAR(_pw_passwd.pw_expire);
+ SCALAR(_pw_passwd.pw_fields);
- *s = ':'; /* Put back the colon we previously replaced with a NUL. */
- if (_pw_breakout_yp(pw, result, resultlen, _gotmaster)) {
- free(result);
- return(1);
- } else {
- free(result);
- goto tryagain;
- }
- }
+ return NS_SUCCESS;
}
-
-#endif /* YP */
diff --git a/lib/libc/gen/getusershell.3 b/lib/libc/gen/getusershell.3
index 068c5d9..d4924fa 100644
--- a/lib/libc/gen/getusershell.3
+++ b/lib/libc/gen/getusershell.3
@@ -1,3 +1,6 @@
+.\" $NetBSD: getusershell.3,v 1.6 1999/03/22 19:44:42 garbled Exp $
+.\" $FreeBSD$
+.\"
.\" Copyright (c) 1985, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
@@ -30,16 +33,15 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)getusershell.3 8.1 (Berkeley) 6/4/93
-.\" $FreeBSD$
.\"
-.Dd June 4, 1993
+.Dd January 16, 1999
.Dt GETUSERSHELL 3
-.Os BSD 4.3
+.Os
.Sh NAME
.Nm getusershell ,
.Nm setusershell ,
.Nm endusershell
-.Nd get legal user shells
+.Nd get valid user shells
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
@@ -54,18 +56,16 @@
The
.Fn getusershell
function
-returns a pointer to a legal user shell as defined by the
-system manager in the file
-.Pa /etc/shells .
-If
-.Pa /etc/shells
-is unreadable or does not exist,
+returns a pointer to a valid user shell as defined by the
+system manager in the shells database as described in
+.Xr shells 5 .
+If the shells database is not available,
.Fn getusershell
behaves as if
.Pa /bin/sh
and
.Pa /bin/csh
-were listed in the file.
+were listed.
.Pp
The
.Fn getusershell
@@ -86,6 +86,7 @@ The routine
returns a null pointer (0) on
.Dv EOF .
.Sh SEE ALSO
+.Xr nsswitch.conf 5 ,
.Xr shells 5
.Sh HISTORY
The
@@ -96,7 +97,6 @@ function appeared in
The
.Fn getusershell
function leaves its result in an internal static object and returns
-a pointer to that object.
-Subsequent calls to
+a pointer to that object. Subsequent calls to
.Fn getusershell
will modify the same object.
diff --git a/lib/libc/gen/getusershell.c b/lib/libc/gen/getusershell.c
index be1a77a..a852421 100644
--- a/lib/libc/gen/getusershell.c
+++ b/lib/libc/gen/getusershell.c
@@ -1,3 +1,5 @@
+/* $NetBSD: getusershell.c,v 1.17 1999/01/25 01:09:34 lukem Exp $ */
+
/*
* Copyright (c) 1985, 1993
* The Regents of the University of California. All rights reserved.
@@ -29,111 +31,248 @@
* 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$
*/
+#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)getusershell.c 8.1 (Berkeley) 6/4/93";
+static char rcsid[] =
+ "$FreeBSD$";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
#include <sys/file.h>
-#include <sys/stat.h>
-#include <stdio.h>
+
#include <ctype.h>
+#include <errno.h>
+#include <nsswitch.h>
+#include <paths.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <stringlist.h>
#include <unistd.h>
-#include <paths.h>
+
+#ifdef HESIOD
+#include <hesiod.h>
+#endif
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yp_prot.h>
+#endif
/*
* Local shells should NOT be added here. They should be added in
* /etc/shells.
*/
-static char *okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL };
-static char **curshell, **shells, *strings;
-static char **initshells __P((void));
+static const char *const okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL };
+static const char *const *curshell;
+static StringList *sl;
+
+static const char *const *initshells __P((void));
/*
- * Get a list of shells from _PATH_SHELLS, if it exists.
+ * Get a list of shells from "shells" nsswitch database
*/
char *
-getusershell()
+getusershell(void)
{
char *ret;
if (curshell == NULL)
curshell = initshells();
- ret = *curshell;
+ /*LINTED*/
+ ret = (char *)*curshell;
if (ret != NULL)
curshell++;
return (ret);
}
void
-endusershell()
+endusershell(void)
{
-
- if (shells != NULL)
- free(shells);
- shells = NULL;
- if (strings != NULL)
- free(strings);
- strings = NULL;
+ if (sl)
+ sl_free(sl, 1);
+ sl = NULL;
curshell = NULL;
}
void
-setusershell()
+setusershell(void)
{
curshell = initshells();
}
-static char **
-initshells()
+
+static int _local_initshells __P((void *, void *, va_list));
+
+/*ARGSUSED*/
+static int
+_local_initshells(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
{
- register char **sp, *cp;
- register FILE *fp;
- struct stat statb;
-
- if (shells != NULL)
- free(shells);
- shells = NULL;
- if (strings != NULL)
- free(strings);
- strings = NULL;
+ char *sp, *cp;
+ FILE *fp;
+ char line[MAXPATHLEN + 2];
+
+ if (sl)
+ sl_free(sl, 1);
+ sl = sl_init();
+
if ((fp = fopen(_PATH_SHELLS, "r")) == NULL)
- return (okshells);
- if (fstat(fileno(fp), &statb) == -1) {
- (void)fclose(fp);
- return (okshells);
- }
- if ((strings = malloc((u_int)statb.st_size)) == NULL) {
- (void)fclose(fp);
- return (okshells);
- }
- shells = calloc((unsigned)statb.st_size / 3, sizeof (char *));
- if (shells == NULL) {
- (void)fclose(fp);
- free(strings);
- strings = NULL;
- return (okshells);
- }
- sp = shells;
- cp = strings;
+ return NS_UNAVAIL;
+
+ sp = cp = line;
while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) {
while (*cp != '#' && *cp != '/' && *cp != '\0')
cp++;
if (*cp == '#' || *cp == '\0')
continue;
- *sp++ = cp;
- while (!isspace((unsigned char)*cp) && *cp != '#' && *cp != '\0')
+ sp = cp;
+ while (!isspace(*cp) && *cp != '#' && *cp != '\0')
cp++;
*cp++ = '\0';
+ sl_add(sl, strdup(sp));
}
- *sp = NULL;
(void)fclose(fp);
- return (shells);
+ return NS_SUCCESS;
+}
+
+#ifdef HESIOD
+static int _dns_initshells __P((void *, void *, va_list));
+
+/*ARGSUSED*/
+static int
+_dns_initshells(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+ char shellname[] = "shells-XXXXX";
+ int hsindex, hpi, r;
+ char **hp;
+ void *context;
+
+ if (sl)
+ sl_free(sl, 1);
+ sl = sl_init();
+ r = NS_UNAVAIL;
+ if (hesiod_init(&context) == -1)
+ return (r);
+
+ for (hsindex = 0; ; hsindex++) {
+ snprintf(shellname, sizeof(shellname)-1, "shells-%d", hsindex);
+ hp = hesiod_resolve(context, shellname, "shells");
+ if (hp == NULL) {
+ if (errno == ENOENT) {
+ if (hsindex == 0)
+ r = NS_NOTFOUND;
+ else
+ r = NS_SUCCESS;
+ }
+ break;
+ } else {
+ for (hpi = 0; hp[hpi]; hpi++)
+ sl_add(sl, hp[hpi]);
+ free(hp);
+ }
+ }
+ hesiod_end(context);
+ return (r);
+}
+#endif /* HESIOD */
+
+#ifdef YP
+static int _nis_initshells __P((void *, void *, va_list));
+
+/*ARGSUSED*/
+static int
+_nis_initshells(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+ static char *ypdomain;
+
+ if (sl)
+ sl_free(sl, 1);
+ sl = sl_init();
+
+ if (ypdomain == NULL) {
+ switch (yp_get_default_domain(&ypdomain)) {
+ case 0:
+ break;
+ case YPERR_RESRC:
+ return NS_TRYAGAIN;
+ default:
+ return NS_UNAVAIL;
+ }
+ }
+
+ for (;;) {
+ char *ypcur = NULL;
+ int ypcurlen = 0; /* XXX: GCC */
+ char *key, *data;
+ int keylen, datalen;
+ int r;
+
+ key = data = NULL;
+ if (ypcur) {
+ r = yp_next(ypdomain, "shells", ypcur, ypcurlen,
+ &key, &keylen, &data, &datalen);
+ free(ypcur);
+ switch (r) {
+ case 0:
+ break;
+ case YPERR_NOMORE:
+ free(key);
+ free(data);
+ return NS_SUCCESS;
+ default:
+ free(key);
+ free(data);
+ return NS_UNAVAIL;
+ }
+ ypcur = key;
+ ypcurlen = keylen;
+ } else {
+ if (yp_first(ypdomain, "shells", &ypcur,
+ &ypcurlen, &data, &datalen)) {
+ free(data);
+ return NS_UNAVAIL;
+ }
+ }
+ data[datalen] = '\0'; /* clear trailing \n */
+ sl_add(sl, data);
+ }
+}
+#endif /* YP */
+
+static const char *const *
+initshells()
+{
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_local_initshells, NULL)
+ NS_DNS_CB(_dns_initshells, NULL)
+ NS_NIS_CB(_nis_initshells, NULL)
+ { 0 }
+ };
+ if (sl)
+ sl_free(sl, 1);
+ sl = sl_init();
+
+ if (nsdispatch(NULL, dtab, NSDB_SHELLS, "initshells", __nsdefaultsrc)
+ != NS_SUCCESS) {
+ if (sl)
+ sl_free(sl, 1);
+ sl = NULL;
+ return (okshells);
+ }
+ sl_add(sl, NULL);
+
+ return (const char *const *)(sl->sl_str);
}
diff --git a/lib/libc/gen/pw_scan.c b/lib/libc/gen/pw_scan.c
index d0fb5f1..3ecb9e0 100644
--- a/lib/libc/gen/pw_scan.c
+++ b/lib/libc/gen/pw_scan.c
@@ -66,12 +66,10 @@ static const char rcsid[] =
* it will be set based on the existance of PW_SCAN_BIG_IDS in the
* environment.
*/
-int pw_big_ids_warning = -1;
+static int pw_big_ids_warning = -1;
int
-pw_scan(bp, pw)
- char *bp;
- struct passwd *pw;
+__pw_scan(char *bp, struct passwd *pw, int flags)
{
uid_t id;
int root;
@@ -97,20 +95,23 @@ pw_scan(bp, pw)
pw->pw_fields |= _PWF_UID;
else {
if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') {
- warnx("no uid for user %s", pw->pw_name);
+ if (flags & _PWSCAN_WARN)
+ warnx("no uid for user %s", pw->pw_name);
return (0);
}
}
id = strtoul(p, (char **)NULL, 10);
if (errno == ERANGE) {
- warnx("%s > max uid value (%u)", p, ULONG_MAX);
+ if (flags & _PWSCAN_WARN)
+ warnx("%s > max uid value (%u)", p, ULONG_MAX);
return (0);
}
if (root && id) {
- warnx("root uid should be 0");
+ if (flags & _PWSCAN_WARN)
+ warnx("root uid should be 0");
return (0);
}
- if (pw_big_ids_warning && id > USHRT_MAX) {
+ if (flags & _PWSCAN_WARN && pw_big_ids_warning && id > USHRT_MAX) {
warnx("%s > recommended max uid value (%u)", p, USHRT_MAX);
/*return (0);*/ /* THIS SHOULD NOT BE FATAL! */
}
@@ -121,28 +122,30 @@ pw_scan(bp, pw)
if(p[0]) pw->pw_fields |= _PWF_GID;
id = strtoul(p, (char **)NULL, 10);
if (errno == ERANGE) {
- warnx("%s > max gid value (%u)", p, ULONG_MAX);
+ if (flags & _PWSCAN_WARN)
+ warnx("%s > max gid value (%u)", p, ULONG_MAX);
return (0);
}
- if (pw_big_ids_warning && id > USHRT_MAX) {
+ if (flags & _PWSCAN_WARN && pw_big_ids_warning && id > USHRT_MAX) {
warnx("%s > recommended max gid value (%u)", p, USHRT_MAX);
/* return (0); This should not be fatal! */
}
pw->pw_gid = id;
- pw->pw_class = strsep(&bp, ":"); /* class */
- if(pw->pw_class[0]) pw->pw_fields |= _PWF_CLASS;
-
- if (!(p = strsep(&bp, ":"))) /* change */
- goto fmt;
- if(p[0]) pw->pw_fields |= _PWF_CHANGE;
- pw->pw_change = atol(p);
-
- if (!(p = strsep(&bp, ":"))) /* expire */
- goto fmt;
- if(p[0]) pw->pw_fields |= _PWF_EXPIRE;
- pw->pw_expire = atol(p);
-
+ if (flags & _PWSCAN_MASTER ) {
+ pw->pw_class = strsep(&bp, ":"); /* class */
+ if(pw->pw_class[0]) pw->pw_fields |= _PWF_CLASS;
+
+ if (!(p = strsep(&bp, ":"))) /* change */
+ goto fmt;
+ if(p[0]) pw->pw_fields |= _PWF_CHANGE;
+ pw->pw_change = atol(p);
+
+ if (!(p = strsep(&bp, ":"))) /* expire */
+ goto fmt;
+ if(p[0]) pw->pw_fields |= _PWF_EXPIRE;
+ pw->pw_expire = atol(p);
+ }
if (!(pw->pw_gecos = strsep(&bp, ":"))) /* gecos */
goto fmt;
if(pw->pw_gecos[0]) pw->pw_fields |= _PWF_GECOS;
@@ -158,7 +161,8 @@ pw_scan(bp, pw)
if (root && *p) /* empty == /bin/sh */
for (setusershell();;) {
if (!(sh = getusershell())) {
- warnx("warning, unknown root shell");
+ if (flags & _PWSCAN_WARN)
+ warnx("warning, unknown root shell");
break;
}
if (!strcmp(p, sh))
@@ -167,7 +171,9 @@ pw_scan(bp, pw)
if(p[0]) pw->pw_fields |= _PWF_SHELL;
if ((p = strsep(&bp, ":"))) { /* too many */
-fmt: warnx("corrupted entry");
+fmt:
+ if (flags & _PWSCAN_WARN)
+ warnx("corrupted entry");
return (0);
}
return (1);
diff --git a/lib/libc/gen/pw_scan.h b/lib/libc/gen/pw_scan.h
index 2519bd4..3bc6201 100644
--- a/lib/libc/gen/pw_scan.h
+++ b/lib/libc/gen/pw_scan.h
@@ -35,6 +35,7 @@
* $FreeBSD$
*/
-extern int pw_big_ids_warning;
+#define _PWSCAN_MASTER 0x01
+#define _PWSCAN_WARN 0x02
-extern int pw_scan __P((char *, struct passwd *));
+extern int __pw_scan __P((char *, struct passwd *, int));
diff --git a/lib/libc/net/Makefile.inc b/lib/libc/net/Makefile.inc
index 1d3ab66..3f84d10 100644
--- a/lib/libc/net/Makefile.inc
+++ b/lib/libc/net/Makefile.inc
@@ -9,19 +9,32 @@ SRCS+= addr2ascii.c ascii2addr.c base64.c ether_addr.c getaddrinfo.c \
getifaddrs.c getnameinfo.c \
getnetbydns.c getnetbyht.c getnetbynis.c getnetnamadr.c \
getproto.c getprotoent.c getprotoname.c getservbyname.c \
- getservbyport.c getservent.c herror.c inet_addr.c ifname.c \
- inet_lnaof.c \
+ getservbyport.c getservent.c herror.c hesiod.c inet_addr.c \
+ ifname.c inet_lnaof.c \
inet_makeaddr.c inet_net_ntop.c inet_net_pton.c inet_neta.c \
inet_netof.c inet_network.c inet_ntoa.c inet_ntop.c \
inet_pton.c ip6opt.c linkaddr.c map_v4v6.c name6.c ns_addr.c \
ns_name.c ns_netint.c \
- ns_ntoa.c ns_parse.c ns_print.c ns_ttl.c nsap_addr.c \
- rcmd.c recv.c res_comp.c res_data.c res_debug.c \
+ ns_ntoa.c ns_parse.c ns_print.c ns_ttl.c \
+ nsdispatch.c nslexer.c nsparser.c \
+ nsap_addr.c rcmd.c recv.c res_comp.c res_data.c res_debug.c \
res_init.c res_mkquery.c res_mkupdate.c res_query.c res_send.c \
res_update.c rthdr.c send.c vars.c
# not supported: iso_addr.c
-CFLAGS+=-DINET6
+CFLAGS+=-DINET6 -I${.OBJDIR}
+
+YFLAGS+=-p_nsyy
+LFLAGS+=-P_nsyy
+
+CLEANFILES+=nsparser.c nslexer.c nsparser.h
+
+nsparser.h: nsparser.c
+ mv y.tab.h ${.TARGET}
+
+nslexer.c: nslexer.l nsparser.h
+ ${LEX} ${LFLAGS} -o/dev/stdout ${.IMPSRC} | \
+ sed -e '/YY_BUF_SIZE/s/16384/1024/' >${.TARGET}
# machine-dependent net sources
.include "${.CURDIR}/../libc/${MACHINE_ARCH}/net/Makefile.inc"
@@ -29,9 +42,10 @@ CFLAGS+=-DINET6
.if ${LIB} == "c"
MAN3+= addr2ascii.3 byteorder.3 ethers.3 getaddrinfo.3 gethostbyname.3 \
getifaddrs.3 getipnodebyname.3 \
- getnameinfo.3 getnetent.3 getprotoent.3 getservent.3 if_indextoname.3 \
+ getnameinfo.3 getnetent.3 getprotoent.3 getservent.3 hesiod.3 \
+ if_indextoname.3 \
inet.3 inet6_option_space.3 inet6_rthdr_space.3 linkaddr.3 \
- rcmd.3 resolver.3
+ nsdispatch.3 rcmd.3 resolver.3
# not installed: iso_addr.3 ns.3
MLINKS+=addr2ascii.3 ascii2addr.3
diff --git a/lib/libc/net/getaddrinfo.3 b/lib/libc/net/getaddrinfo.3
index 1a0b5f4..deb575f 100644
--- a/lib/libc/net/getaddrinfo.3
+++ b/lib/libc/net/getaddrinfo.3
@@ -496,9 +496,9 @@ freeaddrinfo(res0);
.Ed
.\"
.Sh FILES
-.Bl -tag -width /etc/resolv.conf -compact
+.Bl -tag -width /etc/nsswitch.conf -compact
.It Pa /etc/hosts
-.It Pa /etc/host.conf
+.It Pa /etc/nsswitch.conf
.It Pa /etc/resolv.conf
.El
.\"
diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c
index 6d23544..10ddd3a 100644
--- a/lib/libc/net/getaddrinfo.c
+++ b/lib/libc/net/getaddrinfo.c
@@ -1,4 +1,4 @@
-/* $FreeBSD$ */
+/* $FreeBSD$ */
/* $KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $ */
/*
@@ -103,14 +103,18 @@
#include <stdio.h>
#include <errno.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <nsswitch.h>
+
#if defined(__KAME__) && defined(INET6)
# define FAITH
#endif
-#define SUCCESS 0
-#define ANY 0
-#define YES 1
-#define NO 0
+#define SUCCESS 0
+#define ANY 0
+#define YES 1
+#define NO 0
static const char in_addrany[] = { 0, 0, 0, 0 };
static const char in6_addrany[] = {
@@ -127,7 +131,7 @@ static const struct afd {
int a_socklen;
int a_off;
const char *a_addrany;
- const char *a_loopback;
+ const char *a_loopback;
int a_scoped;
} afdl [] = {
#ifdef INET6
@@ -153,9 +157,9 @@ struct explore {
int e_protocol;
const char *e_protostr;
int e_wild;
-#define WILD_AF(ex) ((ex)->e_wild & 0x01)
-#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
-#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
+#define WILD_AF(ex) ((ex)->e_wild & 0x01)
+#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
+#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
};
static const struct explore explore[] = {
@@ -177,11 +181,17 @@ static const struct explore explore[] = {
};
#ifdef INET6
-#define PTON_MAX 16
+#define PTON_MAX 16
#else
-#define PTON_MAX 4
+#define PTON_MAX 4
#endif
+static const ns_src default_dns_files[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NSSRC_DNS, NS_SUCCESS },
+ { 0 }
+};
+
#if PACKETSZ > 1024
#define MAXPACKET PACKETSZ
#else
@@ -223,24 +233,22 @@ static int addrconfig __P((struct addrinfo *));
static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *));
#endif
-static struct addrinfo *getanswer __P((const querybuf *, int, const char *,
- int, const struct addrinfo *));
-static int _dns_getaddrinfo __P((const struct addrinfo *, const char *,
- struct addrinfo **));
-static struct addrinfo *_gethtent __P((FILE *fp, const char *,
- const struct addrinfo *));
-static int _files_getaddrinfo __P((const struct addrinfo *, const char *,
- struct addrinfo **));
+static struct addrinfo *getanswer __P((const querybuf *, int, const char *, int,
+ const struct addrinfo *));
+static int _dns_getaddrinfo __P((void *, void *, va_list));
+static void _sethtent __P((void));
+static void _endhtent __P((void));
+static struct addrinfo *_gethtent __P((const char *, const struct addrinfo *));
+static int _files_getaddrinfo __P((void *, void *, va_list));
#ifdef YP
-static int _nis_getaddrinfo __P((const struct addrinfo *, const char *,
- struct addrinfo **));
+static struct addrinfo *_yphostent __P((char *, const struct addrinfo *));
+static int _yp_getaddrinfo __P((void *, void *, va_list));
#endif
static int res_queryN __P((const char *, struct res_target *));
static int res_searchN __P((const char *, struct res_target *));
static int res_querydomainN __P((const char *, const char *,
- struct res_target *));
-
+ struct res_target *));
static char *ai_errlist[] = {
"Success",
@@ -263,35 +271,9 @@ static char *ai_errlist[] = {
"Unknown error", /* EAI_MAX */
};
-/*
- * Select order host function.
- */
-#define MAXHOSTCONF 4
-
-#ifndef HOSTCONF
-# define HOSTCONF "/etc/host.conf"
-#endif /* !HOSTCONF */
-
-struct _hostconf {
- int (*byname)(const struct addrinfo *, const char *,
- struct addrinfo **);
-};
-
-/* default order */
-static struct _hostconf _hostconf[MAXHOSTCONF] = {
- _dns_getaddrinfo,
- _files_getaddrinfo,
-#ifdef ICMPNL
- NULL,
-#endif /* ICMPNL */
-};
-
-static int _hostconf_init_done;
-static void _hostconf_init(void);
-
/* XXX macros that make external reference is BAD. */
-#define GET_AI(ai, afd, addr) \
+#define GET_AI(ai, afd, addr) \
do { \
/* external reference: pai, error, and label free */ \
(ai) = get_ai(pai, (afd), (addr)); \
@@ -301,7 +283,7 @@ do { \
} \
} while (/*CONSTCOND*/0)
-#define GET_PORT(ai, serv) \
+#define GET_PORT(ai, serv) \
do { \
/* external reference: error and label free */ \
error = get_port((ai), (serv), 0); \
@@ -309,7 +291,7 @@ do { \
goto free; \
} while (/*CONSTCOND*/0)
-#define GET_CANONNAME(ai, str) \
+#define GET_CANONNAME(ai, str) \
do { \
/* external reference: pai, error and label free */ \
error = get_canonname(pai, (ai), (str)); \
@@ -317,7 +299,7 @@ do { \
goto free; \
} while (/*CONSTCOND*/0)
-#define ERR(err) \
+#define ERR(err) \
do { \
/* external reference: error, and label bad */ \
error = (err); \
@@ -325,9 +307,9 @@ do { \
/*NOTREACHED*/ \
} while (/*CONSTCOND*/0)
-#define MATCH_FAMILY(x, y, w) \
+#define MATCH_FAMILY(x, y, w) \
((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
-#define MATCH(x, y, w) \
+#define MATCH(x, y, w) \
((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
char *
@@ -470,7 +452,7 @@ getaddrinfo(hostname, servname, hints, res)
*/
if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
#ifdef PF_INET6
- || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
+ || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
#endif
) {
ai0 = *pai; /* backup *pai */
@@ -501,11 +483,9 @@ getaddrinfo(hostname, servname, hints, res)
if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
continue;
- if (!MATCH(pai->ai_socktype, ex->e_socktype,
- WILD_SOCKTYPE(ex)))
+ if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
continue;
- if (!MATCH(pai->ai_protocol, ex->e_protocol,
- WILD_PROTOCOL(ex)))
+ if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
continue;
if (pai->ai_family == PF_UNSPEC)
@@ -518,8 +498,7 @@ getaddrinfo(hostname, servname, hints, res)
if (hostname == NULL)
error = explore_null(pai, servname, &cur->ai_next);
else
- error = explore_numeric_scope(pai, hostname, servname,
- &cur->ai_next);
+ error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next);
if (error)
goto free;
@@ -561,11 +540,11 @@ getaddrinfo(hostname, servname, hints, res)
continue;
if (!MATCH(pai->ai_socktype, ex->e_socktype,
- WILD_SOCKTYPE(ex))) {
+ WILD_SOCKTYPE(ex))) {
continue;
}
if (!MATCH(pai->ai_protocol, ex->e_protocol,
- WILD_PROTOCOL(ex))) {
+ WILD_PROTOCOL(ex))) {
continue;
}
@@ -574,7 +553,8 @@ getaddrinfo(hostname, servname, hints, res)
if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
pai->ai_protocol = ex->e_protocol;
- error = explore_fqdn(pai, hostname, servname, &cur->ai_next);
+ error = explore_fqdn(pai, hostname, servname,
+ &cur->ai_next);
while (cur && cur->ai_next)
cur = cur->ai_next;
@@ -602,82 +582,6 @@ getaddrinfo(hostname, servname, hints, res)
return error;
}
-static char *
-_hgetword(char **pp)
-{
- char c, *p, *ret;
- const char *sp;
- static const char sep[] = "# \t\n";
-
- ret = NULL;
- for (p = *pp; (c = *p) != '\0'; p++) {
- for (sp = sep; *sp != '\0'; sp++) {
- if (c == *sp)
- break;
- }
- if (c == '#')
- p[1] = '\0'; /* ignore rest of line */
- if (ret == NULL) {
- if (*sp == '\0')
- ret = p;
- } else {
- if (*sp != '\0') {
- *p++ = '\0';
- break;
- }
- }
- }
- *pp = p;
- if (ret == NULL || *ret == '\0')
- return NULL;
- return ret;
-}
-
-/*
- * Initialize hostconf structure.
- */
-
-static void
-_hostconf_init(void)
-{
- FILE *fp;
- int n;
- char *p, *line;
- char buf[BUFSIZ];
-
- _hostconf_init_done = 1;
- n = 0;
- p = HOSTCONF;
- if ((fp = fopen(p, "r")) == NULL)
- return;
- while (n < MAXHOSTCONF && fgets(buf, sizeof(buf), fp)) {
- line = buf;
- if ((p = _hgetword(&line)) == NULL)
- continue;
- do {
- if (strcmp(p, "hosts") == 0
- || strcmp(p, "local") == 0
- || strcmp(p, "file") == 0
- || strcmp(p, "files") == 0)
- _hostconf[n++].byname = _files_getaddrinfo;
- else if (strcmp(p, "dns") == 0
- || strcmp(p, "bind") == 0)
- _hostconf[n++].byname = _dns_getaddrinfo;
-#ifdef YP
- else if (strcmp(p, "nis") == 0)
- _hostconf[n++].byname = _nis_getaddrinfo;
-#endif
- } while ((p = _hgetword(&line)) != NULL);
- }
- fclose(fp);
- if (n < 0) {
- /* no keyword found. do not change default configuration */
- return;
- }
- for (; n < MAXHOSTCONF; n++)
- _hostconf[n].byname = NULL;
-}
-
/*
* FQDN hostname, DNS lookup
*/
@@ -690,10 +594,15 @@ explore_fqdn(pai, hostname, servname, res)
{
struct addrinfo *result;
struct addrinfo *cur;
- int error = 0, i;
+ int error = 0;
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_files_getaddrinfo, NULL)
+ { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */
+ NS_NIS_CB(_yp_getaddrinfo, NULL)
+ { 0 }
+ };
result = NULL;
- *res = NULL;
/*
* if the servname does not match socktype/protocol, ignore it.
@@ -701,23 +610,30 @@ explore_fqdn(pai, hostname, servname, res)
if (get_portmatch(pai, servname) != 0)
return 0;
- if (!_hostconf_init_done)
- _hostconf_init();
-
- for (i = 0; i < MAXHOSTCONF; i++) {
- if (!_hostconf[i].byname)
- continue;
- error = (*_hostconf[i].byname)(pai, hostname, &result);
- if (error != 0)
- continue;
+ switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
+ default_dns_files, hostname, pai)) {
+ case NS_TRYAGAIN:
+ error = EAI_AGAIN;
+ goto free;
+ case NS_UNAVAIL:
+ error = EAI_FAIL;
+ goto free;
+ case NS_NOTFOUND:
+ error = EAI_NODATA;
+ goto free;
+ case NS_SUCCESS:
+ error = 0;
for (cur = result; cur; cur = cur->ai_next) {
GET_PORT(cur, servname);
/* canonname should be filled already */
}
- *res = result;
- return 0;
+ break;
}
+ *res = result;
+
+ return 0;
+
free:
if (result)
freeaddrinfo(result);
@@ -887,6 +803,7 @@ explore_numeric_scope(pai, hostname, servname, res)
afd = find_afd(pai->ai_family);
if (afd == NULL)
return 0;
+
if (!afd->a_scoped)
return explore_numeric(pai, hostname, servname, res);
@@ -1003,14 +920,13 @@ get_ai(pai, afd, addr)
ai->ai_addr->sa_len = afd->a_socklen;
ai->ai_addrlen = afd->a_socklen;
ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
- p = (char *)(ai->ai_addr);
+ p = (char *)(void *)(ai->ai_addr);
#ifdef FAITH
if (translate == 1)
- memcpy(p + afd->a_off, &faith_prefix, afd->a_addrlen);
+ memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen);
else
#endif
- memcpy(p + afd->a_off, addr, afd->a_addrlen);
-
+ memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
return ai;
}
@@ -1152,7 +1068,6 @@ addrconfig(pai)
else
_close(s);
}
-
}
if (af != AF_UNSPEC) {
if ((s = socket(af, SOCK_DGRAM, 0)) < 0)
@@ -1212,6 +1127,7 @@ ip6_str2scopeid(scope, sin6)
static const char AskedForGot[] =
"gethostby*.getanswer: asked for \"%s\", got \"%s\"";
#endif
+static FILE *hostf = NULL;
static struct addrinfo *
getanswer(answer, anslen, qname, qtype, pai)
@@ -1415,17 +1331,21 @@ getanswer(answer, anslen, qname, qtype, pai)
/*ARGSUSED*/
static int
-_dns_getaddrinfo(pai, hostname, res)
- const struct addrinfo *pai;
- const char *hostname;
- struct addrinfo **res;
+_dns_getaddrinfo(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
{
struct addrinfo *ai;
querybuf buf, buf2;
const char *name;
+ const struct addrinfo *pai;
struct addrinfo sentinel, *cur;
struct res_target q, q2;
+ name = va_arg(ap, char *);
+ pai = va_arg(ap, const struct addrinfo *);
+
memset(&q, 0, sizeof(q2));
memset(&q2, 0, sizeof(q2));
memset(&sentinel, 0, sizeof(sentinel));
@@ -1457,10 +1377,10 @@ _dns_getaddrinfo(pai, hostname, res)
q.anslen = sizeof(buf);
break;
default:
- return EAI_FAIL;
+ return NS_UNAVAIL;
}
- if (res_searchN(hostname, &q) < 0)
- return EAI_NODATA;
+ if (res_searchN(name, &q) < 0)
+ return NS_NOTFOUND;
ai = getanswer(&buf, q.n, q.name, q.qtype, pai);
if (ai) {
cur->ai_next = ai;
@@ -1475,19 +1395,36 @@ _dns_getaddrinfo(pai, hostname, res)
if (sentinel.ai_next == NULL)
switch (h_errno) {
case HOST_NOT_FOUND:
- return EAI_NODATA;
+ return NS_NOTFOUND;
case TRY_AGAIN:
- return EAI_AGAIN;
+ return NS_TRYAGAIN;
default:
- return EAI_FAIL;
+ return NS_UNAVAIL;
}
- *res = sentinel.ai_next;
- return 0;
+ *((struct addrinfo **)rv) = sentinel.ai_next;
+ return NS_SUCCESS;
+}
+
+static void
+_sethtent()
+{
+ if (!hostf)
+ hostf = fopen(_PATH_HOSTS, "r" );
+ else
+ rewind(hostf);
+}
+
+static void
+_endhtent()
+{
+ if (hostf) {
+ (void) fclose(hostf);
+ hostf = NULL;
+ }
}
static struct addrinfo *
-_gethtent(hostf, name, pai)
- FILE *hostf;
+_gethtent(name, pai)
const char *name;
const struct addrinfo *pai;
{
@@ -1498,6 +1435,8 @@ _gethtent(hostf, name, pai)
const char *addr;
char hostbuf[8*1024];
+ if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" )))
+ return (NULL);
again:
if (!(p = fgets(hostbuf, sizeof hostbuf, hostf)))
return (NULL);
@@ -1557,102 +1496,181 @@ found:
/*ARGSUSED*/
static int
-_files_getaddrinfo(pai, hostname, res)
- const struct addrinfo *pai;
- const char *hostname;
- struct addrinfo **res;
+_files_getaddrinfo(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
{
- FILE *hostf;
+ const char *name;
+ const struct addrinfo *pai;
struct addrinfo sentinel, *cur;
struct addrinfo *p;
- sentinel.ai_next = NULL;
+ name = va_arg(ap, char *);
+ pai = va_arg(ap, struct addrinfo *);
+
+ memset(&sentinel, 0, sizeof(sentinel));
cur = &sentinel;
- if ((hostf = fopen(_PATH_HOSTS, "r")) == NULL)
- return EAI_FAIL;
- while ((p = _gethtent(hostf, hostname, pai)) != NULL) {
+ _sethtent();
+ while ((p = _gethtent(name, pai)) != NULL) {
cur->ai_next = p;
while (cur && cur->ai_next)
cur = cur->ai_next;
}
- fclose(hostf);
+ _endhtent();
- if (!sentinel.ai_next)
- return EAI_NODATA;
-
- *res = sentinel.ai_next;
- return 0;
+ *((struct addrinfo **)rv) = sentinel.ai_next;
+ if (sentinel.ai_next == NULL)
+ return NS_NOTFOUND;
+ return NS_SUCCESS;
}
#ifdef YP
+static char *__ypdomain;
+
/*ARGSUSED*/
-static int
-_nis_getaddrinfo(pai, hostname, res)
+static struct addrinfo *
+_yphostent(line, pai)
+ char *line;
const struct addrinfo *pai;
- const char *hostname;
- struct addrinfo **res;
{
- struct hostent *hp;
- int h_error;
- int af;
struct addrinfo sentinel, *cur;
- int i;
- const struct afd *afd;
+ struct addrinfo hints, *res, *res0;
int error;
+ char *p = line;
+ const char *addr, *canonname;
+ char *nextline;
+ char *cp;
- sentinel.ai_next = NULL;
+ addr = canonname = NULL;
+
+ memset(&sentinel, 0, sizeof(sentinel));
cur = &sentinel;
- af = (pai->ai_family == AF_UNSPEC) ? AF_INET : pai->ai_family;
- if (af != AF_INET)
- return (EAI_ADDRFAMILY);
+nextline:
+ /* terminate line */
+ cp = strchr(p, '\n');
+ if (cp) {
+ *cp++ = '\0';
+ nextline = cp;
+ } else
+ nextline = NULL;
- if ((hp = _gethostbynisname(hostname, af)) == NULL) {
- switch (errno) {
- /* XXX: should be filled in */
- default:
- error = EAI_FAIL;
- break;
- }
- } else if (hp->h_name == NULL ||
- hp->h_name[0] == 0 || hp->h_addr_list[0] == NULL) {
- hp = NULL;
- error = EAI_FAIL;
+ cp = strpbrk(p, " \t");
+ if (cp == NULL) {
+ if (canonname == NULL)
+ return (NULL);
+ else
+ goto done;
}
+ *cp++ = '\0';
- if (hp == NULL)
- return error;
+ addr = p;
- for (i = 0; hp->h_addr_list[i] != NULL; i++) {
- if (hp->h_addrtype != af)
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
continue;
+ }
+ if (!canonname)
+ canonname = cp;
+ if ((cp = strpbrk(cp, " \t")) != NULL)
+ *cp++ = '\0';
+ }
- afd = find_afd(hp->h_addrtype);
- if (afd == NULL)
- continue;
+ hints = *pai;
+ hints.ai_flags = AI_NUMERICHOST;
+ error = getaddrinfo(addr, NULL, &hints, &res0);
+ if (error == 0) {
+ for (res = res0; res; res = res->ai_next) {
+ /* cover it up */
+ res->ai_flags = pai->ai_flags;
- GET_AI(cur->ai_next, afd, hp->h_addr_list[i]);
- if ((pai->ai_flags & AI_CANONNAME) != 0) {
- /*
- * RFC2553 says that ai_canonname will be set only for
- * the first element. we do it for all the elements,
- * just for convenience.
- */
- GET_CANONNAME(cur->ai_next, hp->h_name);
+ if (pai->ai_flags & AI_CANONNAME)
+ (void)get_canonname(pai, res, canonname);
}
-
+ } else
+ res0 = NULL;
+ if (res0) {
+ cur->ai_next = res0;
while (cur && cur->ai_next)
cur = cur->ai_next;
}
- *res = sentinel.ai_next;
- return 0;
+ if (nextline) {
+ p = nextline;
+ goto nextline;
+ }
-free:
- if (sentinel.ai_next)
- freeaddrinfo(sentinel.ai_next);
- return error;
+done:
+ return sentinel.ai_next;
+}
+
+/*ARGSUSED*/
+static int
+_yp_getaddrinfo(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+ struct addrinfo sentinel, *cur;
+ struct addrinfo *ai = NULL;
+ static char *__ypcurrent;
+ int __ypcurrentlen, r;
+ const char *name;
+ const struct addrinfo *pai;
+
+ name = va_arg(ap, char *);
+ pai = va_arg(ap, const struct addrinfo *);
+
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+
+ if (!__ypdomain) {
+ if (_yp_check(&__ypdomain) == 0)
+ return NS_UNAVAIL;
+ }
+ if (__ypcurrent)
+ free(__ypcurrent);
+ __ypcurrent = NULL;
+
+ /* hosts.byname is only for IPv4 (Solaris8) */
+ if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) {
+ r = yp_match(__ypdomain, "hosts.byname", name,
+ (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
+ if (r == 0) {
+ struct addrinfo ai4;
+
+ ai4 = *pai;
+ ai4.ai_family = AF_INET;
+ ai = _yphostent(__ypcurrent, &ai4);
+ if (ai) {
+ cur->ai_next = ai;
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+ }
+ }
+
+ /* ipnodes.byname can hold both IPv4/v6 */
+ r = yp_match(__ypdomain, "ipnodes.byname", name,
+ (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
+ if (r == 0) {
+ ai = _yphostent(__ypcurrent, pai);
+ if (ai) {
+ cur->ai_next = ai;
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+ }
+
+ if (sentinel.ai_next == NULL) {
+ h_errno = HOST_NOT_FOUND;
+ return NS_NOTFOUND;
+ }
+ *((struct addrinfo **)rv) = sentinel.ai_next;
+ return NS_SUCCESS;
}
#endif
diff --git a/lib/libc/net/gethostbydns.c b/lib/libc/net/gethostbydns.c
index a5a3e7b..4a56655 100644
--- a/lib/libc/net/gethostbydns.c
+++ b/lib/libc/net/gethostbydns.c
@@ -74,6 +74,8 @@ static char rcsid[] = "$FreeBSD$";
#include <ctype.h>
#include <errno.h>
#include <syslog.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#include "res_config.h"
@@ -474,19 +476,23 @@ __dns_getanswer(answer, anslen, qname, qtype)
return(gethostanswer((const querybuf *)answer, anslen, qname, qtype));
}
-struct hostent *
-_gethostbydnsname(name, af)
+int
+_dns_gethostbyname(void *rval, void *cb_data, va_list ap)
+{
const char *name;
int af;
-{
querybuf buf;
register const char *cp;
char *bp;
int n, size, type, len;
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+ *(struct hostent **)rval = NULL;
+
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
h_errno = NETDB_INTERNAL;
- return (NULL);
+ return NS_UNAVAIL;
}
switch (af) {
@@ -501,7 +507,7 @@ _gethostbydnsname(name, af)
default:
h_errno = NETDB_INTERNAL;
errno = EAFNOSUPPORT;
- return (NULL);
+ return NS_UNAVAIL;
}
host.h_addrtype = af;
@@ -531,7 +537,7 @@ _gethostbydnsname(name, af)
*/
if (inet_pton(af, name, host_addr) <= 0) {
h_errno = HOST_NOT_FOUND;
- return (NULL);
+ return NS_NOTFOUND;
}
strncpy(hostbuf, name, MAXDNAME);
hostbuf[MAXDNAME] = '\0';
@@ -546,7 +552,8 @@ _gethostbydnsname(name, af)
if (_res.options & RES_USE_INET6)
_map_v4v6_hostent(&host, &bp, &len);
h_errno = NETDB_SUCCESS;
- return (&host);
+ *(struct hostent **)rval = &host;
+ return NS_SUCCESS;
}
if (!isdigit((unsigned char)*cp) && *cp != '.')
break;
@@ -564,7 +571,7 @@ _gethostbydnsname(name, af)
*/
if (inet_pton(af, name, host_addr) <= 0) {
h_errno = HOST_NOT_FOUND;
- return (NULL);
+ return NS_NOTFOUND;
}
strncpy(hostbuf, name, MAXDNAME);
hostbuf[MAXDNAME] = '\0';
@@ -577,7 +584,8 @@ _gethostbydnsname(name, af)
h_addr_ptrs[1] = NULL;
host.h_addr_list = h_addr_ptrs;
h_errno = NETDB_SUCCESS;
- return (&host);
+ *(struct hostent **)rval = &host;
+ return NS_SUCCESS;
}
if (!isxdigit((unsigned char)*cp) && *cp != ':' && *cp != '.')
break;
@@ -585,17 +593,18 @@ _gethostbydnsname(name, af)
if ((n = res_search(name, C_IN, type, buf.buf, sizeof(buf))) < 0) {
dprintf("res_search failed (%d)\n", n);
- return (NULL);
+ return NS_UNAVAIL;
}
- return (gethostanswer(&buf, n, name, type));
+ *(struct hostent **)rval = gethostanswer(&buf, n, name, type);
+ return (*(struct hostent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
-struct hostent *
-_gethostbydnsaddr(addr, len, af)
+int
+_dns_gethostbyaddr(void *rval, void *cb_data, va_list ap)
+{
const char *addr; /* XXX should have been def'd as u_char! */
int len, af;
-{
- const u_char *uaddr = (const u_char *)addr;
+ const u_char *uaddr;
static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
int n, size;
@@ -608,10 +617,17 @@ _gethostbydnsaddr(addr, len, af)
u_long old_options;
char hname2[MAXDNAME+1];
#endif /*SUNSECURITY*/
+
+ addr = va_arg(ap, const char *);
+ uaddr = (const u_char *)addr;
+ len = va_arg(ap, int);
+ af = va_arg(ap, int);
+
+ *(struct hostent **)rval = NULL;
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
h_errno = NETDB_INTERNAL;
- return (NULL);
+ return NS_UNAVAIL;
}
if (af == AF_INET6 && len == IN6ADDRSZ &&
(!bcmp(uaddr, mapped, sizeof mapped) ||
@@ -632,12 +648,12 @@ _gethostbydnsaddr(addr, len, af)
default:
errno = EAFNOSUPPORT;
h_errno = NETDB_INTERNAL;
- return (NULL);
+ return NS_UNAVAIL;
}
if (size != len) {
errno = EINVAL;
h_errno = NETDB_INTERNAL;
- return (NULL);
+ return NS_UNAVAIL;
}
switch (af) {
case AF_INET:
@@ -662,14 +678,14 @@ _gethostbydnsaddr(addr, len, af)
n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf);
if (n < 0) {
dprintf("res_query failed (%d)\n", n);
- return (NULL);
+ return NS_UNAVAIL;
}
if (n > sizeof buf.buf) {
dprintf("static buffer is too small (%d)\n", n);
- return (NULL);
+ return NS_UNAVAIL;
}
if (!(hp = gethostanswer(&buf, n, qbuf, T_PTR)))
- return (NULL); /* h_errno was set by gethostanswer() */
+ return NS_NOTFOUND; /* h_errno was set by gethostanswer() */
#ifdef SUNSECURITY
if (af == AF_INET) {
/*
@@ -687,7 +703,7 @@ _gethostbydnsaddr(addr, len, af)
hname2, inet_ntoa(*((struct in_addr *)addr)));
_res.options = old_options;
h_errno = HOST_NOT_FOUND;
- return (NULL);
+ return NS_NOTFOUND;
}
_res.options = old_options;
for (haddr = rhp->h_addr_list; *haddr; haddr++)
@@ -698,7 +714,7 @@ _gethostbydnsaddr(addr, len, af)
"gethostbyaddr: A record of %s != PTR record [%s]",
hname2, inet_ntoa(*((struct in_addr *)addr)));
h_errno = HOST_NOT_FOUND;
- return (NULL);
+ return NS_NOTFOUND;
}
}
#endif /*SUNSECURITY*/
@@ -713,7 +729,8 @@ _gethostbydnsaddr(addr, len, af)
hp->h_length = IN6ADDRSZ;
}
h_errno = NETDB_SUCCESS;
- return (hp);
+ *(struct hostent **)rval = hp;
+ return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
#ifdef RESOLVSORT
diff --git a/lib/libc/net/gethostbyht.c b/lib/libc/net/gethostbyht.c
index cd5f0f4..eeecd22 100644
--- a/lib/libc/net/gethostbyht.c
+++ b/lib/libc/net/gethostbyht.c
@@ -65,6 +65,8 @@ static char rcsid[] = "$FreeBSD$";
#include <ctype.h>
#include <errno.h>
#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#include <arpa/nameser.h> /* XXX */
#include <resolv.h> /* XXX */
@@ -163,13 +165,16 @@ gethostent()
return (&host);
}
-struct hostent *
-_gethostbyhtname(name, af)
+int
+_ht_gethostbyname(void *rval, void *cb_data, va_list ap)
+{
const char *name;
int af;
-{
register struct hostent *p;
register char **cp;
+
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
sethostent(0);
while ((p = gethostent()) != NULL) {
@@ -183,20 +188,28 @@ _gethostbyhtname(name, af)
}
found:
endhostent();
- return (p);
+ *(struct hostent **)rval = p;
+
+ return (p != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
-struct hostent *
-_gethostbyhtaddr(addr, len, af)
+int
+_ht_gethostbyaddr(void *rval, void *cb_data, va_list ap)
+{
const char *addr;
int len, af;
-{
register struct hostent *p;
+ addr = va_arg(ap, const char *);
+ len = va_arg(ap, int);
+ af = va_arg(ap, int);
+
sethostent(0);
while ((p = gethostent()) != NULL)
if (p->h_addrtype == af && !bcmp(p->h_addr, addr, len))
break;
endhostent();
- return (p);
+
+ *(struct hostent **)rval = p;
+ return (p != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
diff --git a/lib/libc/net/gethostbyname.3 b/lib/libc/net/gethostbyname.3
index e513d74..0e2006e 100644
--- a/lib/libc/net/gethostbyname.3
+++ b/lib/libc/net/gethostbyname.3
@@ -78,10 +78,15 @@ 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 .
+broken-out fields from a line in
+.Pa /etc/hosts ,
+or database entries supplied by the
+.Xr yp 4
+system.
+The order of the lookups is controlled by the
+.Sq hosts
+entry in
+.Xr nsswitch.conf 5 .
.Bd -literal
struct hostent {
char *h_name; /* official name of host */
@@ -188,9 +193,9 @@ value of the
.Fa err
parameter.
.Sh FILES
-.Bl -tag -width /etc/resolv.conf -compact
+.Bl -tag -width /etc/nsswitch.conf -compact
.It Pa /etc/hosts
-.It Pa /etc/host.conf
+.It Pa /etc/nsswitch.conf
.It Pa /etc/resolv.conf
.El
.Sh DIAGNOSTICS
diff --git a/lib/libc/net/gethostbynis.c b/lib/libc/net/gethostbynis.c
index 82e0b3d..518d512 100644
--- a/lib/libc/net/gethostbynis.c
+++ b/lib/libc/net/gethostbynis.c
@@ -39,6 +39,8 @@ static char rcsid[] = "$FreeBSD$";
#include <ctype.h>
#include <errno.h>
#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#ifdef YP
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
@@ -52,7 +54,6 @@ static char rcsid[] = "$FreeBSD$";
static char *host_aliases[MAXALIASES];
static char hostaddr[MAXADDRS];
static char *host_addrs[2];
-#endif /* YP */
static struct hostent *
_gethostbynis(name, map, af)
@@ -60,7 +61,6 @@ _gethostbynis(name, map, af)
char *map;
int af;
{
-#ifdef YP
register char *cp, **q;
char *result;
int resultlen,size;
@@ -122,24 +122,64 @@ _gethostbynis(name, map, af)
}
*q = NULL;
return (&h);
-#else
- return (NULL);
-#endif /* YP */
}
+#endif /* YP */
+/* XXX _gethostbynisname/_gethostbynisaddr only used by getaddrinfo */
struct hostent *
-_gethostbynisname(name, af)
- const char *name;
- int af;
+_gethostbynisname(const char *name, int af)
{
+#ifdef YP
return _gethostbynis(name, "hosts.byname", af);
+#else
+ return NULL;
+#endif
}
struct hostent *
-_gethostbynisaddr(addr, len, af)
+_gethostbynisaddr(const char *addr, int len, int af)
+{
+#ifdef YP
+ return _gethostbynis(inet_ntoa(*(struct in_addr *)addr),
+ "hosts.byaddr", af);
+#else
+ return NULL;
+#endif
+}
+
+
+int
+_nis_gethostbyname(void *rval, void *cb_data, va_list ap)
+{
+#ifdef YP
+ const char *name;
+ int af;
+
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+
+ *(struct hostent **)rval = _gethostbynis(name, "hosts.byname", af);
+ return (*(struct hostent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
+#else
+ return NS_UNAVAIL;
+#endif
+}
+
+int
+_nis_gethostbyaddr(void *rval, void *cb_data, va_list ap)
+{
+#ifdef YP
const char *addr;
int len;
int af;
-{
- return _gethostbynis(inet_ntoa(*(struct in_addr *)addr),"hosts.byaddr", af);
+
+ addr = va_arg(ap, const char *);
+ len = va_arg(ap, int);
+ af = va_arg(ap, int);
+
+ *(struct hostent **)rval =_gethostbynis(inet_ntoa(*(struct in_addr *)addr),"hosts.byaddr", af);
+ return (*(struct hostent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
+#else
+ return NS_UNAVAIL;
+#endif
}
diff --git a/lib/libc/net/gethostnamadr.c b/lib/libc/net/gethostnamadr.c
index 010e4db..fcfc979 100644
--- a/lib/libc/net/gethostnamadr.c
+++ b/lib/libc/net/gethostnamadr.c
@@ -37,87 +37,25 @@ static char rcsid[] = "$FreeBSD$";
#include <ctype.h>
#include <errno.h>
#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#include <arpa/nameser.h> /* XXX hack for _res */
#include <resolv.h> /* XXX hack for _res */
-#define _PATH_HOSTCONF "/etc/host.conf"
-
-enum service_type {
- SERVICE_NONE = 0,
- SERVICE_BIND,
- SERVICE_HOSTS,
- SERVICE_NIS };
-#define SERVICE_MAX SERVICE_NIS
-
-static struct {
- const char *name;
- enum service_type type;
-} service_names[] = {
- { "hosts", SERVICE_HOSTS },
- { "/etc/hosts", SERVICE_HOSTS },
- { "hosttable", SERVICE_HOSTS },
- { "htable", SERVICE_HOSTS },
- { "bind", SERVICE_BIND },
- { "dns", SERVICE_BIND },
- { "domain", SERVICE_BIND },
- { "yp", SERVICE_NIS },
- { "yellowpages", SERVICE_NIS },
- { "nis", SERVICE_NIS },
- { 0, SERVICE_NONE }
+extern int _ht_gethostbyname(void *, void *, va_list);
+extern int _dns_gethostbyname(void *, void *, va_list);
+extern int _nis_gethostbyname(void *, void *, va_list);
+extern int _ht_gethostbyaddr(void *, void *, va_list);
+extern int _dns_gethostbyaddr(void *, void *, va_list);
+extern int _nis_gethostbyaddr(void *, void *, va_list);
+
+/* Host lookup order if nsswitch.conf is broken or nonexistant */
+static const ns_src default_src[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NSSRC_DNS, NS_SUCCESS },
+ { 0 }
};
-static enum service_type service_order[SERVICE_MAX + 1];
-static int service_done = 0;
-
-static enum service_type
-get_service_name(const char *name) {
- int i;
- for(i = 0; service_names[i].type != SERVICE_NONE; i++) {
- if(!strcasecmp(name, service_names[i].name)) {
- return service_names[i].type;
- }
- }
- return SERVICE_NONE;
-}
-
-static void
-init_services()
-{
- char *cp, *p, buf[BUFSIZ];
- register int cc = 0;
- FILE *fd;
-
- if ((fd = (FILE *)fopen(_PATH_HOSTCONF, "r")) == NULL) {
- /* make some assumptions */
- service_order[0] = SERVICE_BIND;
- service_order[1] = SERVICE_HOSTS;
- service_order[2] = SERVICE_NONE;
- } else {
- while (fgets(buf, BUFSIZ, fd) != NULL && cc < SERVICE_MAX) {
- if(buf[0] == '#')
- continue;
-
- p = buf;
- while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0')
- ;
- if (cp == NULL)
- continue;
- do {
- if (isalpha((unsigned char)cp[0])) {
- service_order[cc] = get_service_name(cp);
- if(service_order[cc] != SERVICE_NONE)
- cc++;
- }
- while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0')
- ;
- } while(cp != NULL && cc < SERVICE_MAX);
- }
- service_order[cc] = SERVICE_NONE;
- fclose(fd);
- }
- service_done = 1;
-}
-
struct hostent *
gethostbyname(const char *name)
{
@@ -135,56 +73,44 @@ struct hostent *
gethostbyname2(const char *name, int type)
{
struct hostent *hp = 0;
- int nserv = 0;
-
- if (!service_done)
- init_services();
-
- while (!hp) {
- switch (service_order[nserv]) {
- case SERVICE_NONE:
- return NULL;
- case SERVICE_HOSTS:
- hp = _gethostbyhtname(name, type);
- break;
- case SERVICE_BIND:
- hp = _gethostbydnsname(name, type);
- break;
- case SERVICE_NIS:
- hp = _gethostbynisname(name, type);
- break;
- }
- nserv++;
- }
- return hp;
+ int rval;
+
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_ht_gethostbyname, NULL)
+ { NSSRC_DNS, _dns_gethostbyname, NULL },
+ NS_NIS_CB(_nis_gethostbyname, NULL) /* force -DHESIOD */
+ { 0 }
+ };
+
+ rval = nsdispatch((void *)&hp, dtab, NSDB_HOSTS, "gethostbyname",
+ default_src, name, type);
+
+ if (rval != NS_SUCCESS)
+ return NULL;
+ else
+ return hp;
}
struct hostent *
gethostbyaddr(const char *addr, int len, int type)
{
struct hostent *hp = 0;
- int nserv = 0;
-
- if (!service_done)
- init_services();
-
- while (!hp) {
- switch (service_order[nserv]) {
- case SERVICE_NONE:
- return 0;
- case SERVICE_HOSTS:
- hp = _gethostbyhtaddr(addr, len, type);
- break;
- case SERVICE_BIND:
- hp = _gethostbydnsaddr(addr, len, type);
- break;
- case SERVICE_NIS:
- hp = _gethostbynisaddr(addr, len, type);
- break;
- }
- nserv++;
- }
- return hp;
+ int rval;
+
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_ht_gethostbyaddr, NULL)
+ { NSSRC_DNS, _dns_gethostbyaddr, NULL },
+ NS_NIS_CB(_nis_gethostbyaddr, NULL) /* force -DHESIOD */
+ { 0 }
+ };
+
+ rval = nsdispatch((void *)&hp, dtab, NSDB_HOSTS, "gethostbyaddr",
+ default_src, addr, len, type);
+
+ if (rval != NS_SUCCESS)
+ return NULL;
+ else
+ return hp;
}
#ifdef _THREAD_SAFE
diff --git a/lib/libc/net/getipnodebyname.3 b/lib/libc/net/getipnodebyname.3
index 618f5a3..5eec582 100644
--- a/lib/libc/net/getipnodebyname.3
+++ b/lib/libc/net/getipnodebyname.3
@@ -405,9 +405,9 @@ or
.Fn getipnodebyaddr .
.\"
.Sh FILES
-.Bl -tag -width /etc/resolv.conf -compact
+.Bl -tag -width /etc/nsswitch.conf -compact
.It Pa /etc/hosts
-.It Pa /etc/host.conf
+.It Pa /etc/nsswitch.conf
.It Pa /etc/resolv.conf
.El
.\"
@@ -429,6 +429,7 @@ The meanings of each error code are described in
.Xr gethostbyname 3 ,
.Xr gethostbyaddr 3 ,
.Xr hosts 5 ,
+.Xr nsswitch.conf 5 ,
.Xr services 5 ,
.Xr hostname 7 ,
.Xr named 8
diff --git a/lib/libc/net/getnameinfo.3 b/lib/libc/net/getnameinfo.3
index 113563f..0289b9f 100644
--- a/lib/libc/net/getnameinfo.3
+++ b/lib/libc/net/getnameinfo.3
@@ -226,9 +226,9 @@ printf("host=%s\\n", hbuf);
.Ed
.\"
.Sh FILES
-.Bl -tag -width /etc/resolv.conf -compact
+.Bl -tag -width /etc/nsswitch.conf -compact
.It Pa /etc/hosts
-.It Pa /etc/host.conf
+.It Pa /etc/nsswitch.conf
.It Pa /etc/resolv.conf
.El
.\"
diff --git a/lib/libc/net/getnetbydns.c b/lib/libc/net/getnetbydns.c
index 65d9d2d..5827103 100644
--- a/lib/libc/net/getnetbydns.c
+++ b/lib/libc/net/getnetbydns.c
@@ -77,6 +77,8 @@ static char rcsid[] = "$FreeBSD$";
#include <string.h>
#include <unistd.h>
#include <syslog.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#include "res_config.h"
@@ -218,11 +220,11 @@ static char *net_aliases[MAXALIASES], netbuf[PACKETSZ];
return (NULL);
}
-struct netent *
-_getnetbydnsaddr(net, net_type)
- register unsigned long net;
- register int net_type;
+int
+_dns_getnetbyaddr(void *rval, void *cb_data, va_list ap)
{
+ unsigned long net;
+ int net_type;
unsigned int netbr[4];
int nn, anslen;
querybuf buf;
@@ -230,8 +232,13 @@ _getnetbydnsaddr(net, net_type)
unsigned long net2;
struct netent *net_entry;
+ net = va_arg(ap, unsigned long);
+ net_type = va_arg(ap, int);
+
+ *(struct netent **)rval = NULL;
+
if (net_type != AF_INET)
- return (NULL);
+ return NS_UNAVAIL;
for (nn = 4, net2 = net; net2; net2 >>= 8)
netbr[--nn] = net2 & 0xff;
@@ -257,7 +264,7 @@ _getnetbydnsaddr(net, net_type)
if (_res.options & RES_DEBUG)
printf("res_query failed\n");
#endif
- return (NULL);
+ return NS_UNAVAIL;
}
net_entry = getnetanswer(&buf, anslen, BYADDR);
if (net_entry) {
@@ -267,22 +274,27 @@ _getnetbydnsaddr(net, net_type)
while ((u_net & 0xff) == 0 && u_net != 0)
u_net >>= 8;
net_entry->n_net = u_net;
- return (net_entry);
+ *(struct netent **)rval = net_entry;
+ return NS_SUCCESS;
}
- return (NULL);
+ return NS_NOTFOUND;
}
-struct netent *
-_getnetbydnsname(net)
- register const char *net;
+int
+_dns_getnetbyname(void *rval, void *cb_data, va_list ap)
{
+ const char *net;
int anslen;
querybuf buf;
char qbuf[MAXDNAME];
+ net = va_arg(ap, const char *);
+
+ *(struct netent**)rval = NULL;
+
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
h_errno = NETDB_INTERNAL;
- return (NULL);
+ return NS_UNAVAIL;
}
strncpy(qbuf, net, sizeof(qbuf) - 1);
qbuf[sizeof(qbuf) - 1] = '\0';
@@ -292,9 +304,10 @@ _getnetbydnsname(net)
if (_res.options & RES_DEBUG)
printf("res_query failed\n");
#endif
- return (NULL);
+ return NS_UNAVAIL;
}
- return getnetanswer(&buf, anslen, BYNAME);
+ *(struct netent**)rval = getnetanswer(&buf, anslen, BYNAME);
+ return (*(struct netent**)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
void
diff --git a/lib/libc/net/getnetbyht.c b/lib/libc/net/getnetbyht.c
index ab164b1..b5f73be 100644
--- a/lib/libc/net/getnetbyht.c
+++ b/lib/libc/net/getnetbyht.c
@@ -55,6 +55,8 @@ static chat rcsid[] = "$FreeBSD$";
#include <netdb.h>
#include <stdio.h>
#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#define MAXALIASES 35
@@ -135,13 +137,15 @@ again:
return (&net);
}
-struct netent *
-_getnetbyhtname(name)
- register const char *name;
+int
+_ht_getnetbyname(void *rval, void *cb_data, va_list ap)
{
+ const char *name;
register struct netent *p;
register char **cp;
+ name = va_arg(ap, const char *);
+
setnetent(_net_stayopen);
while ( (p = getnetent()) ) {
if (strcasecmp(p->n_name, name) == 0)
@@ -153,21 +157,26 @@ _getnetbyhtname(name)
found:
if (!_net_stayopen)
endnetent();
- return (p);
+ *(struct netent **)rval = p;
+ return (p != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
-struct netent *
-_getnetbyhtaddr(net, type)
- register unsigned long net;
- register int type;
+int
+_ht_getnetbyaddr(void *rval, void *cb_data, va_list ap)
{
+ unsigned long net;
+ int type;
register struct netent *p;
+ net = va_arg(ap, unsigned long);
+ type = va_arg(ap, int);
+
setnetent(_net_stayopen);
while ( (p = getnetent()) )
if (p->n_addrtype == type && p->n_net == net)
break;
if (!_net_stayopen)
endnetent();
- return (p);
+ *(struct netent **)rval = p;
+ return (p != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
diff --git a/lib/libc/net/getnetbynis.c b/lib/libc/net/getnetbynis.c
index 0ab7073..d226b01 100644
--- a/lib/libc/net/getnetbynis.c
+++ b/lib/libc/net/getnetbynis.c
@@ -38,6 +38,8 @@ static char rcsid[] = "$FreeBSD$";
#include <ctype.h>
#include <errno.h>
#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#include <arpa/nameser.h>
#ifdef YP
#include <rpc/rpc.h>
@@ -50,15 +52,10 @@ static char rcsid[] = "$FreeBSD$";
#ifdef YP
static char *host_aliases[MAXALIASES];
-#endif /* YP */
static struct netent *
-_getnetbynis(name, map, af)
- const char *name;
- char *map;
- int af;
+_getnetbynis(const char *name, char *map, int af)
{
-#ifdef YP
register char *cp, **q;
static char *result;
int resultlen;
@@ -117,32 +114,45 @@ _getnetbynis(name, map, af)
}
*q = NULL;
return (&h);
-#else
- return (NULL);
-#endif
}
+#endif /* YP */
-struct netent *
-_getnetbynisname(name)
- const char *name;
+int
+_nis_getnetbyname(void *rval, void *cb_data, va_list ap)
{
- return _getnetbynis(name, "networks.byname", AF_INET);
+#ifdef YP
+ const char *name;
+
+ name = va_arg(ap, const char *);
+
+ *(struct netent **)rval = _getnetbynis(name, "networks.byname", AF_INET);
+ return (*(struct netent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
+#else
+ return NS_UNAVAIL;
+#endif
+
}
-struct netent *
-_getnetbynisaddr(addr, af)
+int
+_nis_getnetbyaddr(void *rval, void *cb_data, va_list ap)
+{
+#ifdef YP
unsigned long addr;
int af;
-{
char *str, *cp;
unsigned long net2;
int nn;
unsigned int netbr[4];
char buf[MAXDNAME];
+ addr = va_arg(ap, unsigned long);
+ af = va_arg(ap, int);
+
+ *(struct netent **)rval = NULL;
+
if (af != AF_INET) {
errno = EAFNOSUPPORT;
- return (NULL);
+ return NS_UNAVAIL;
}
for (nn = 4, net2 = addr; net2; net2 >>= 8) {
@@ -173,5 +183,9 @@ _getnetbynisaddr(addr, af)
cp = str + (strlen(str) - 2);
}
- return _getnetbynis(str, "networks.byaddr", af);
+ *(struct netent **)rval = _getnetbynis(str, "networks.byaddr", af);
+ return (*(struct netent**)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
+#else
+ return NS_UNAVAIL;
+#endif /* YP */
}
diff --git a/lib/libc/net/getnetent.3 b/lib/libc/net/getnetent.3
index 086f4c3..de3e9df 100644
--- a/lib/libc/net/getnetent.3
+++ b/lib/libc/net/getnetent.3
@@ -64,10 +64,18 @@ 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 .
+following structure describing an internet network.
+This structure contains either the information obtained
+from the nameserver,
+.Xr named 8 ,
+broken-out fields of a line in the network data base
+.Pa /etc/networks ,
+or entries supplied by the
+.Xr yp 4
+system. The order of the lookups is controlled by the
+`networks' entry in
+.Xr nsswitch.conf 5 .
+.Pp
.Bd -literal -offset indent
struct netent {
char *n_name; /* official name of net */
@@ -129,8 +137,10 @@ must be
.Dv AF_INET .
Network numbers are supplied in host order.
.Sh FILES
-.Bl -tag -width /etc/networks -compact
+.Bl -tag -width /etc/nsswitch.conf -compact
.It Pa /etc/networks
+.It Pa /etc/nsswitch.conf
+.It Pa /etc/resolv.conf
.El
.Sh DIAGNOSTICS
Null pointer
diff --git a/lib/libc/net/getnetnamadr.c b/lib/libc/net/getnetnamadr.c
index cb5871b..6d9dbfa 100644
--- a/lib/libc/net/getnetnamadr.c
+++ b/lib/libc/net/getnetnamadr.c
@@ -36,142 +36,66 @@ static char rcsid[] = "$FreeBSD$";
#include <ctype.h>
#include <errno.h>
#include <string.h>
-
-#ifndef _PATH_NETCONF
-#define _PATH_NETCONF "/etc/host.conf"
-#endif
-
-enum service_type {
- SERVICE_NONE = 0,
- SERVICE_BIND,
- SERVICE_TABLE,
- SERVICE_NIS };
-#define SERVICE_MAX SERVICE_NIS
-
-static struct {
- const char *name;
- enum service_type type;
-} service_names[] = {
- { "hosts", SERVICE_TABLE },
- { "/etc/hosts", SERVICE_TABLE },
- { "hosttable", SERVICE_TABLE },
- { "htable", SERVICE_TABLE },
- { "bind", SERVICE_BIND },
- { "dns", SERVICE_BIND },
- { "domain", SERVICE_BIND },
- { "yp", SERVICE_NIS },
- { "yellowpages", SERVICE_NIS },
- { "nis", SERVICE_NIS },
- { 0, SERVICE_NONE }
+#include <stdarg.h>
+#include <nsswitch.h>
+
+extern int _ht_getnetbyname(void *, void *, va_list);
+extern int _dns_getnetbyname(void *, void *, va_list);
+extern int _nis_getnetbyname(void *, void *, va_list);
+extern int _ht_getnetbyaddr(void *, void *, va_list);
+extern int _dns_getnetbyaddr(void *, void *, va_list);
+extern int _nis_getnetbyaddr(void *, void *, va_list);
+
+/* Network lookup order if nsswitch.conf is broken or nonexistant */
+static const ns_src default_src[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NSSRC_DNS, NS_SUCCESS },
+ { 0 }
};
-static enum service_type service_order[SERVICE_MAX + 1];
-static int service_done = 0;
-
-static enum service_type
-get_service_name(const char *name) {
- int i;
- for(i = 0; service_names[i].type != SERVICE_NONE; i++) {
- if(!strcasecmp(name, service_names[i].name)) {
- return service_names[i].type;
- }
- }
- return SERVICE_NONE;
-}
-
-static void
-init_services()
-{
- char *cp, *p, buf[BUFSIZ];
- register int cc = 0;
- FILE *fd;
-
- if ((fd = (FILE *)fopen(_PATH_NETCONF, "r")) == NULL) {
- /* make some assumptions */
- service_order[0] = SERVICE_TABLE;
- service_order[1] = SERVICE_NONE;
- } else {
- while (fgets(buf, BUFSIZ, fd) != NULL && cc < SERVICE_MAX) {
- if(buf[0] == '#')
- continue;
-
- p = buf;
- while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0')
- ;
- if (cp == NULL)
- continue;
- do {
- if (isalpha((unsigned char)cp[0])) {
- service_order[cc] = get_service_name(cp);
- if(service_order[cc] != SERVICE_NONE)
- cc++;
- }
- while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0')
- ;
- } while(cp != NULL && cc < SERVICE_MAX);
- }
- service_order[cc] = SERVICE_NONE;
- fclose(fd);
- }
- service_done = 1;
-}
-
struct netent *
getnetbyname(const char *name)
{
struct netent *hp = 0;
- int nserv = 0;
-
- if (!service_done)
- init_services();
-
- while (!hp) {
- switch (service_order[nserv]) {
- case SERVICE_NONE:
- return NULL;
- case SERVICE_TABLE:
- hp = _getnetbyhtname(name);
- break;
- case SERVICE_BIND:
- hp = _getnetbydnsname(name);
- break;
- case SERVICE_NIS:
- hp = _getnetbynisname(name);
- break;
- }
- nserv++;
- }
- return hp;
+ int rval;
+
+
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_ht_getnetbyname, NULL)
+ { NSSRC_DNS, _dns_getnetbyname, NULL },
+ NS_NIS_CB(_nis_getnetbyname, NULL) /* force -DHESIOD */
+ { 0 }
+ };
+
+ rval = nsdispatch((void *)&hp, dtab, NSDB_NETWORKS, "getnetbyname",
+ default_src, name);
+
+ if (rval != NS_SUCCESS)
+ return NULL;
+ else
+ return hp;
}
struct netent *
-getnetbyaddr(addr, af)
- u_long addr;
- int af;
+getnetbyaddr(u_long addr, int af)
{
struct netent *hp = 0;
- int nserv = 0;
-
- if (!service_done)
- init_services();
-
- while (!hp) {
- switch (service_order[nserv]) {
- case SERVICE_NONE:
- return 0;
- case SERVICE_TABLE:
- hp = _getnetbyhtaddr(addr, af);
- break;
- case SERVICE_BIND:
- hp = _getnetbydnsaddr(addr, af);
- break;
- case SERVICE_NIS:
- hp = _getnetbynisaddr(addr, af);
- break;
- }
- nserv++;
- }
- return hp;
+ int rval;
+
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_ht_getnetbyaddr, NULL)
+ { NSSRC_DNS, _dns_getnetbyaddr, NULL },
+ NS_NIS_CB(_nis_getnetbyaddr, NULL) /* force -DHESIOD */
+ { 0 }
+ };
+
+ rval = nsdispatch((void *)&hp, dtab, NSDB_HOSTS, "getnetbyaddr",
+ default_src, addr, af);
+
+ if (rval != NS_SUCCESS)
+ return NULL;
+ else
+ return hp;
}
void
diff --git a/lib/libc/net/hesiod.3 b/lib/libc/net/hesiod.3
new file mode 100644
index 0000000..49e7d67
--- /dev/null
+++ b/lib/libc/net/hesiod.3
@@ -0,0 +1,136 @@
+.\" $NetBSD: hesiod.3,v 1.1 1999/01/25 03:43:04 lukem Exp $
+.\" $FreeBSD$
+.\"
+.\" from: #Id: hesiod.3,v 1.9.2.1 1997/01/03 21:02:23 ghudson Exp #
+.\"
+.\" Copyright 1988, 1996 by the Massachusetts Institute of Technology.
+.\"
+.\" Permission to use, copy, modify, and distribute this
+.\" software and its documentation for any purpose and without
+.\" fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright
+.\" notice and this permission notice appear in supporting
+.\" documentation, and that the name of M.I.T. not be used in
+.\" advertising or publicity pertaining to distribution of the
+.\" software without specific, written prior permission.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose. It is provided "as is"
+.\" without express or implied warranty.
+.\"
+.TH HESIOD 3 "30 November 1996"
+.SH NAME
+hesiod, hesiod_init, hesiod_resolve, hesiod_free_list, hesiod_to_bind, hesiod_end \- Hesiod name server interface library
+.SH SYNOPSIS
+.nf
+.B #include <hesiod.h>
+.PP
+.B int hesiod_init(void **\fIcontext\fP)
+.B char **hesiod_resolve(void *\fIcontext\fP, const char *\fIname\fP,
+.B const char *\fItype\fP)
+.B void hesiod_free_list(void *\fIcontext\fP, char **\fIlist\fP);
+.B char *hesiod_to_bind(void *\fIcontext\fP, const char *\fIname\fP,
+.B const char *\fItype\fP)
+.B void hesiod_end(void *\fIcontext\fP)
+.PP
+.B cc file.c -lhesiod
+.fi
+.SH DESCRIPTION
+This family of functions allows you to perform lookups of Hesiod
+information, which is stored as text records in the Domain Name
+Service. To perform lookups, you must first initialize a
+.IR context ,
+an opaque object which stores information used internally by the
+library between calls.
+.I hesiod_init
+initializes a context, storing a pointer to the context in the
+location pointed to by the
+.I context
+argument.
+.I hesiod_end
+frees the resources used by a context.
+.PP
+.I hesiod_resolve
+is the primary interface to the library. If successful, it returns a
+list of one or more strings giving the records matching
+.I name
+and
+.IR type .
+The last element of the list is followed by a NULL pointer. It is the
+caller's responsibility to call
+.I hesiod_free_list
+to free the resources used by the returned list.
+.PP
+.I hesiod_to_bind
+converts
+.I name
+and
+.I type
+into the DNS name used by
+.IR hesiod_resolve .
+It is the caller's responsibility to free the returned string using
+.IR free .
+.SH RETURN VALUES
+If successful,
+.I hesiod_init
+returns 0; otherwise it returns \-1 and sets
+.I errno
+to indicate the error. On failure,
+.I hesiod_resolve
+and
+.I hesiod_to_bind
+return NULL and set the global variable
+.I errno
+to indicate the error.
+.SH ENVIRONMENT
+If the environment variable
+.B HES_DOMAIN
+is set, it will override the domain in the Hesiod configuration file.
+If the environment variable
+.B HESIOD_CONFIG
+is set, it specifies the location of the Hesiod configuration file.
+.SH SEE ALSO
+`Hesiod - Project Athena Technical Plan -- Name Service', named(8),
+hesiod.conf(5)
+.SH ERRORS
+Hesiod calls may fail because of:
+.IP ENOMEM
+Insufficient memory was available to carry out the requested
+operation.
+.IP ENOEXEC
+.I hesiod_init
+failed because the Hesiod configuration file was invalid.
+.IP ECONNREFUSED
+.I hesiod_resolve
+failed because no name server could be contacted to answer the query.
+.IP EMSGSIZE
+.I hesiod_resolve
+or
+.I hesiod_to_bind
+failed because the query or response was too big to fit into the
+packet buffers.
+.IP ENOENT
+.I hesiod_resolve
+failed because the name server had no text records matching
+.I name
+and
+.IR type ,
+or
+.I hesiod_to_bind
+failed because the
+.I name
+argument had a domain extension which could not be resolved with type
+``rhs-extension'' in the local Hesiod domain.
+.SH AUTHOR
+Steve Dyer, IBM/Project Athena
+.br
+Greg Hudson, MIT Team Athena
+.br
+Copyright 1987, 1988, 1995, 1996 by the Massachusetts Institute of Technology.
+.SH BUGS
+The strings corresponding to the
+.I errno
+values set by the Hesiod functions are not particularly indicative of
+what went wrong, especially for
+.I ENOEXEC
+and
+.IR ENOENT .
diff --git a/lib/libc/net/hesiod.c b/lib/libc/net/hesiod.c
new file mode 100644
index 0000000..f36757b
--- /dev/null
+++ b/lib/libc/net/hesiod.c
@@ -0,0 +1,572 @@
+/* $NetBSD: hesiod.c,v 1.9 1999/02/11 06:16:38 simonb Exp $ */
+
+/* Copyright (c) 1996 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.
+ */
+
+/* Copyright 1996 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is part of the hesiod library. It implements the core
+ * portion of the hesiod resolver.
+ *
+ * This file is loosely based on an interim version of hesiod.c from
+ * the BIND IRS library, which was in turn based on an earlier version
+ * of this file. Extensive changes have been made on each step of the
+ * path.
+ *
+ * This implementation is not truly thread-safe at the moment because
+ * it uses res_send() and accesses _res.
+ */
+
+#include <sys/cdefs.h>
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *orig_rcsid = "$NetBSD: hesiod.c,v 1.9 1999/02/11 06:16:38 simonb Exp $";
+static char *rcsid = "$FreeBSD$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <hesiod.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct hesiod_p {
+ char *lhs; /* normally ".ns" */
+ char *rhs; /* AKA the default hesiod domain */
+ int classes[2]; /* The class search order. */
+};
+
+#define MAX_HESRESP 1024
+
+static int read_config_file __P((struct hesiod_p *, const char *));
+static char **get_txt_records __P((int, const char *));
+static int init_context __P((void));
+static void translate_errors __P((void));
+
+
+/*
+ * hesiod_init --
+ * initialize a hesiod_p.
+ */
+int
+hesiod_init(context)
+ void **context;
+{
+ struct hesiod_p *ctx;
+ const char *p, *configname;
+
+ ctx = malloc(sizeof(struct hesiod_p));
+ if (ctx) {
+ *context = ctx;
+ configname = getenv("HESIOD_CONFIG");
+ if (!configname)
+ configname = _PATH_HESIOD_CONF;
+ if (read_config_file(ctx, configname) >= 0) {
+ /*
+ * The default rhs can be overridden by an
+ * environment variable.
+ */
+ p = getenv("HES_DOMAIN");
+ if (p) {
+ if (ctx->rhs)
+ free(ctx->rhs);
+ ctx->rhs = malloc(strlen(p) + 2);
+ if (ctx->rhs) {
+ *ctx->rhs = '.';
+ strcpy(ctx->rhs + 1,
+ (*p == '.') ? p + 1 : p);
+ return 0;
+ } else
+ errno = ENOMEM;
+ } else
+ return 0;
+ }
+ } else
+ errno = ENOMEM;
+
+ if (ctx->lhs)
+ free(ctx->lhs);
+ if (ctx->rhs)
+ free(ctx->rhs);
+ if (ctx)
+ free(ctx);
+ return -1;
+}
+
+/*
+ * hesiod_end --
+ * Deallocates the hesiod_p.
+ */
+void
+hesiod_end(context)
+ void *context;
+{
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+
+ free(ctx->rhs);
+ if (ctx->lhs)
+ free(ctx->lhs);
+ free(ctx);
+}
+
+/*
+ * hesiod_to_bind --
+ * takes a hesiod (name, type) and returns a DNS
+ * name which is to be resolved.
+ */
+char *
+hesiod_to_bind(void *context, const char *name, const char *type)
+{
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+ char bindname[MAXDNAME], *p, *ret, **rhs_list = NULL;
+ const char *rhs;
+ int len;
+
+ strcpy(bindname, name);
+
+ /*
+ * Find the right right hand side to use, possibly
+ * truncating bindname.
+ */
+ p = strchr(bindname, '@');
+ if (p) {
+ *p++ = 0;
+ if (strchr(p, '.'))
+ rhs = name + (p - bindname);
+ else {
+ rhs_list = hesiod_resolve(context, p, "rhs-extension");
+ if (rhs_list)
+ rhs = *rhs_list;
+ else {
+ errno = ENOENT;
+ return NULL;
+ }
+ }
+ } else
+ rhs = ctx->rhs;
+
+ /* See if we have enough room. */
+ len = strlen(bindname) + 1 + strlen(type);
+ if (ctx->lhs)
+ len += strlen(ctx->lhs) + ((ctx->lhs[0] != '.') ? 1 : 0);
+ len += strlen(rhs) + ((rhs[0] != '.') ? 1 : 0);
+ if (len > sizeof(bindname) - 1) {
+ if (rhs_list)
+ hesiod_free_list(context, rhs_list);
+ errno = EMSGSIZE;
+ return NULL;
+ }
+ /* Put together the rest of the domain. */
+ strcat(bindname, ".");
+ strcat(bindname, type);
+ /* Only append lhs if it isn't empty. */
+ if (ctx->lhs && ctx->lhs[0] != '\0' ) {
+ if (ctx->lhs[0] != '.')
+ strcat(bindname, ".");
+ strcat(bindname, ctx->lhs);
+ }
+ if (rhs[0] != '.')
+ strcat(bindname, ".");
+ strcat(bindname, rhs);
+
+ /* rhs_list is no longer needed, since we're done with rhs. */
+ if (rhs_list)
+ hesiod_free_list(context, rhs_list);
+
+ /* Make a copy of the result and return it to the caller. */
+ ret = strdup(bindname);
+ if (!ret)
+ errno = ENOMEM;
+ return ret;
+}
+
+/*
+ * hesiod_resolve --
+ * Given a hesiod name and type, return an array of strings returned
+ * by the resolver.
+ */
+char **
+hesiod_resolve(context, name, type)
+ void *context;
+ const char *name;
+ const char *type;
+{
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+ char *bindname, **retvec;
+
+ bindname = hesiod_to_bind(context, name, type);
+ if (!bindname)
+ return NULL;
+
+ retvec = get_txt_records(ctx->classes[0], bindname);
+ if (retvec == NULL && errno == ENOENT && ctx->classes[1])
+ retvec = get_txt_records(ctx->classes[1], bindname);
+
+ free(bindname);
+ return retvec;
+}
+
+/*ARGSUSED*/
+void
+hesiod_free_list(context, list)
+ void *context;
+ char **list;
+{
+ char **p;
+
+ if (list == NULL)
+ return;
+ for (p = list; *p; p++)
+ free(*p);
+ free(list);
+}
+
+
+/* read_config_file --
+ * Parse the /etc/hesiod.conf file. Returns 0 on success,
+ * -1 on failure. On failure, it might leave values in ctx->lhs
+ * or ctx->rhs which need to be freed by the caller.
+ */
+static int
+read_config_file(ctx, filename)
+ struct hesiod_p *ctx;
+ const char *filename;
+{
+ char *key, *data, *p, **which;
+ char buf[MAXDNAME + 7];
+ int n;
+ FILE *fp;
+
+ /* Set default query classes. */
+ ctx->classes[0] = C_IN;
+ ctx->classes[1] = C_HS;
+
+ /* Try to open the configuration file. */
+ fp = fopen(filename, "r");
+ if (!fp) {
+ /* Use compiled in default domain names. */
+ ctx->lhs = strdup(DEF_LHS);
+ ctx->rhs = strdup(DEF_RHS);
+ if (ctx->lhs && ctx->rhs)
+ return 0;
+ else {
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ ctx->lhs = NULL;
+ ctx->rhs = NULL;
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ p = buf;
+ if (*p == '#' || *p == '\n' || *p == '\r')
+ continue;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ key = p;
+ while (*p != ' ' && *p != '\t' && *p != '=')
+ p++;
+ *p++ = 0;
+
+ while (isspace(*p) || *p == '=')
+ p++;
+ data = p;
+ while (!isspace(*p))
+ p++;
+ *p = 0;
+
+ if (strcasecmp(key, "lhs") == 0 ||
+ strcasecmp(key, "rhs") == 0) {
+ which = (strcasecmp(key, "lhs") == 0)
+ ? &ctx->lhs : &ctx->rhs;
+ *which = strdup(data);
+ if (!*which) {
+ errno = ENOMEM;
+ return -1;
+ }
+ } else {
+ if (strcasecmp(key, "classes") == 0) {
+ n = 0;
+ while (*data && n < 2) {
+ p = data;
+ while (*p && *p != ',')
+ p++;
+ if (*p)
+ *p++ = 0;
+ if (strcasecmp(data, "IN") == 0)
+ ctx->classes[n++] = C_IN;
+ else
+ if (strcasecmp(data, "HS") == 0)
+ ctx->classes[n++] =
+ C_HS;
+ data = p;
+ }
+ while (n < 2)
+ ctx->classes[n++] = 0;
+ }
+ }
+ }
+ fclose(fp);
+
+ if (!ctx->rhs || ctx->classes[0] == 0 ||
+ ctx->classes[0] == ctx->classes[1]) {
+ errno = ENOEXEC;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * get_txt_records --
+ * Given a DNS class and a DNS name, do a lookup for TXT records, and
+ * return a list of them.
+ */
+static char **
+get_txt_records(qclass, name)
+ int qclass;
+ const char *name;
+{
+ HEADER *hp;
+ unsigned char qbuf[PACKETSZ], abuf[MAX_HESRESP], *p, *eom, *eor;
+ char *dst, **list;
+ int ancount, qdcount, i, j, n, skip, type, class, len;
+
+ /* Make sure the resolver is initialized. */
+ if ((_res.options & RES_INIT) == 0 && res_init() == -1)
+ return NULL;
+
+ /* Construct the query. */
+ n = res_mkquery(QUERY, name, qclass, T_TXT, NULL, 0,
+ NULL, qbuf, PACKETSZ);
+ if (n < 0)
+ return NULL;
+
+ /* Send the query. */
+ n = res_send(qbuf, n, abuf, MAX_HESRESP);
+ if (n < 0) {
+ errno = ECONNREFUSED;
+ return NULL;
+ }
+ /* Parse the header of the result. */
+ hp = (HEADER *) (void *) abuf;
+ ancount = ntohs(hp->ancount);
+ qdcount = ntohs(hp->qdcount);
+ p = abuf + sizeof(HEADER);
+ eom = abuf + n;
+
+ /*
+ * Skip questions, trying to get to the answer section
+ * which follows.
+ */
+ for (i = 0; i < qdcount; i++) {
+ skip = dn_skipname(p, eom);
+ if (skip < 0 || p + skip + QFIXEDSZ > eom) {
+ errno = EMSGSIZE;
+ return NULL;
+ }
+ p += skip + QFIXEDSZ;
+ }
+
+ /* Allocate space for the text record answers. */
+ list = malloc((ancount + 1) * sizeof(char *));
+ if (!list) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ /* Parse the answers. */
+ j = 0;
+ for (i = 0; i < ancount; i++) {
+ /* Parse the header of this answer. */
+ skip = dn_skipname(p, eom);
+ if (skip < 0 || p + skip + 10 > eom)
+ break;
+ type = p[skip + 0] << 8 | p[skip + 1];
+ class = p[skip + 2] << 8 | p[skip + 3];
+ len = p[skip + 8] << 8 | p[skip + 9];
+ p += skip + 10;
+ if (p + len > eom) {
+ errno = EMSGSIZE;
+ break;
+ }
+ /* Skip entries of the wrong class and type. */
+ if (class != qclass || type != T_TXT) {
+ p += len;
+ continue;
+ }
+ /* Allocate space for this answer. */
+ list[j] = malloc((size_t)len);
+ if (!list[j]) {
+ errno = ENOMEM;
+ break;
+ }
+ dst = list[j++];
+
+ /* Copy answer data into the allocated area. */
+ eor = p + len;
+ while (p < eor) {
+ n = (unsigned char) *p++;
+ if (p + n > eor) {
+ errno = EMSGSIZE;
+ break;
+ }
+ memcpy(dst, p, (size_t)n);
+ p += n;
+ dst += n;
+ }
+ if (p < eor) {
+ errno = EMSGSIZE;
+ break;
+ }
+ *dst = 0;
+ }
+
+ /*
+ * If we didn't terminate the loop normally, something
+ * went wrong.
+ */
+ if (i < ancount) {
+ for (i = 0; i < j; i++)
+ free(list[i]);
+ free(list);
+ return NULL;
+ }
+ if (j == 0) {
+ errno = ENOENT;
+ free(list);
+ return NULL;
+ }
+ list[j] = NULL;
+ return list;
+}
+
+ /*
+ * COMPATIBILITY FUNCTIONS
+ */
+
+static int inited = 0;
+static void *context;
+static int errval = HES_ER_UNINIT;
+
+int
+hes_init()
+{
+ init_context();
+ return errval;
+}
+
+char *
+hes_to_bind(name, type)
+ const char *name;
+ const char *type;
+{
+ static char *bindname;
+ if (init_context() < 0)
+ return NULL;
+ if (bindname)
+ free(bindname);
+ bindname = hesiod_to_bind(context, name, type);
+ if (!bindname)
+ translate_errors();
+ return bindname;
+}
+
+char **
+hes_resolve(name, type)
+ const char *name;
+ const char *type;
+{
+ static char **list;
+
+ if (init_context() < 0)
+ return NULL;
+
+ /*
+ * In the old Hesiod interface, the caller was responsible for
+ * freeing the returned strings but not the vector of strings itself.
+ */
+ if (list)
+ free(list);
+
+ list = hesiod_resolve(context, name, type);
+ if (!list)
+ translate_errors();
+ return list;
+}
+
+int
+hes_error()
+{
+ return errval;
+}
+
+void
+hes_free(hp)
+ char **hp;
+{
+ hesiod_free_list(context, hp);
+}
+
+static int
+init_context()
+{
+ if (!inited) {
+ inited = 1;
+ if (hesiod_init(&context) < 0) {
+ errval = HES_ER_CONFIG;
+ return -1;
+ }
+ errval = HES_ER_OK;
+ }
+ return 0;
+}
+
+static void
+translate_errors()
+{
+ switch (errno) {
+ case ENOENT:
+ errval = HES_ER_NOTFOUND;
+ break;
+ case ECONNREFUSED:
+ case EMSGSIZE:
+ errval = HES_ER_NET;
+ break;
+ case ENOMEM:
+ default:
+ /* Not a good match, but the best we can do. */
+ errval = HES_ER_CONFIG;
+ break;
+ }
+}
diff --git a/lib/libc/net/name6.c b/lib/libc/net/name6.c
index 8edcb1b..ea08d92 100644
--- a/lib/libc/net/name6.c
+++ b/lib/libc/net/name6.c
@@ -109,6 +109,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#include <unistd.h>
#ifndef _PATH_HOSTS
@@ -169,110 +171,32 @@ static char *_hgetword(char **pp);
static int _mapped_addr_enabled(void);
static FILE *_files_open(int *errp);
-static struct hostent *_files_ghbyname(const char *name, int af, int *errp);
-static struct hostent *_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
+static int _files_ghbyname(void *, void *, va_list);
+static int _files_ghbyaddr(void *, void *, va_list);
static void _files_shent(int stayopen);
static void _files_ehent(void);
#ifdef YP
-static struct hostent *_nis_ghbyname(const char *name, int af, int *errp);
-static struct hostent *_nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
+static int _nis_ghbyname(void *, void *, va_list);
+static int _nis_ghbyaddr(void *, void *, va_list);
#endif
-static struct hostent *_dns_ghbyname(const char *name, int af, int *errp);
-static struct hostent *_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
+static int _dns_ghbyname(void *, void *, va_list);
+static int _dns_ghbyaddr(void *, void *, va_list);
static void _dns_shent(int stayopen);
static void _dns_ehent(void);
#ifdef ICMPNL
-static struct hostent *_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
+static int _icmp_ghbyaddr(void *, void *, va_list);
#endif /* ICMPNL */
-/*
- * Select order host function.
- */
-#define MAXHOSTCONF 4
-
-#ifndef HOSTCONF
-# define HOSTCONF "/etc/host.conf"
-#endif /* !HOSTCONF */
-
-struct _hostconf {
- struct hostent *(*byname)(const char *name, int af, int *errp);
- struct hostent *(*byaddr)(const void *addr, int addrlen, int af, int *errp);
-};
-
-/* default order */
-static struct _hostconf _hostconf[MAXHOSTCONF] = {
- { _dns_ghbyname, _dns_ghbyaddr },
- { _files_ghbyname, _files_ghbyaddr },
+/* Host lookup order if nsswitch.conf is broken or nonexistant */
+static const ns_src default_src[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NSSRC_DNS, NS_SUCCESS },
#ifdef ICMPNL
- { NULL, _icmp_ghbyaddr },
-#endif /* ICMPNL */
-};
-
-static int _hostconf_init_done;
-static void _hostconf_init(void);
-
-/*
- * Initialize hostconf structure.
- */
-
-static void
-_hostconf_init(void)
-{
- FILE *fp;
- int n;
- char *p, *line;
- char buf[BUFSIZ];
-
- _hostconf_init_done = 1;
- n = 0;
- p = HOSTCONF;
- if ((fp = fopen(p, "r")) == NULL)
- return;
- while (n < MAXHOSTCONF && fgets(buf, sizeof(buf), fp)) {
- line = buf;
- if ((p = _hgetword(&line)) == NULL)
- continue;
- do {
- if (strcmp(p, "hosts") == 0
- || strcmp(p, "local") == 0
- || strcmp(p, "file") == 0
- || strcmp(p, "files") == 0) {
- _hostconf[n].byname = _files_ghbyname;
- _hostconf[n].byaddr = _files_ghbyaddr;
- n++;
- }
- else if (strcmp(p, "dns") == 0
- || strcmp(p, "bind") == 0) {
- _hostconf[n].byname = _dns_ghbyname;
- _hostconf[n].byaddr = _dns_ghbyaddr;
- n++;
- }
-#ifdef YP
- else if (strcmp(p, "nis") == 0) {
- _hostconf[n].byname = _nis_ghbyname;
- _hostconf[n].byaddr = _nis_ghbyaddr;
- n++;
- }
+#define NSSRC_ICMP "icmp"
+ { NSSRC_ICMP, NS_SUCCESS },
#endif
-#ifdef ICMPNL
- else if (strcmp(p, "icmp") == 0) {
- _hostconf[n].byname = NULL;
- _hostconf[n].byaddr = _icmp_ghbyaddr;
- n++;
- }
-#endif /* ICMPNL */
- } while ((p = _hgetword(&line)) != NULL);
- }
- fclose(fp);
- if (n < 0) {
- /* no keyword found. do not change default configuration */
- return;
- }
- for (; n < MAXHOSTCONF; n++) {
- _hostconf[n].byname = NULL;
- _hostconf[n].byaddr = NULL;
- }
-}
+ { 0 }
+};
/*
* Check if kernel supports mapped address.
@@ -311,7 +235,14 @@ static struct hostent *
_ghbyname(const char *name, int af, int flags, int *errp)
{
struct hostent *hp;
- int i;
+ int i, rval;
+
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_files_ghbyname, NULL)
+ { NSSRC_DNS, _dns_ghbyname, NULL },
+ NS_NIS_CB(_nis_ghbyname, NULL)
+ { 0 }
+ };
if (flags & AI_ADDRCONFIG) {
int s;
@@ -342,13 +273,9 @@ _ghbyname(const char *name, int af, int flags, int *errp)
}
}
- for (i = 0; i < MAXHOSTCONF; i++) {
- if (_hostconf[i].byname
- && (hp = (*_hostconf[i].byname)(name, af, errp)) != NULL)
- return hp;
- }
-
- return NULL;
+ rval = nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyname", default_src,
+ name, af, errp);
+ return (rval == NS_SUCCESS) ? hp : NULL;
}
/* getipnodebyname() internal routine for multiple query(PF_UNSPEC) support. */
@@ -392,9 +319,6 @@ _getipnodebyname_multi(const char *name, int af, int flags, int *errp)
return _hpaddr(af, name, &addrbuf, errp);
}
- if (!_hostconf_init_done)
- _hostconf_init();
-
*errp = HOST_NOT_FOUND;
hp = _ghbyname(name, af, flags, errp);
@@ -436,13 +360,23 @@ struct hostent *
getipnodebyaddr(const void *src, size_t len, int af, int *errp)
{
struct hostent *hp;
- int i;
+ int i, rval;
#ifdef INET6
struct in6_addr addrbuf;
#else
struct in_addr addrbuf;
#endif
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_files_ghbyaddr, NULL)
+ { NSSRC_DNS, _dns_ghbyaddr, NULL },
+ NS_NIS_CB(_nis_ghbyaddr, NULL)
+#ifdef ICMPNL
+ { NSSRC_ICMP, _icmp_ghbyaddr, NULL },
+#endif
+ { 0 }
+ };
+
*errp = HOST_NOT_FOUND;
switch (af) {
@@ -484,15 +418,9 @@ getipnodebyaddr(const void *src, size_t len, int af, int *errp)
return NULL;
}
- if (!_hostconf_init_done)
- _hostconf_init();
- for (i = 0; i < MAXHOSTCONF; i++) {
- if (_hostconf[i].byaddr
- && (hp = (*_hostconf[i].byaddr)(src, len, af, errp)) != NULL)
- return hp;
- }
-
- return NULL;
+ rval = nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyaddr", default_src,
+ src, len, af, errp);
+ return (rval == NS_SUCCESS) ? hp : NULL;
}
void
@@ -828,9 +756,12 @@ _files_open(int *errp)
return fp;
}
-static struct hostent *
-_files_ghbyname(const char *name, int af, int *errp)
+static int
+_files_ghbyname(void *rval, void *cb_data, va_list ap)
{
+ const char *name;
+ int af;
+ int *errp;
int match, nalias;
char *p, *line, *addrstr, *cname;
FILE *fp;
@@ -840,8 +771,14 @@ _files_ghbyname(const char *name, int af, int *errp)
char buf[BUFSIZ];
int af0 = af;
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
+ *(struct hostent **)rval = NULL;
+
if ((fp = _files_open(errp)) == NULL)
- return NULL;
+ return NS_UNAVAIL;
rethp = hp = NULL;
while (fgets(buf, sizeof(buf), fp)) {
@@ -906,12 +843,17 @@ _files_ghbyname(const char *name, int af, int *errp)
rethp = _hpmerge(rethp, hp, errp);
}
fclose(fp);
- return rethp;
+ *(struct hostent **)rval = rethp;
+ return (rethp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
-static struct hostent *
-_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
+static int
+_files_ghbyaddr(void *rval, void *cb_data, va_list ap)
{
+ const void *addr;
+ int addrlen;
+ int af;
+ int *errp;
int nalias;
char *p, *line;
FILE *fp;
@@ -920,8 +862,15 @@ _files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
union inx_addr addrbuf;
char buf[BUFSIZ];
+ addr = va_arg(ap, const void *);
+ addrlen = va_arg(ap, int);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
+ *(struct hostent**)rval = NULL;
+
if ((fp = _files_open(errp)) == NULL)
- return NULL;
+ return NS_UNAVAIL;
hp = NULL;
while (fgets(buf, sizeof(buf), fp)) {
line = buf;
@@ -950,7 +899,8 @@ _files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
break;
}
fclose(fp);
- return hp;
+ *(struct hostent **)rval = hp;
+ return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
#ifdef YP
@@ -959,11 +909,18 @@ _files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
*
* XXX actually a hack, these are INET4 specific.
*/
-static struct hostent *
-_nis_ghbyname(const char *name, int af, int *errp)
+static int
+_nis_ghbyname(void *rval, void *cb_data, va_list ap)
{
+ const char *name;
+ int af;
+ int *errp;
struct hostent *hp = NULL;
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
if (af == AF_UNSPEC)
af = AF_INET;
if (af == AF_INET) {
@@ -971,21 +928,32 @@ _nis_ghbyname(const char *name, int af, int *errp)
if (hp != NULL)
hp = _hpcopy(hp, errp);
}
- return (hp);
+
+ *(struct hostent **)rval = hp;
+ return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
-static struct hostent *
-_nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
+static int
+_nis_ghbyaddr(void *rval, void *cb_data, va_list ap)
{
+ const void *addr;
+ int addrlen;
+ int af;
+ int *errp;
struct hostent *hp = NULL;
+ addr = va_arg(ap, const void *);
+ addrlen = va_arg(ap, int);
+ af = va_arg(ap, int);
+
if (af == AF_INET) {
hp = _gethostbynisaddr(addr, addrlen, af);
if (hp != NULL)
hp = _hpcopy(hp, errp);
}
- return (hp);
+ *(struct hostent **)rval = hp;
+ return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
#endif
@@ -1486,14 +1454,21 @@ _res_search_multi(name, rtl, errp)
return (NULL);
}
-static struct hostent *
-_dns_ghbyname(const char *name, int af, int *errp)
+static int
+_dns_ghbyname(void *rval, void *cb_data, va_list ap)
{
+ const char *name;
+ int af;
+ int *errp;
struct __res_type_list *rtl, rtl4;
#ifdef INET6
struct __res_type_list rtl6;
#endif
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
#ifdef INET6
switch (af) {
case AF_UNSPEC:
@@ -1514,12 +1489,17 @@ _dns_ghbyname(const char *name, int af, int *errp)
SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
rtl = &rtl4;
#endif
- return(_res_search_multi(name, rtl, errp));
+ *(struct hostent **)rval = _res_search_multi(name, rtl, errp);
+ return (*(struct hostent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
-static struct hostent *
-_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
+static int
+_dns_ghbyaddr(void *rval, void *cb_data, va_list ap)
{
+ const void *addr;
+ int addrlen;
+ int af;
+ int *errp;
int n;
struct hostent *hp;
u_char c, *cp;
@@ -1533,16 +1513,23 @@ _dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
char qbuf[MAXDNAME+1];
char *hlist[2];
+ addr = va_arg(ap, const void *);
+ addrlen = va_arg(ap, int);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
+ *(struct hostent **)rval = NULL;
+
#ifdef INET6
/* XXX */
if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr))
- return NULL;
+ return NS_NOTFOUND;
#endif
if ((_res.options & RES_INIT) == 0) {
if (res_init() < 0) {
*errp = h_errno;
- return NULL;
+ return NS_UNAVAIL;
}
}
memset(&hbuf, 0, sizeof(hbuf));
@@ -1585,17 +1572,18 @@ _dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
n = res_query(qbuf, C_IN, T_PTR, buf.buf, sizeof buf.buf);
if (n < 0) {
*errp = h_errno;
- return NULL;
+ return NS_UNAVAIL;
}
hp = getanswer(&buf, n, qbuf, T_PTR, &hbuf, errp);
if (!hp)
- return NULL;
+ return NS_NOTFOUND;
hbuf.h_addrtype = af;
hbuf.h_length = addrlen;
hbuf.h_addr_list = hlist;
hlist[0] = (char *)addr;
hlist[1] = NULL;
- return _hpcopy(&hbuf, errp);
+ *(struct hostent **)rval = _hpcopy(&hbuf, errp);
+ return NS_SUCCESS;
}
static void
diff --git a/lib/libc/net/nsdispatch.3 b/lib/libc/net/nsdispatch.3
new file mode 100644
index 0000000..bd6366e
--- /dev/null
+++ b/lib/libc/net/nsdispatch.3
@@ -0,0 +1,231 @@
+.\" $NetBSD: nsdispatch.3,v 1.8 1999/03/22 19:44:53 garbled Exp $
+.\" $FreeBSD$
+.\"
+.\" Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Luke Mewburn.
+.\"
+.\" 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 FOUNDATION 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 January 19, 1999
+.Dt NSDISPATCH 3
+.Os
+.Sh NAME
+.Nm nsdispatch
+.Nd name-service switch dispatcher routine
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <nsswitch.h>
+.Ft int
+.Fo nsdispatch
+.Fa "void *retval"
+.Fa "const ns_dtab dtab[]"
+.Fa "const char *database"
+.Fa "const char *method"
+.Fa "const ns_src defaults[]"
+.Fa "..."
+.Fc
+.Sh DESCRIPTION
+The
+.Fn nsdispatch
+function invokes the callback functions specified in
+.Va dtab
+in the order given in
+.Pa /etc/nsswitch.conf
+for the database
+.Va database
+until a successful entry is found.
+.Pp
+.Va retval
+is passed to each callback function to modify as necessary
+(to pass back to the caller of
+.Fn nsdispatch )
+.Pp
+.Va dtab
+is an array of
+.Va ns_dtab
+structures, which have the following format:
+.Bd -literal -offset indent
+typedef struct {
+ const char *src;
+ int (*cb)(void *retval, void *cb_data, va_list ap);
+ void *cb_data;
+} ns_dtab;
+.Ed
+.Pp
+.Bd -ragged -offset indent
+For each source type that is implemented, an entry with
+.Va src
+set to the name of the source,
+.Va cb
+defined as a function which handles that source, and
+.Va cb_data
+is used to pass arbritrary data to the callback function.
+The last entry in
+.Va dtab
+should contain
+.Dv NULL
+values for
+.Va src ,
+.Va cb ,
+and
+.Va cb_data .
+.Ed
+.Pp
+.Va method
+is usually the name of the function calling
+.Fn nsdispatch .
+When dynamic loading is supported, a symbol constructed from
+.Va database ,
+the current source, and
+.Va method
+will be used as the name to invoke the dynamically loaded function.
+.Pp
+.Va defaults
+contains a list of default sources to try in the case of
+a missing or corrupt
+.Xr nsswitch.conf 5 ,
+or if there isn't a relevant entry for
+.Va database .
+It is an array of
+.Va ns_src
+structures, which have the following format:
+.Bd -literal -offset indent
+typedef struct {
+ const char *src;
+ u_int32_t flags;
+} ns_src;
+.Ed
+.Pp
+.Bd -ragged -offset indent
+For each default source type, an entry with
+.Va src
+set to the name of the source, and
+.Va flags
+set to the relevant flags
+(usually
+.Dv NS_SUCCESS ;
+refer to
+.Sx Callback return values
+for more information).
+The last entry in
+.Va defaults
+should have
+.Va src
+set to
+.Dv NULL
+and
+.Va flags
+set to 0.
+.Pp
+For convenience, a global variable defined as:
+.Dl extern const ns_src __nsdefaultsrc[];
+exists which contains a single default entry for
+.Sq files
+for use by callers which don't require complicated default rules.
+.Ed
+.Pp
+.Va Sq ...
+are optional extra arguments, which
+are passed to the appropriate callback function as a variable argument
+list of the type
+.Va va_list .
+.Ss Valid source types
+Whilst there is support for arbitrary sources, the following
+#defines for commonly implementated sources are available:
+.Bl -column NS_COMPAT COMPAT -offset indent
+.Sy #define value
+.It NSSRC_FILES "files"
+.It NSSRC_DNS "dns"
+.It NSSRC_NIS "nis"
+.It NSSRC_COMPAT "compat"
+.El
+.Pp
+Refer to
+.Xr nsswitch.conf 5
+for a complete description of what each source type is.
+.Pp
+.Ss Callback return values
+The callback functions should return one of the following values
+depending upon status of the lookup:
+.Bl -column NS_NOTFOUND -offset indent
+.Sy "Return value" Status code
+.It NS_SUCCESS success
+.It NS_NOTFOUND notfound
+.It NS_UNAVAIL unavail
+.It NS_TRYAGAIN tryagain
+.El
+.Pp
+Refer to
+.Xr nsswitch.conf 5
+for a complete description of what each status code is.
+.Pp
+.Nm
+returns the value of the callback that caused the dispatcher to finish,
+or NS_NOTFOUND otherwise.
+.Sh SEE ALSO
+.Xr hesiod 3 ,
+.Xr stdarg 3 ,
+.Xr ypclnt 3 ,
+.Xr nsswitch.conf 5
+.Sh HISTORY
+The
+.Nm
+routines first appeared in
+.Fx 4.1 .
+They were imported from the
+.Nx
+Project,
+where they appeared first in
+.Nx 1.4 .
+.Sh AUTHORS
+Luke Mewburn
+.Aq lukem@netbsd.org
+wrote this freely distributable name-service switch implementation,
+using ideas from the
+.Tn ULTRIX
+.Xr svc.conf 5
+and
+.Tn Solaris
+.Xr nsswitch.conf 4
+manual pages.
+.Sh BUGS
+The
+.Nm
+routines are not thread safe.
+This will be rectified in the future.
+.Pp
+Currently there is no support for dynamically loadable dispatcher callback
+functions.
+It is anticipated that this will be added in the future in the back-end
+without requiring changes to code that invokes
+.Fn nsdispatch .
diff --git a/lib/libc/net/nsdispatch.c b/lib/libc/net/nsdispatch.c
new file mode 100644
index 0000000..311b89d
--- /dev/null
+++ b/lib/libc/net/nsdispatch.c
@@ -0,0 +1,270 @@
+/* $NetBSD: nsdispatch.c,v 1.9 1999/01/25 00:16:17 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * 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 FOUNDATION 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.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid =
+ "$FreeBSD$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <fcntl.h>
+#define _NS_PRIVATE
+#include <nsswitch.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * default sourcelist: `files'
+ */
+const ns_src __nsdefaultsrc[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { 0 },
+};
+
+
+static int _nsmapsize = 0;
+static ns_dbt *_nsmap = NULL;
+
+/*
+ * size of dynamic array chunk for _nsmap and _nsmap[x].srclist
+ */
+#define NSELEMSPERCHUNK 8
+
+
+int _nscmp __P((const void *, const void *));
+
+
+int
+_nscmp(a, b)
+ const void *a;
+ const void *b;
+{
+ return (strcasecmp(((const ns_dbt *)a)->name,
+ ((const ns_dbt *)b)->name));
+}
+
+
+void
+_nsdbtaddsrc(dbt, src)
+ ns_dbt *dbt;
+ const ns_src *src;
+{
+ if ((dbt->srclistsize % NSELEMSPERCHUNK) == 0) {
+ dbt->srclist = (ns_src *)realloc(dbt->srclist,
+ (dbt->srclistsize + NSELEMSPERCHUNK) * sizeof(ns_src));
+ if (dbt->srclist == NULL)
+ err(1, "nsdispatch: memory allocation failure");
+ }
+ memmove(&dbt->srclist[dbt->srclistsize++], src, sizeof(ns_src));
+}
+
+
+void
+_nsdbtdump(dbt)
+ const ns_dbt *dbt;
+{
+ int i;
+
+ printf("%s (%d source%s):", dbt->name, dbt->srclistsize,
+ dbt->srclistsize == 1 ? "" : "s");
+ for (i = 0; i < dbt->srclistsize; i++) {
+ printf(" %s", dbt->srclist[i].name);
+ if (!(dbt->srclist[i].flags &
+ (NS_UNAVAIL|NS_NOTFOUND|NS_TRYAGAIN)) &&
+ (dbt->srclist[i].flags & NS_SUCCESS))
+ continue;
+ printf(" [");
+ if (!(dbt->srclist[i].flags & NS_SUCCESS))
+ printf(" SUCCESS=continue");
+ if (dbt->srclist[i].flags & NS_UNAVAIL)
+ printf(" UNAVAIL=return");
+ if (dbt->srclist[i].flags & NS_NOTFOUND)
+ printf(" NOTFOUND=return");
+ if (dbt->srclist[i].flags & NS_TRYAGAIN)
+ printf(" TRYAGAIN=return");
+ printf(" ]");
+ }
+ printf("\n");
+}
+
+
+const ns_dbt *
+_nsdbtget(name)
+ const char *name;
+{
+ static time_t confmod;
+
+ struct stat statbuf;
+ ns_dbt dbt;
+
+ extern FILE *_nsyyin;
+ extern int _nsyyparse __P((void));
+
+ dbt.name = name;
+
+ if (confmod) {
+ if (stat(_PATH_NS_CONF, &statbuf) == -1)
+ return (NULL);
+ if (confmod < statbuf.st_mtime) {
+ int i, j;
+
+ for (i = 0; i < _nsmapsize; i++) {
+ for (j = 0; j < _nsmap[i].srclistsize; j++) {
+ if (_nsmap[i].srclist[j].name != NULL) {
+ /*LINTED const cast*/
+ free((void *)
+ _nsmap[i].srclist[j].name);
+ }
+ }
+ if (_nsmap[i].srclist)
+ free(_nsmap[i].srclist);
+ if (_nsmap[i].name) {
+ /*LINTED const cast*/
+ free((void *)_nsmap[i].name);
+ }
+ }
+ if (_nsmap)
+ free(_nsmap);
+ _nsmap = NULL;
+ _nsmapsize = 0;
+ confmod = 0;
+ }
+ }
+ if (!confmod) {
+ if (stat(_PATH_NS_CONF, &statbuf) == -1)
+ return (NULL);
+ _nsyyin = fopen(_PATH_NS_CONF, "r");
+ if (_nsyyin == NULL)
+ return (NULL);
+ _nsyyparse();
+ (void)fclose(_nsyyin);
+ qsort(_nsmap, (size_t)_nsmapsize, sizeof(ns_dbt), _nscmp);
+ confmod = statbuf.st_mtime;
+ }
+ return (bsearch(&dbt, _nsmap, (size_t)_nsmapsize, sizeof(ns_dbt),
+ _nscmp));
+}
+
+
+void
+_nsdbtput(dbt)
+ const ns_dbt *dbt;
+{
+ int i;
+
+ for (i = 0; i < _nsmapsize; i++) {
+ if (_nscmp(dbt, &_nsmap[i]) == 0) {
+ /* overwrite existing entry */
+ if (_nsmap[i].srclist != NULL)
+ free(_nsmap[i].srclist);
+ memmove(&_nsmap[i], dbt, sizeof(ns_dbt));
+ return;
+ }
+ }
+
+ if ((_nsmapsize % NSELEMSPERCHUNK) == 0) {
+ _nsmap = (ns_dbt *)realloc(_nsmap,
+ (_nsmapsize + NSELEMSPERCHUNK) * sizeof(ns_dbt));
+ if (_nsmap == NULL)
+ err(1, "nsdispatch: memory allocation failure");
+ }
+ memmove(&_nsmap[_nsmapsize++], dbt, sizeof(ns_dbt));
+}
+
+
+int
+#if __STDC__
+nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
+ const char *method, const ns_src defaults[], ...)
+#else
+nsdispatch(retval, disp_tab, database, method, defaults, va_alist)
+ void *retval;
+ const ns_dtab disp_tab[];
+ const char *database;
+ const char *method;
+ const ns_src defaults[];
+ va_dcl
+#endif
+{
+ va_list ap;
+ int i, curdisp, result;
+ const ns_dbt *dbt;
+ const ns_src *srclist;
+ int srclistsize;
+
+ dbt = _nsdbtget(database);
+ if (dbt != NULL) {
+ srclist = dbt->srclist;
+ srclistsize = dbt->srclistsize;
+ } else {
+ srclist = defaults;
+ srclistsize = 0;
+ while (srclist[srclistsize].name != NULL)
+ srclistsize++;
+ }
+ result = 0;
+
+ for (i = 0; i < srclistsize; i++) {
+ for (curdisp = 0; disp_tab[curdisp].src != NULL; curdisp++)
+ if (strcasecmp(disp_tab[curdisp].src,
+ srclist[i].name) == 0)
+ break;
+ result = 0;
+ if (disp_tab[curdisp].callback) {
+#if __STDC__
+ va_start(ap, defaults);
+#else
+ va_start(ap);
+#endif
+ result = disp_tab[curdisp].callback(retval,
+ disp_tab[curdisp].cb_data, ap);
+ va_end(ap);
+ if (result & srclist[i].flags) {
+ break;
+ }
+ }
+ }
+ return (result ? result : NS_NOTFOUND);
+}
diff --git a/lib/libc/net/nslexer.l b/lib/libc/net/nslexer.l
new file mode 100644
index 0000000..104cfbb
--- /dev/null
+++ b/lib/libc/net/nslexer.l
@@ -0,0 +1,116 @@
+%{
+/* $NetBSD: nslexer.l,v 1.3 1999/01/25 00:16:17 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * 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 FOUNDATION 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.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid =
+ "$FreeBSD$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <ctype.h>
+#include <err.h>
+#define _NS_PRIVATE
+#include <nsswitch.h>
+#include <string.h>
+
+#include "nsparser.h"
+
+#define YY_NO_UNPUT
+
+%}
+
+%option yylineno
+
+BLANK [ \t]
+CR \n
+STRING [a-zA-Z][a-zA-Z0-9_]*
+
+%%
+
+{BLANK}+ ; /* skip whitespace */
+
+#.* ; /* skip comments */
+
+\\{CR} ; /* allow continuation */
+
+{CR} return NL;
+
+[sS][uU][cC][cC][eE][sS][sS] return SUCCESS;
+[uU][nN][aA][vV][aA][iI][lL] return UNAVAIL;
+[nN][oO][tT][fF][oO][uU][nN][dD] return NOTFOUND;
+[tT][rR][yY][aA][gG][aA][iI][nN] return TRYAGAIN;
+
+[rR][eE][tT][uU][rR][nN] return RETURN;
+[cC][oO][nN][tT][iI][nN][uU][eE] return CONTINUE;
+
+{STRING} {
+ char *p;
+ int i;
+
+ if ((p = strdup(yytext)) == NULL)
+ err(1, "nsdispatch: memory allocation failure");
+
+ for (i = 0; i < strlen(p); i++) {
+ if (isupper((unsigned char)p[i]))
+ p[i] = tolower((unsigned char)p[i]);
+ }
+ _nsyylval.str = p;
+ return STRING;
+ }
+
+[:=\[\]] return yytext[0];
+
+. ; /* ignore all else */
+
+%%
+
+#undef _nsyywrap
+int
+_nsyywrap()
+{
+ return 1;
+} /* _nsyywrap */
+
+void
+_nsyyerror(msg)
+ const char *msg;
+{
+
+ warnx("%s line %d: %s at '%s'", _PATH_NS_CONF, yylineno, msg, yytext);
+} /* _nsyyerror */
diff --git a/lib/libc/net/nsparser.y b/lib/libc/net/nsparser.y
new file mode 100644
index 0000000..b39f011
--- /dev/null
+++ b/lib/libc/net/nsparser.y
@@ -0,0 +1,175 @@
+%{
+/* $NetBSD: nsparser.y,v 1.3 1999/01/25 00:16:18 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * 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 FOUNDATION 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.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid =
+ "$FreeBSD$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <err.h>
+#define _NS_PRIVATE
+#include <nsswitch.h>
+#include <stdio.h>
+#include <string.h>
+
+
+static void _nsaddsrctomap __P((const char *));
+
+static ns_dbt curdbt;
+static ns_src cursrc;
+%}
+
+%union {
+ char *str;
+ int mapval;
+}
+
+%token NL
+%token SUCCESS UNAVAIL NOTFOUND TRYAGAIN
+%token RETURN CONTINUE
+%token <str> STRING
+
+%type <mapval> Status Action
+
+%%
+
+File
+ : /* empty */
+ | Lines
+ ;
+
+Lines
+ : Entry
+ | Lines Entry
+ ;
+
+Entry
+ : NL
+ | Database ':' NL
+ | Database ':' Srclist NL
+ {
+ _nsdbtput(&curdbt);
+ }
+ ;
+
+Database
+ : STRING
+ {
+ curdbt.name = yylval.str;
+ curdbt.srclist = NULL;
+ curdbt.srclistsize = 0;
+ }
+ ;
+
+Srclist
+ : Item
+ | Srclist Item
+ ;
+
+Item
+ : STRING
+ {
+ cursrc.flags = NS_SUCCESS;
+ _nsaddsrctomap($1);
+ }
+ | STRING '[' { cursrc.flags = NS_SUCCESS; } Criteria ']'
+ {
+ _nsaddsrctomap($1);
+ }
+ ;
+
+Criteria
+ : Criterion
+ | Criteria Criterion
+ ;
+
+Criterion
+ : Status '=' Action
+ {
+ if ($3) /* if action == RETURN set RETURN bit */
+ cursrc.flags |= $1;
+ else /* else unset it */
+ cursrc.flags &= ~$1;
+ }
+ ;
+
+Status
+ : SUCCESS { $$ = NS_SUCCESS; }
+ | UNAVAIL { $$ = NS_UNAVAIL; }
+ | NOTFOUND { $$ = NS_NOTFOUND; }
+ | TRYAGAIN { $$ = NS_TRYAGAIN; }
+ ;
+
+Action
+ : RETURN { $$ = 1L; }
+ | CONTINUE { $$ = 0L; }
+ ;
+
+%%
+
+static void
+_nsaddsrctomap(elem)
+ const char *elem;
+{
+ int i, lineno;
+ extern int _nsyylineno;
+ extern char * _nsyytext;
+
+ lineno = _nsyylineno - (*_nsyytext == '\n' ? 1 : 0);
+ if (curdbt.srclistsize > 0) {
+ if ((strcasecmp(elem, NSSRC_COMPAT) == 0) ||
+ (strcasecmp(curdbt.srclist[0].name, NSSRC_COMPAT) == 0)) {
+ /* XXX: syslog the following */
+ warnx("%s line %d: 'compat' used with other sources",
+ _PATH_NS_CONF, lineno);
+ return;
+ }
+ }
+ for (i = 0; i < curdbt.srclistsize; i++) {
+ if (strcasecmp(curdbt.srclist[i].name, elem) == 0) {
+ /* XXX: syslog the following */
+ warnx("%s line %d: duplicate source '%s'",
+ _PATH_NS_CONF, lineno, elem);
+ return;
+ }
+ }
+ cursrc.name = elem;
+ _nsdbtaddsrc(&curdbt, &cursrc);
+}
OpenPOWER on IntegriCloud