Add capability to use a db version of services. It is enabled by

specifying `db' as source of service in /etc/nsswitch.conf.

MFC after:	2 weeks
This commit is contained in:
Hajimu UMEMOTO 2010-04-04 08:31:03 +00:00
parent dc6ab8ddb4
commit e622b47989
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=206155
6 changed files with 224 additions and 3 deletions

View File

@ -82,6 +82,7 @@ typedef __uint32_t uint32_t;
#define _PATH_NETWORKS "/etc/networks"
#define _PATH_PROTOCOLS "/etc/protocols"
#define _PATH_SERVICES "/etc/services"
#define _PATH_SERVICES_DB "/var/db/services.db"
#define h_errno (*__h_errno())

View File

@ -58,6 +58,7 @@
* currently implemented sources
*/
#define NSSRC_FILES "files" /* local files */
#define NSSRC_DB "db" /* database */
#define NSSRC_DNS "dns" /* DNS; IN for hosts, HS for others */
#define NSSRC_NIS "nis" /* YP/NIS */
#define NSSRC_COMPAT "compat" /* passwd,group in YP compat mode */

View File

@ -37,7 +37,9 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <db.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <netdb.h>
#include <nsswitch.h>
@ -94,6 +96,19 @@ NSS_TLS_HANDLING(files);
static int files_servent(void *, void *, va_list);
static int files_setservent(void *, void *, va_list);
/* db backend declarations */
struct db_state
{
DB *db;
int stayopen;
int keynum;
};
static void db_endstate(void *);
NSS_TLS_HANDLING(db);
static int db_servent(void *, void *, va_list);
static int db_setservent(void *, void *, va_list);
#ifdef YP
/* nis backend declarations */
static int nis_servent(void *, void *, va_list);
@ -263,6 +278,8 @@ files_servent(void *retval, void *mdata, va_list ap)
{ NULL, 0 }
};
ns_dtab compat_dtab[] = {
{ NSSRC_DB, db_servent,
(void *)((struct servent_mdata *)mdata)->how },
#ifdef YP
{ NSSRC_NIS, nis_servent,
(void *)((struct servent_mdata *)mdata)->how },
@ -452,6 +469,185 @@ files_setservent(void *retval, void *mdata, va_list ap)
return (NS_UNAVAIL);
}
/* db backend implementation */
static void
db_endstate(void *p)
{
DB *db;
if (p == NULL)
return;
db = ((struct db_state *)p)->db;
if (db != NULL)
db->close(db);
free(p);
}
static int
db_servent(void *retval, void *mdata, va_list ap)
{
char buf[BUFSIZ];
DBT key, data;
DB *db;
char *resultbuf;
struct db_state *st;
int rv;
int stayopen;
enum nss_lookup_type how;
char *name;
char *proto;
int port;
struct servent *serv;
char *buffer;
size_t bufsize;
int *errnop;
name = NULL;
proto = NULL;
how = (enum nss_lookup_type)mdata;
switch (how) {
case nss_lt_name:
name = va_arg(ap, char *);
proto = va_arg(ap, char *);
break;
case nss_lt_id:
port = va_arg(ap, int);
proto = va_arg(ap, char *);
break;
case nss_lt_all:
break;
default:
return NS_NOTFOUND;
};
serv = va_arg(ap, struct servent *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap,int *);
*errnop = db_getstate(&st);
if (*errnop != 0)
return (NS_UNAVAIL);
if (how == nss_lt_all && st->keynum < 0)
return (NS_NOTFOUND);
if (st->db == NULL) {
st->db = dbopen(_PATH_SERVICES_DB, O_RDONLY, 0, DB_HASH, NULL);
if (st->db == NULL) {
*errnop = errno;
return (NS_UNAVAIL);
}
}
stayopen = (how == nss_lt_all) ? 1 : st->stayopen;
db = st->db;
do {
switch (how) {
case nss_lt_name:
key.data = buf;
if (proto == NULL)
key.size = snprintf(buf, sizeof(buf),
"\376%s", name);
else
key.size = snprintf(buf, sizeof(buf),
"\376%s/%s", name, proto);
key.size++;
if (db->get(db, &key, &data, 0) != 0 ||
db->get(db, &data, &key, 0) != 0) {
rv = NS_NOTFOUND;
goto db_fin;
}
resultbuf = key.data;
break;
case nss_lt_id:
key.data = buf;
port = htons(port);
if (proto == NULL)
key.size = snprintf(buf, sizeof(buf),
"\377%d", port);
else
key.size = snprintf(buf, sizeof(buf),
"\377%d/%s", port, proto);
key.size++;
if (db->get(db, &key, &data, 0) != 0 ||
db->get(db, &data, &key, 0) != 0) {
rv = NS_NOTFOUND;
goto db_fin;
}
resultbuf = key.data;
break;
case nss_lt_all:
key.data = buf;
key.size = snprintf(buf, sizeof(buf), "%d",
st->keynum++);
key.size++;
if (db->get(db, &key, &data, 0) != 0) {
st->keynum = -1;
rv = NS_NOTFOUND;
goto db_fin;
}
resultbuf = data.data;
break;
}
rv = parse_result(serv, buffer, bufsize, resultbuf,
strlen(resultbuf), errnop);
} while (!(rv & NS_TERMINATE) && how == nss_lt_all);
db_fin:
if (!stayopen && st->db != NULL) {
db->close(db);
st->db = NULL;
}
if (rv == NS_SUCCESS && retval != NULL)
*(struct servent **)retval = serv;
return (rv);
}
static int
db_setservent(void *retval, void *mdata, va_list ap)
{
DB *db;
struct db_state *st;
int rv;
int f;
rv = db_getstate(&st);
if (rv != 0)
return (NS_UNAVAIL);
switch ((enum constants)mdata) {
case SETSERVENT:
f = va_arg(ap, int);
st->stayopen |= f;
st->keynum = 0;
break;
case ENDSERVENT:
db = st->db;
if (db != NULL) {
db->close(db);
st->db = NULL;
}
st->stayopen = 0;
break;
default:
break;
};
return (NS_UNAVAIL);
}
/* nis backend implementation */
#ifdef YP
static void
@ -638,6 +834,7 @@ compat_setservent(void *retval, void *mdata, va_list ap)
{ NULL, 0 }
};
ns_dtab compat_dtab[] = {
{ NSSRC_DB, db_setservent, mdata },
#ifdef YP
{ NSSRC_NIS, nis_setservent, mdata },
#endif
@ -924,6 +1121,7 @@ getservbyname_r(const char *name, const char *proto, struct servent *serv,
#endif /* NS_CACHING */
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_servent, (void *)&mdata },
{ NSSRC_DB, db_servent, (void *)nss_lt_name },
#ifdef YP
{ NSSRC_NIS, nis_servent, (void *)nss_lt_name },
#endif
@ -960,6 +1158,7 @@ getservbyport_r(int port, const char *proto, struct servent *serv,
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_servent, (void *)&mdata },
{ NSSRC_DB, db_servent, (void *)nss_lt_id },
#ifdef YP
{ NSSRC_NIS, nis_servent, (void *)nss_lt_id },
#endif
@ -995,6 +1194,7 @@ getservent_r(struct servent *serv, char *buffer, size_t bufsize,
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_servent, (void *)&mdata },
{ NSSRC_DB, db_servent, (void *)nss_lt_all },
#ifdef YP
{ NSSRC_NIS, nis_servent, (void *)nss_lt_all },
#endif
@ -1027,6 +1227,7 @@ setservent(int stayopen)
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_setservent, (void *)SETSERVENT },
{ NSSRC_DB, db_setservent, (void *)SETSERVENT },
#ifdef YP
{ NSSRC_NIS, nis_setservent, (void *)SETSERVENT },
#endif
@ -1051,6 +1252,7 @@ endservent()
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_setservent, (void *)ENDSERVENT },
{ NSSRC_DB, db_setservent, (void *)ENDSERVENT },
#ifdef YP
{ NSSRC_NIS, nis_setservent, (void *)ENDSERVENT },
#endif

View File

@ -32,7 +32,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd January 22, 2007
.Dd April 4, 2010
.Dt NSDISPATCH 3
.Os
.Sh NAME
@ -176,6 +176,7 @@ While there is support for arbitrary sources, the following
.Bl -column NSSRC_COMPAT compat -offset indent
.It Sy "#define value"
.It Dv NSSRC_FILES Ta """files""
.It Dv NSSRC_DB Ta """db""
.It Dv NSSRC_DNS Ta """dns""
.It Dv NSSRC_NIS Ta """nis""
.It Dv NSSRC_COMPAT Ta """compat""

View File

@ -33,7 +33,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd December 23, 2008
.Dd April 4, 2010
.Dt NSSWITCH.CONF 5
.Os
.Sh NAME
@ -72,6 +72,8 @@ Local files, such as
.Pa /etc/hosts ,
and
.Pa /etc/passwd .
.It db
Local database.
.It dns
Internet Domain Name System.
.Dq hosts

View File

@ -32,7 +32,7 @@
.\" @(#)services.5 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
.Dd June 5, 1993
.Dd April 4, 2010
.Dt SERVICES 5
.Os
.Sh NAME
@ -65,6 +65,18 @@ not interpreted by the routines which search the file.
Service names may contain any printable
character other than a field delimiter, newline,
or comment character.
.Pp
If
.Dq db
is specified as source in the
.Xr nsswitch.conf 5 ,
.Pa /var/db/services.db
is searched.
The database in
.Pa /var/db/services.db
needs to be updated with
.Xr services_mkdb 8
after changes to the services file have been applied.
.Sh NIS INTERACTION
Access to the NIS
.Pa services.byname
@ -84,6 +96,8 @@ file resides in
.El
.Sh SEE ALSO
.Xr getservent 3
.Xr nsswitch.conf 5
.Xr services_mkdb 8
.Sh HISTORY
The
.Nm