summaryrefslogtreecommitdiff
path: root/libexec/identd
diff options
context:
space:
mode:
authorpeter <peter@NetBSD.org>2005-04-03 22:15:32 +0000
committerpeter <peter@NetBSD.org>2005-04-03 22:15:32 +0000
commitf90aa792d58d794fb09f1e272f12b4db6e20f7d0 (patch)
treea678bb8f8c260a099ebdb63552b012b17600c53e /libexec/identd
parentc3582b4d147d6a9b039a3b82d5bb1cc26b154b38 (diff)
Add forward/proxy support to identd(8).
Approved by christos.
Diffstat (limited to 'libexec/identd')
-rw-r--r--libexec/identd/Makefile19
-rw-r--r--libexec/identd/identd.851
-rw-r--r--libexec/identd/identd.c409
-rw-r--r--libexec/identd/identd.h27
-rw-r--r--libexec/identd/ipf.c97
-rw-r--r--libexec/identd/pf.c101
6 files changed, 637 insertions, 67 deletions
diff --git a/libexec/identd/Makefile b/libexec/identd/Makefile
index 2462ab6f6c8..8f6c2199ee4 100644
--- a/libexec/identd/Makefile
+++ b/libexec/identd/Makefile
@@ -1,7 +1,22 @@
-# $NetBSD: Makefile,v 1.10 2004/01/31 21:47:17 christos Exp $
+# $NetBSD: Makefile,v 1.11 2005/04/03 22:15:32 peter Exp $
-WARNS=3
+.include <bsd.own.mk>
+
+WARNS= 4
PROG= identd
+SRCS= identd.c
MAN= identd.8
+# Build with IP Filter support?
+.if (${MKIPFILTER} != "no")
+SRCS+= ipf.c
+CPPFLAGS+=-I${NETBSDSRCDIR}/sys/dist/ipf -DWITH_IPF
+.endif
+
+# Build with pf support?
+.if (${MKPF} != "no")
+SRCS+= pf.c
+CPPFLAGS+=-DWITH_PF
+.endif
+
.include <bsd.prog.mk>
diff --git a/libexec/identd/identd.8 b/libexec/identd/identd.8
index 27f567022af..e09ca2b1c92 100644
--- a/libexec/identd/identd.8
+++ b/libexec/identd/identd.8
@@ -1,9 +1,9 @@
-.\" $NetBSD: identd.8,v 1.18 2004/01/31 22:39:24 wiz Exp $
+.\" $NetBSD: identd.8,v 1.19 2005/04/03 22:15:32 peter Exp $
.\"
.\" This software is in the public domain.
-.\" Written by Peter Postma <peter@pointless.nl>
+.\" Written by Peter Postma <peter@NetBSD.org>
.\"
-.Dd January 31, 2004
+.Dd March 22, 2005
.Dt IDENTD 8
.Os
.Sh NAME
@@ -18,7 +18,9 @@
.Op Fl f Ar fallback
.Op Fl g Ar uid
.Op Fl L Ar username
+.Op Fl m Ar filter
.Op Fl o Ar osname
+.Op Fl P Ar address
.Op Fl p Ar portno
.Op Fl t Ar seconds
.Op Fl u Ar uid
@@ -95,7 +97,8 @@ Specify a
.Ar fallback
username.
If the lookup fails then this username will be returned.
-This can be useful for when running this service on a NAT host.
+This can be useful for when running this service on a NAT host and
+not using the forward/proxy functionality.
.It Fl g Ar gid
Specify the group id number or name which the server should switch to after
binding itself to the TCP/IP port.
@@ -122,6 +125,40 @@ Return this name for all ident requests.
Use
.Xr syslogd 8
for logging.
+.It Fl m Ar filter
+Enables forwarding of ident queries.
+The
+.Ar filter
+argument specifies which packet filter should be used to lookup the
+connections, currently
+.Sq pf
+and
+.Sq ipfilter
+are supported packet filters.
+Note that
+.Nm
+changes the ident queries to use the local port on the NAT host instead of
+the local port on the forwarding host.
+This is needed because otherwise we can't do a lookup on the proxy host.
+On the proxy host,
+.Dq proxy mode
+should be enabled with the
+.Fl P
+flag or
+.Dq lying mode
+with the
+.Fl L
+flag.
+.Nm
+will need access to
+.Pa /etc/pf
+or
+.Pa /etc/ipnat
+so you either need to run
+.Nm
+under root or adjust group owner/permissions to the device(s) and run
+.Nm
+under that group.
.It Fl N
Enable
.Pa .noident
@@ -136,6 +173,12 @@ Return
.Ar osname
instead of the default
.Dq UNIX .
+.It Fl P Ar address
+Specify a proxy server which will be used to receive proxied ident
+queries from.
+See also the
+.Fl m
+flag how this operates.
.It Fl p Ar portno
Specify an alternative port number under which the server should run.
The default is port 113.
diff --git a/libexec/identd/identd.c b/libexec/identd/identd.c
index cca112d53ab..e52cab259c8 100644
--- a/libexec/identd/identd.c
+++ b/libexec/identd/identd.c
@@ -1,10 +1,10 @@
-/* $NetBSD: identd.c,v 1.25 2005/03/11 15:49:52 peter Exp $ */
+/* $NetBSD: identd.c,v 1.26 2005/04/03 22:15:32 peter Exp $ */
/*
* identd.c - TCP/IP Ident protocol server.
*
* This software is in the public domain.
- * Written by Peter Postma <peter@pointless.nl>
+ * Written by Peter Postma <peter@NetBSD.org>
*/
#include <sys/types.h>
@@ -38,19 +38,26 @@
#include <syslog.h>
#include <unistd.h>
-__RCSID("$NetBSD: identd.c,v 1.25 2005/03/11 15:49:52 peter Exp $");
+#include "identd.h"
+
+__RCSID("$NetBSD: identd.c,v 1.26 2005/04/03 22:15:32 peter Exp $");
#define OPSYS_NAME "UNIX"
#define IDENT_SERVICE "auth"
#define TIMEOUT 30 /* seconds */
static int idhandle(int, const char *, const char *, const char *,
- const char *, int);
+ const char *, struct sockaddr *, int);
static void idparse(int, int, int, const char *, const char *, const char *);
static void iderror(int, int, int, const char *);
-static const char *gethost(struct sockaddr_storage *);
+static const char *gethost(struct sockaddr *);
static int *socketsetup(const char *, const char *, int);
+static int ident_getuid(struct sockaddr_storage *, socklen_t,
+ struct sockaddr *, uid_t *);
static int sysctl_getuid(struct sockaddr_storage *, socklen_t, uid_t *);
+static int sysctl_proxy_getuid(struct sockaddr_storage *,
+ struct sockaddr *, uid_t *);
+static int forward(int, struct sockaddr *, int, int, int);
static int check_noident(const char *);
static int check_userident(const char *, char *, size_t);
static void random_string(char *, size_t);
@@ -58,18 +65,37 @@ static int change_format(const char *, struct passwd *, char *, size_t);
static void timeout_handler(int);
static void waitchild(int);
static void fatal(const char *);
-static void maybe_syslog(int, const char *, ...);
+static void die(const char *, ...);
static int bflag, eflag, fflag, Fflag, iflag, Iflag;
static int lflag, Lflag, nflag, Nflag, rflag;
+/* NAT lookup function pointer. */
+static int (*nat_lookup)(struct sockaddr_storage *, struct sockaddr *, int *);
+
+/* Packet filters. */
+static const struct {
+ const char *name;
+ int (*fn)(struct sockaddr_storage *, struct sockaddr *, int *);
+} filters[] = {
+#ifdef WITH_PF
+ { "pf", pf_natlookup },
+#endif
+#ifdef WITH_IPF
+ { "ipfilter", ipf_natlookup },
+#endif
+ { NULL, NULL }
+};
+
int
main(int argc, char *argv[])
{
- int IPv4or6, ch, *socks, timeout;
+ int IPv4or6, ch, error, i, *socks, timeout;
+ const char *filter, *osname, *portno, *proxy;
char *address, *charset, *fmt, *p;
- const char *osname, *portno;
char user[LOGIN_NAME_MAX];
+ struct addrinfo *ai, hints;
+ struct sockaddr *proxy_addr;
struct group *grp;
struct passwd *pw;
gid_t gid;
@@ -79,6 +105,9 @@ main(int argc, char *argv[])
osname = OPSYS_NAME;
portno = IDENT_SERVICE;
timeout = TIMEOUT;
+ nat_lookup = NULL;
+ proxy_addr = NULL;
+ filter = proxy = NULL;
address = charset = fmt = NULL;
uid = gid = 0;
bflag = eflag = fflag = Fflag = iflag = Iflag = 0;
@@ -89,7 +118,8 @@ main(int argc, char *argv[])
bflag = 1;
/* Parse command line arguments. */
- while ((ch = getopt(argc, argv, "46a:bceF:f:g:IiL:lNno:p:rt:u:")) != -1)
+ while ((ch = getopt(argc, argv,
+ "46a:bceF:f:g:IiL:lm:Nno:P:p:rt:u:")) != -1) {
switch (ch) {
case '4':
IPv4or6 = AF_INET;
@@ -123,8 +153,7 @@ main(int argc, char *argv[])
if ((grp = getgrnam(optarg)) != NULL)
gid = grp->gr_gid;
else
- errx(EXIT_FAILURE,
- "No such group '%s'", optarg);
+ die("No such group `%s'", optarg);
}
break;
case 'I':
@@ -138,8 +167,13 @@ main(int argc, char *argv[])
(void)strlcpy(user, optarg, sizeof(user));
break;
case 'l':
+ if (!lflag)
+ openlog("identd", LOG_PID, LOG_DAEMON);
lflag = 1;
break;
+ case 'm':
+ filter = optarg;
+ break;
case 'N':
Nflag = 1;
break;
@@ -149,6 +183,9 @@ main(int argc, char *argv[])
case 'o':
osname = optarg;
break;
+ case 'P':
+ proxy = optarg;
+ break;
case 'p':
portno = optarg;
break;
@@ -157,9 +194,8 @@ main(int argc, char *argv[])
break;
case 't':
timeout = (int)strtol(optarg, &p, 0);
- if (*p != '\0')
- errx(EXIT_FAILURE,
- "Invalid timeout value '%s'", optarg);
+ if (*p != '\0' || timeout < 1)
+ die("Invalid timeout value `%s'", optarg);
break;
case 'u':
uid = (uid_t)strtol(optarg, &p, 0);
@@ -168,34 +204,49 @@ main(int argc, char *argv[])
uid = pw->pw_uid;
gid = pw->pw_gid;
} else
- errx(EXIT_FAILURE,
- "No such user '%s'", optarg);
+ die("No such user `%s'", optarg);
}
break;
default:
exit(EXIT_FAILURE);
}
+ }
- if (lflag)
- openlog("identd", LOG_PID, LOG_DAEMON);
+ /* Verify proxy address, if enabled. */
+ if (proxy != NULL) {
+ (void)memset(&hints, 0, sizeof(hints));
+ hints.ai_family = IPv4or6;
+ hints.ai_socktype = SOCK_STREAM;
+ error = getaddrinfo(proxy, NULL, &hints, &ai);
+ if (error != 0)
+ die("Bad proxy `%s': %s", proxy, gai_strerror(error));
+ if (ai->ai_next != NULL)
+ die("Bad proxy `%s': resolves to multiple addresses",
+ proxy);
+ proxy_addr = ai->ai_addr;
+ }
+
+ /* Verify filter, if enabled. */
+ if (filter != NULL) {
+ for (i = 0; filters[i].name != NULL; i++) {
+ if (strcasecmp(filter, filters[i].name) == 0) {
+ nat_lookup = filters[i].fn;
+ break;
+ }
+ }
+ if (nat_lookup == NULL)
+ die("Packet filter `%s' is not supported", filter);
+ }
/* Setup sockets when running in the background. */
if (bflag)
socks = socketsetup(address, portno, IPv4or6);
/* Switch to another uid/gid? */
- if (gid && setgid(gid) == -1) {
- maybe_syslog(LOG_ERR, "setgid: %m");
- if (bflag)
- warn("setgid");
- exit(EXIT_FAILURE);
- }
- if (uid && setuid(uid) == -1) {
- maybe_syslog(LOG_ERR, "setuid: %m");
- if (bflag)
- warn("setuid");
- exit(EXIT_FAILURE);
- }
+ if (gid && setgid(gid) == -1)
+ die("Failed to set GID to `%d': %s", gid, strerror(errno));
+ if (uid && setuid(uid) == -1)
+ die("Failed to set UID to `%d': %s", uid, strerror(errno));
/*
* When running as daemon: daemonize, setup pollfds and go into
@@ -203,12 +254,12 @@ main(int argc, char *argv[])
* let inetd handle the sockets.
*/
if (bflag) {
- int fd, i, nfds, rv;
+ int fd, nfds, rv;
struct pollfd *rfds;
(void)signal(SIGCHLD, waitchild);
if (daemon(0, 0) < 0)
- err(EXIT_FAILURE, "daemon");
+ die("daemon: %s", strerror(errno));
rfds = malloc(*socks * sizeof(struct pollfd));
if (rfds == NULL)
@@ -243,7 +294,8 @@ main(int argc, char *argv[])
break;
case 0: /* child */
(void)idhandle(fd, charset,
- fmt, osname, user, timeout);
+ fmt, osname, user,
+ proxy_addr, timeout);
_exit(EXIT_SUCCESS);
default: /* parent */
(void)close(fd);
@@ -253,14 +305,14 @@ main(int argc, char *argv[])
}
} else
(void)idhandle(STDIN_FILENO, charset, fmt, osname, user,
- timeout);
+ proxy_addr, timeout);
return 0;
}
static int
idhandle(int fd, const char *charset, const char *fmt, const char *osname,
- const char *user, int timeout)
+ const char *user, struct sockaddr *proxy, int timeout)
{
struct sockaddr_storage ss[2];
char userbuf[LOGIN_NAME_MAX]; /* actual user name (or numeric uid) */
@@ -282,7 +334,8 @@ idhandle(int fd, const char *charset, const char *fmt, const char *osname,
if (getpeername(fd, (struct sockaddr *)&ss[0], &len) < 0)
fatal("getpeername");
- maybe_syslog(LOG_INFO, "Connection from %s", gethost(&ss[0]));
+ maybe_syslog(LOG_INFO, "Connection from %s",
+ gethost((struct sockaddr *)&ss[0]));
/* Get local internet address. */
len = sizeof(ss[1]);
@@ -318,7 +371,7 @@ idhandle(int fd, const char *charset, const char *fmt, const char *osname,
/* Are the ports valid? */
if (lport < 1 || lport > 65535 || fport < 1 || fport > 65535) {
maybe_syslog(LOG_NOTICE, "Invalid port(s): %d, %d from %s",
- lport, fport, gethost(&ss[0]));
+ lport, fport, gethost((struct sockaddr *)&ss[0]));
iderror(fd, 0, 0, eflag ? "UNKNOWN-ERROR" : "INVALID-PORT");
return 1;
}
@@ -326,7 +379,7 @@ idhandle(int fd, const char *charset, const char *fmt, const char *osname,
/* If there is a 'lie' user enabled, then handle it now and stop. */
if (Lflag) {
maybe_syslog(LOG_NOTICE, "Lying with name %s to %s",
- idbuf, gethost(&ss[0]));
+ idbuf, gethost((struct sockaddr *)&ss[0]));
idparse(fd, lport, fport, charset, osname, idbuf);
return 0;
}
@@ -334,12 +387,12 @@ idhandle(int fd, const char *charset, const char *fmt, const char *osname,
/* Protocol dependent stuff. */
switch (ss[0].ss_family) {
case AF_INET:
- ((struct sockaddr_in *)&ss[0])->sin_port = htons(fport);
- ((struct sockaddr_in *)&ss[1])->sin_port = htons(lport);
+ satosin(&ss[0])->sin_port = htons(fport);
+ satosin(&ss[1])->sin_port = htons(lport);
break;
case AF_INET6:
- ((struct sockaddr_in6 *)&ss[0])->sin6_port = htons(fport);
- ((struct sockaddr_in6 *)&ss[1])->sin6_port = htons(lport);
+ satosin6(&ss[0])->sin6_port = htons(fport);
+ satosin6(&ss[1])->sin6_port = htons(lport);
break;
default:
maybe_syslog(LOG_ERR, "Unsupported protocol (no. %d)",
@@ -348,14 +401,31 @@ idhandle(int fd, const char *charset, const char *fmt, const char *osname,
}
/* Try to get the UID of the connection owner using sysctl. */
- if (sysctl_getuid(ss, sizeof(ss), &uid) == -1) {
- maybe_syslog(LOG_ERR, "sysctl: %m");
+ if (ident_getuid(ss, sizeof(ss), proxy, &uid) == -1) {
+ /* Lookup failed, try to forward if enabled. */
+ if (nat_lookup != NULL) {
+ struct sockaddr nat_addr;
+ int nat_lport;
+
+ (void)memset(&nat_addr, 0, sizeof(nat_addr));
+
+ if ((*nat_lookup)(ss, &nat_addr, &nat_lport) &&
+ forward(fd, &nat_addr, nat_lport, fport, lport)) {
+ maybe_syslog(LOG_INFO,
+ "Succesfully forwarded the request to %s",
+ gethost(&nat_addr));
+ return 0;
+ }
+ }
+ /* Fall back to a default name? */
if (fflag) {
maybe_syslog(LOG_NOTICE, "Using fallback name %s to %s",
- idbuf, gethost(&ss[0]));
+ idbuf, gethost((struct sockaddr *)&ss[0]));
idparse(fd, lport, fport, charset, osname, idbuf);
return 0;
}
+ maybe_syslog(LOG_ERR, "Lookup failed, returning error to %s",
+ gethost((struct sockaddr *)&ss[0]));
iderror(fd, lport, fport, eflag ? "UNKNOWN-ERROR" : "NO-USER");
return 1;
}
@@ -366,14 +436,15 @@ idhandle(int fd, const char *charset, const char *fmt, const char *osname,
(void)snprintf(userbuf, sizeof(userbuf), "%u", uid);
} else {
maybe_syslog(LOG_INFO, "Successful lookup: %d, %d: %s for %s",
- lport, fport, pw->pw_name, gethost(&ss[0]));
+ lport, fport, pw->pw_name,
+ gethost((struct sockaddr *)&ss[0]));
(void)strlcpy(userbuf, pw->pw_name, sizeof(userbuf));
}
/* No ident enabled? */
if (Nflag && pw && check_noident(pw->pw_dir)) {
maybe_syslog(LOG_NOTICE, "Returning HIDDEN-USER for user %s"
- " to %s", pw->pw_name, gethost(&ss[0]));
+ " to %s", pw->pw_name, gethost((struct sockaddr *)&ss[0]));
iderror(fd, lport, fport, "HIDDEN-USER");
return 1;
}
@@ -390,8 +461,9 @@ idhandle(int fd, const char *charset, const char *fmt, const char *osname,
(void)strlcpy(idbuf, userbuf, sizeof(idbuf));
}
}
- maybe_syslog(LOG_NOTICE, "Returning user-specified '%s' for "
- "user %s to %s", idbuf, userbuf, gethost(&ss[0]));
+ maybe_syslog(LOG_NOTICE,
+ "Returning user-specified '%s' for user %s to %s",
+ idbuf, userbuf, gethost((struct sockaddr *)&ss[0]));
idparse(fd, lport, fport, charset, osname, idbuf);
return 0;
}
@@ -405,8 +477,9 @@ idhandle(int fd, const char *charset, const char *fmt, const char *osname,
else
random_string(idbuf, sizeof(idbuf));
- maybe_syslog(LOG_NOTICE, "Returning random '%s' for user %s"
- " to %s", idbuf, userbuf, gethost(&ss[0]));
+ maybe_syslog(LOG_NOTICE,
+ "Returning random '%s' for user %s to %s",
+ idbuf, userbuf, gethost((struct sockaddr *)&ss[0]));
idparse(fd, lport, fport, charset, osname, idbuf);
return 0;
}
@@ -463,12 +536,12 @@ iderror(int fd, int lport, int fport, const char *error)
/* Return the IP address of the connecting host. */
static const char *
-gethost(struct sockaddr_storage *ss)
+gethost(struct sockaddr *sa)
{
static char host[NI_MAXHOST];
- if (getnameinfo((struct sockaddr *)ss, ss->ss_len, host,
- sizeof(host), NULL, 0, NI_NUMERICHOST) == 0)
+ if (getnameinfo(sa, sa->sa_len, host, sizeof(host),
+ NULL, 0, NI_NUMERICHOST) == 0)
return host;
return "UNKNOWN";
@@ -488,8 +561,7 @@ socketsetup(const char *address, const char *port, int af)
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(address, port, &hints, &res0);
if (error) {
- maybe_syslog(LOG_ERR, "getaddrinfo: %s", gai_strerror(error));
- errx(EXIT_FAILURE, "%s", gai_strerror(error));
+ die("getaddrinfo: %s", gai_strerror(error));
/* NOTREACHED */
}
@@ -499,8 +571,7 @@ socketsetup(const char *address, const char *port, int af)
socks = malloc((maxs + 1) * sizeof(int));
if (socks == NULL) {
- maybe_syslog(LOG_ERR, "malloc: %m");
- err(EXIT_FAILURE, "malloc");
+ die("malloc: %s", strerror(errno));
/* NOTREACHED */
}
@@ -529,8 +600,7 @@ socketsetup(const char *address, const char *port, int af)
if (*socks == 0) {
free(socks);
- maybe_syslog(LOG_ERR, "%s: %m", cause);
- err(EXIT_FAILURE, "%s", cause);
+ die("%s: %s", cause, strerror(errno));
/* NOTREACHED */
}
if (res0)
@@ -539,6 +609,20 @@ socketsetup(const char *address, const char *port, int af)
return socks;
}
+/* UID lookup wrapper. */
+static int
+ident_getuid(struct sockaddr_storage *ss, socklen_t len,
+ struct sockaddr *proxy, uid_t *uid)
+{
+ int rc;
+
+ rc = sysctl_getuid(ss, len, uid);
+ if (rc == -1 && proxy != NULL)
+ rc = sysctl_proxy_getuid(ss, proxy, uid);
+
+ return rc;
+}
+
/* Try to get the UID of the connection owner using sysctl. */
static int
sysctl_getuid(struct sockaddr_storage *ss, socklen_t len, uid_t *uid)
@@ -561,6 +645,190 @@ sysctl_getuid(struct sockaddr_storage *ss, socklen_t len, uid_t *uid)
return 0;
}
+/* Try to get the UID of the connection owner using sysctl (proxy version). */
+static int
+sysctl_proxy_getuid(struct sockaddr_storage *ss, struct sockaddr *proxy,
+ uid_t *uid)
+{
+ struct sockaddr_storage new[2];
+ int i, rc, name[CTL_MAXNAME];
+ struct kinfo_pcb *kp;
+ size_t sz, len;
+ const char *list;
+
+ rc = -1;
+ sz = CTL_MAXNAME;
+ list = NULL;
+
+ /* Retrieve a list of sockets. */
+ switch (ss[0].ss_family) {
+ case AF_INET:
+ /* We only accept queries from the proxy. */
+ if (in_hosteq(satosin(&ss[0])->sin_addr,
+ satosin(proxy)->sin_addr))
+ list = "net.inet.tcp.pcblist";
+ break;
+ case AF_INET6:
+ /* We only accept queries from the proxy. */
+ if (IN6_ARE_ADDR_EQUAL(&satosin6(&ss[0])->sin6_addr,
+ &satosin6(proxy)->sin6_addr))
+ list = "net.inet6.tcp.pcblist";
+ break;
+ default:
+ maybe_syslog(LOG_ERR, "Unsupported protocol for proxy (no. %d)",
+ ss[0].ss_family);
+ }
+ if (list != NULL)
+ rc = sysctlnametomib(list, &name[0], &sz);
+ if (rc == -1)
+ return -1;
+ len = sz;
+
+ name[len++] = PCB_ALL;
+ name[len++] = 0;
+ name[len++] = sizeof(struct kinfo_pcb);
+ name[len++] = INT_MAX;
+
+ kp = NULL;
+ sz = 0;
+ do {
+ rc = sysctl(&name[0], len, kp, &sz, NULL, 0);
+ if (rc == -1 && errno != ENOMEM)
+ return -1;
+ if (kp == NULL) {
+ kp = malloc(sz);
+ rc = -1;
+ }
+ if (kp == NULL)
+ return -1;
+ } while (rc == -1);
+
+ rc = -1;
+ /*
+ * Walk through the list of sockets and try to find a match.
+ * We don't know who has sent the query (we only know that the
+ * proxy has forwarded to us) so just try to match the ports and
+ * the local address.
+ */
+ for (i = 0; i < sz / sizeof(struct kinfo_pcb); i++) {
+ switch (ss[0].ss_family) {
+ case AF_INET:
+ /* Foreign and local ports must match. */
+ if (satosin(&ss[0])->sin_port !=
+ satosin(&kp[i].ki_src)->sin_port)
+ continue;
+ if (satosin(&ss[1])->sin_port !=
+ satosin(&kp[i].ki_dst)->sin_port)
+ continue;
+ /* Foreign address may not match proxy address. */
+ if (in_hosteq(satosin(proxy)->sin_addr,
+ satosin(&kp[i].ki_dst)->sin_addr))
+ continue;
+ /* Local addresses must match. */
+ if (!in_hosteq(satosin(&ss[1])->sin_addr,
+ satosin(&kp[i].ki_src)->sin_addr))
+ continue;
+ break;
+ case AF_INET6:
+ /* Foreign and local ports must match. */
+ if (satosin6(&ss[0])->sin6_port !=
+ satosin6(&kp[i].ki_src)->sin6_port)
+ continue;
+ if (satosin6(&ss[1])->sin6_port !=
+ satosin6(&kp[i].ki_dst)->sin6_port)
+ continue;
+ /* Foreign address may not match proxy address. */
+ if (IN6_ARE_ADDR_EQUAL(&satosin6(proxy)->sin6_addr,
+ &satosin6(&kp[i].ki_dst)->sin6_addr))
+ continue;
+ /* Local addresses must match. */
+ if (!IN6_ARE_ADDR_EQUAL(&satosin6(&ss[1])->sin6_addr,
+ &satosin6(&kp[i].ki_src)->sin6_addr))
+ continue;
+ break;
+ }
+
+ /*
+ * We have found the foreign address, copy it to a new
+ * struct and retrieve the UID of the connection owner.
+ */
+ (void)memcpy(&new[0], &kp[i].ki_dst, kp[i].ki_dst.sa_len);
+ (void)memcpy(&new[1], &kp[i].ki_src, kp[i].ki_src.sa_len);
+
+ rc = sysctl_getuid(new, sizeof(new), uid);
+
+ /* Done. */
+ break;
+ }
+
+ free(kp);
+ return rc;
+}
+
+/* Forward ident queries. Returns 1 when succesful, or zero if not. */
+static int
+forward(int fd, struct sockaddr *nat_addr, int nat_lport, int fport, int lport)
+{
+ char buf[BUFSIZ], reply[BUFSIZ], *p;
+ int sock, n;
+
+ /* Connect to the NAT host. */
+ sock = socket(nat_addr->sa_family, SOCK_STREAM, 0);
+ if (sock < 0) {
+ maybe_syslog(LOG_ERR, "socket: %m");
+ return 0;
+ }
+ if (connect(sock, nat_addr, nat_addr->sa_len) < 0) {
+ maybe_syslog(LOG_ERR, "Can't connect to %s: %m",
+ gethost(nat_addr));
+ (void)close(sock);
+ return 0;
+ }
+
+ /*
+ * Send the ident query to the NAT host, but use as local port
+ * the port of the NAT host.
+ */
+ (void)snprintf(buf, sizeof(buf), "%d , %d\r\n", nat_lport, fport);
+ if (send(sock, buf, strlen(buf), 0) < 0) {
+ maybe_syslog(LOG_ERR, "send: %m");
+ (void)close(sock);
+ return 0;
+ }
+
+ /* Read the reply from the NAT host. */
+ if ((n = recv(sock, reply, sizeof(reply) - 1, 0)) < 0) {
+ maybe_syslog(LOG_ERR, "recv: %m");
+ (void)close(sock);
+ return 0;
+ } else if (n == 0) {
+ maybe_syslog(LOG_NOTICE, "recv: EOF");
+ (void)close(sock);
+ return 0;
+ }
+ reply[n] = '\0';
+ (void)close(sock);
+
+ /* Extract everything after the port specs from the ident reply. */
+ for (p = reply; *p != '\0' && *p != ':'; p++)
+ continue;
+ if (*p == '\0' || *++p == '\0') {
+ maybe_syslog(LOG_ERR, "Malformed ident reply from %s",
+ gethost(nat_addr));
+ return 0;
+ }
+ /* Build reply for the requesting host, use the original local port. */
+ (void)snprintf(buf, sizeof(buf), "%d,%d:%s", lport, fport, p);
+
+ /* Send the reply from the NAT host back to the requesting host. */
+ if (send(fd, buf, strlen(buf), 0) < 0) {
+ maybe_syslog(LOG_ERR, "send: %m");
+ return 0;
+ }
+
+ return 1;
+}
+
/* Check if a .noident file exists in the user home directory. */
static int
check_noident(const char *homedir)
@@ -753,8 +1021,27 @@ fatal(const char *func)
exit(EXIT_FAILURE);
}
-/* Log using syslog, but only if enabled with the -l flag. */
+/*
+ * Report an error through syslog and/or stderr and quit. Only used when
+ * running identd in the background and when it isn't a daemon yet.
+ */
static void
+die(const char *message, ...)
+{
+ va_list ap;
+
+ va_start(ap, message);
+ if (bflag)
+ vwarnx(message, ap);
+ if (lflag)
+ vsyslog(LOG_ERR, message, ap);
+ va_end(ap);
+
+ exit(EXIT_FAILURE);
+}
+
+/* Log using syslog, but only if enabled with the -l flag. */
+void
maybe_syslog(int priority, const char *message, ...)
{
va_list ap;
diff --git a/libexec/identd/identd.h b/libexec/identd/identd.h
new file mode 100644
index 00000000000..63c92e91e94
--- /dev/null
+++ b/libexec/identd/identd.h
@@ -0,0 +1,27 @@
+/* $NetBSD: identd.h,v 1.8 2005/04/03 22:15:32 peter Exp $ */
+
+/*
+ * identd.h - TCP/IP Ident protocol server.
+ *
+ * This software is in the public domain.
+ * Written by Peter Postma <peter@NetBSD.org>
+ */
+
+#ifndef _IDENTD_H_
+#define _IDENTD_H_
+
+#define satosin(sa) ((struct sockaddr_in *)(sa))
+#define satosin6(sa) ((struct sockaddr_in6 *)(sa))
+#define in_hosteq(s,t) ((s).s_addr == (t).s_addr)
+
+void maybe_syslog(int, const char *, ...);
+
+#ifdef WITH_PF
+int pf_natlookup(struct sockaddr_storage *, struct sockaddr *, int *);
+#endif
+
+#ifdef WITH_IPF
+int ipf_natlookup(struct sockaddr_storage *, struct sockaddr *, int *);
+#endif
+
+#endif /* !_IDENTD_H_ */
diff --git a/libexec/identd/ipf.c b/libexec/identd/ipf.c
new file mode 100644
index 00000000000..edbcd1c7f40
--- /dev/null
+++ b/libexec/identd/ipf.c
@@ -0,0 +1,97 @@
+/* $NetBSD: ipf.c,v 1.1 2005/04/03 22:15:32 peter Exp $ */
+
+/*
+ * ipf.c - NAT lookup code for IP Filter.
+ *
+ * This software is in the public domain.
+ * Written by Peter Postma <peter@NetBSD.org>
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/fcntl.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ipl.h>
+#include <netinet/ip_compat.h>
+#include <netinet/ip_fil.h>
+#include <netinet/ip_nat.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "identd.h"
+
+int
+ipf_natlookup(struct sockaddr_storage *ss, struct sockaddr *nat_addr,
+ int *nat_lport)
+{
+ natlookup_t nl;
+ ipfobj_t obj;
+ int dev;
+
+ (void)memset(&obj, 0, sizeof(obj));
+ (void)memset(&nl, 0, sizeof(nl));
+
+ /* Build the ipf object description structure. */
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_size = sizeof(nl);
+ obj.ipfo_ptr = &nl;
+ obj.ipfo_type = IPFOBJ_NATLOOKUP;
+
+ /* Build the ipf natlook structure. */
+ switch (ss[0].ss_family) {
+ case AF_INET:
+ (void)memcpy(&nl.nl_realip, &satosin(&ss[0])->sin_addr,
+ sizeof(struct in_addr));
+ (void)memcpy(&nl.nl_outip, &satosin(&ss[1])->sin_addr,
+ sizeof(struct in_addr));
+ nl.nl_realport = ntohs(satosin(&ss[0])->sin_port);
+ nl.nl_outport = ntohs(satosin(&ss[1])->sin_port);
+ nl.nl_flags = IPN_TCP | IPN_IN;
+ break;
+ case AF_INET6:
+ /* XXX IP Filter doesn't support IPv6 NAT yet. */
+ default:
+ maybe_syslog(LOG_ERR, "Unsupported protocol for NAT lookup "
+ "(no. %d)", ss[0].ss_family);
+ return 0;
+ }
+
+ /* Open the NAT device and do the lookup. */
+ if ((dev = open(IPNAT_NAME, O_RDONLY)) == -1) {
+ maybe_syslog(LOG_ERR, "Cannot open %s: %m", IPNAT_NAME);
+ return 0;
+ }
+ if (ioctl(dev, SIOCGNATL, &obj) == -1) {
+ maybe_syslog(LOG_ERR, "NAT lookup failure: %m");
+ (void)close(dev);
+ return 0;
+ }
+ (void)close(dev);
+
+ /*
+ * Put the originating address into nat_addr and fill
+ * the port with the ident port, 113.
+ */
+ switch (ss[0].ss_family) {
+ case AF_INET:
+ (void)memcpy(&satosin(nat_addr)->sin_addr, &nl.nl_inip,
+ sizeof(struct in_addr));
+ satosin(nat_addr)->sin_port = htons(113);
+ satosin(nat_addr)->sin_len = sizeof(struct sockaddr_in);
+ satosin(nat_addr)->sin_family = AF_INET;
+ break;
+ case AF_INET6:
+ break;
+ }
+ /* Put the originating port into nat_lport. */
+ *nat_lport = nl.nl_inport;
+
+ return 1;
+}
diff --git a/libexec/identd/pf.c b/libexec/identd/pf.c
new file mode 100644
index 00000000000..9c8c04ad134
--- /dev/null
+++ b/libexec/identd/pf.c
@@ -0,0 +1,101 @@
+/* $NetBSD: pf.c,v 1.1 2005/04/03 22:15:32 peter Exp $ */
+
+/*
+ * pf.c - NAT lookup code for pf.
+ *
+ * This software is in the public domain.
+ * Written by Peter Postma <peter@NetBSD.org>
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/fcntl.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/pfvar.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "identd.h"
+
+int
+pf_natlookup(struct sockaddr_storage *ss, struct sockaddr *nat_addr,
+ int *nat_lport)
+{
+ struct pfioc_natlook nl;
+ int dev;
+
+ (void)memset(&nl, 0, sizeof(nl));
+
+ /* Build the pf natlook structure. */
+ switch (ss[0].ss_family) {
+ case AF_INET:
+ (void)memcpy(&nl.daddr.v4, &satosin(&ss[0])->sin_addr,
+ sizeof(struct in_addr));
+ (void)memcpy(&nl.saddr.v4, &satosin(&ss[1])->sin_addr,
+ sizeof(struct in_addr));
+ nl.dport = satosin(&ss[0])->sin_port;
+ nl.sport = satosin(&ss[1])->sin_port;
+ nl.af = AF_INET;
+ nl.proto = IPPROTO_TCP;
+ nl.direction = PF_IN;
+ break;
+ case AF_INET6:
+ (void)memcpy(&nl.daddr.v6, &satosin6(&ss[0])->sin6_addr,
+ sizeof(struct in6_addr));
+ (void)memcpy(&nl.saddr.v6, &satosin6(&ss[1])->sin6_addr,
+ sizeof(struct in6_addr));
+ nl.dport = satosin6(&ss[0])->sin6_port;
+ nl.sport = satosin6(&ss[1])->sin6_port;
+ nl.af = AF_INET6;
+ nl.proto = IPPROTO_TCP;
+ nl.direction = PF_IN;
+ break;
+ default:
+ maybe_syslog(LOG_ERR, "Unsupported protocol for NAT lookup "
+ "(no. %d)", ss[0].ss_family);
+ return 0;
+ }
+
+ /* Open the /dev/pf device and do the lookup. */
+ if ((dev = open("/dev/pf", O_RDWR)) == -1) {
+ maybe_syslog(LOG_ERR, "Cannot open /dev/pf: %m");
+ return 0;
+ }
+ if (ioctl(dev, DIOCNATLOOK, &nl) == -1) {
+ maybe_syslog(LOG_ERR, "NAT lookup failure: %m");
+ (void)close(dev);
+ return 0;
+ }
+ (void)close(dev);
+
+ /*
+ * Put the originating address into nat_addr and fill
+ * the port with the ident port, 113.
+ */
+ switch (ss[0].ss_family) {
+ case AF_INET:
+ (void)memcpy(&satosin(nat_addr)->sin_addr, &nl.rsaddr.v4,
+ sizeof(struct in_addr));
+ satosin(nat_addr)->sin_port = htons(113);
+ satosin(nat_addr)->sin_len = sizeof(struct sockaddr_in);
+ satosin(nat_addr)->sin_family = AF_INET;
+ break;
+ case AF_INET6:
+ (void)memcpy(&satosin6(nat_addr)->sin6_addr, &nl.rsaddr.v6,
+ sizeof(struct in6_addr));
+ satosin6(nat_addr)->sin6_port = htons(113);
+ satosin6(nat_addr)->sin6_len = sizeof(struct sockaddr_in6);
+ satosin6(nat_addr)->sin6_family = AF_INET6;
+ break;
+ }
+ /* Put the originating port into nat_lport. */
+ *nat_lport = nl.rsport;
+
+ return 1;
+}