summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/inetd/inetd.870
-rw-r--r--usr.sbin/inetd/inetd.c105
-rw-r--r--usr.sbin/inetd/inetd.h6
3 files changed, 169 insertions, 12 deletions
diff --git a/usr.sbin/inetd/inetd.8 b/usr.sbin/inetd/inetd.8
index 937aa8d..5b0b30b 100644
--- a/usr.sbin/inetd/inetd.8
+++ b/usr.sbin/inetd/inetd.8
@@ -200,7 +200,10 @@ The
.Em service-name
entry is the name of a valid service in
the file
-.Pa /etc/services .
+.Pa /etc/services ,
+or the specification of a
+.Ux
+domain socket (see below).
For
.Dq internal
services (discussed below), the service
@@ -250,7 +253,8 @@ TCPMUX services must use
.Pp
The
.Em protocol
-must be a valid protocol.
+must be a valid protocol or
+.Dq unix .
Examples are
.Dq tcp
or
@@ -580,6 +584,7 @@ records its process ID in the file
.Pa /var/run/inetd.pid
to assist in reconfiguration.
.Sh IMPLEMENTATION NOTES
+.Ss TCP Wrappers
When given the
.Fl w
option,
@@ -682,6 +687,66 @@ If an invalid IPsec policy specifier appears in
will provide an error message via the
.Xr syslog 3
interface and abort execution.
+.Ss Ux Domain Sockets
+In addition to running services on IP sockets,
+.Nm
+can also manage
+.Ux
+domain sockets.
+To do this you specify a
+.Em protocol
+of
+.Dq unix
+and specify the unix domain socket as the
+.Em service-name .
+The
+.Em service-type
+may be
+.Dq stream
+or
+.Dq dgram .
+The specification of the socket must be
+an absolute path name,
+optionally prefixed by an owner and mode
+of the form
+.Em :user:group:mode: .
+The specification:
+.Bd -literal -offset indent -compact
+:news:daemon:220:/var/run/sock
+.Ed
+creates a socket owned
+by user news in group daemon
+with permissions allowing only that user and group to connect.
+The default owner is the user that inetd is running as.
+The default mode only allows the socket's owner to connect.
+.Pp
+.Sy WARNING:
+while creating
+.Ux
+domain socket
+.Nm
+must change the ownership and permissions on the socket.
+This can only be done securely if
+the directory in which the socket is created
+is writable only by root.
+Do
+.Sy NOT
+use
+.Nm
+to create sockets in world writable directories,
+such as
+.Pa /tmp ,
+instead use
+.Pa /var/run
+or a similar directory.
+.Pp
+Internal services may be run on
+.Ux
+domain sockets, in the usual way.
+In this case
+the name of the internal service
+is determined using
+the last component of the socket's pathname.
.Sh "FILES"
.Bl -tag -width /var/run/inetd.pid -compact
.It Pa /etc/inetd.conf
@@ -705,6 +770,7 @@ shell stream tcp46 nowait root /usr/libexec/rshd rshd
tcpmux/+date stream tcp nowait guest /bin/date date
tcpmux/phonebook stream tcp nowait guest /usr/local/bin/phonebook phonebook
rstatd/1-3 dgram rpc/udp wait root /usr/libexec/rpc.rstatd rpc.rstatd
+/var/run/echo stream unix nowait root internal
#@ ipsec ah/require
chargen stream tcp nowait root internal
#@
diff --git a/usr.sbin/inetd/inetd.c b/usr.sbin/inetd/inetd.c
index eca4749..61945dc 100644
--- a/usr.sbin/inetd/inetd.c
+++ b/usr.sbin/inetd/inetd.c
@@ -68,10 +68,11 @@ static const char rcsid[] =
* order shown below. Continuation lines for an entry must begin with
* a space or tab. All fields must be present in each entry.
*
- * service name must be in /etc/services or must
- * name a tcpmux service
+ * service name must be in /etc/services
+ * or name a tcpmux service
+ * or specify a unix domain socket
* socket type stream/dgram/raw/rdm/seqpacket
- * protocol tcp[4][6][/faith,ttcp], udp[4][6]
+ * protocol tcp[4][6][/faith,ttcp], udp[4][6], unix
* wait/nowait single-threaded/multi-threaded
* user user to run daemon as
* server program full path name
@@ -115,6 +116,8 @@ static const char rcsid[] =
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
@@ -169,6 +172,7 @@ static const char rcsid[] =
#define ISWRAP(sep) \
( ((wrap_ex && !(sep)->se_bi) || (wrap_bi && (sep)->se_bi)) \
+ && (sep->se_family == AF_INET || sep->se_family == AF_INET6) \
&& ( ((sep)->se_accept && (sep)->se_socktype == SOCK_STREAM) \
|| (sep)->se_socktype == SOCK_DGRAM))
@@ -226,6 +230,9 @@ int signalpipe[2];
#ifdef SANITY_CHECK
int nsock;
#endif
+uid_t euid;
+gid_t egid;
+mode_t mask;
struct servtab *servtab;
@@ -403,6 +410,10 @@ main(argc, argv, envp)
exit(EX_USAGE);
}
+ euid = geteuid();
+ egid = getegid();
+ umask(mask = umask(0777));
+
argc -= optind;
argv += optind;
@@ -898,6 +909,7 @@ void config()
for (sep = servtab; sep; sep = sep->se_next)
if (strcmp(sep->se_service, new->se_service) == 0 &&
strcmp(sep->se_proto, new->se_proto) == 0 &&
+ sep->se_socktype == new->se_socktype &&
sep->se_family == new->se_family)
break;
if (sep != 0) {
@@ -978,12 +990,14 @@ void config()
#endif
}
if (!sep->se_rpc) {
- sp = getservbyname(sep->se_service, sep->se_proto);
- if (sp == 0) {
- syslog(LOG_ERR, "%s/%s: unknown service",
- sep->se_service, sep->se_proto);
- sep->se_checked = 0;
- continue;
+ if (sep->se_family != AF_UNIX) {
+ sp = getservbyname(sep->se_service, sep->se_proto);
+ if (sp == 0) {
+ syslog(LOG_ERR, "%s/%s: unknown service",
+ sep->se_service, sep->se_proto);
+ sep->se_checked = 0;
+ continue;
+ }
}
switch (sep->se_family) {
case AF_INET:
@@ -1154,6 +1168,10 @@ setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
#ifdef IPSEC
ipsecsetup(sep);
#endif
+ if (sep->se_family == AF_UNIX) {
+ (void) unlink(sep->se_ctrladdr_un.sun_path);
+ umask(0777); /* Make socket with conservative permissions */
+ }
if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
sep->se_ctrladdr_size) < 0) {
if (debug)
@@ -1167,8 +1185,18 @@ setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
timingout = 1;
alarm(RETRYTIME);
}
+ if (sep->se_family == AF_UNIX)
+ umask(mask);
return;
}
+ if (sep->se_family == AF_UNIX) {
+ /* Ick - fch{own,mod} don't work on Unix domain sockets */
+ if (chown(sep->se_service, sep->se_sockuid, sep->se_sockgid) < 0)
+ syslog(LOG_ERR, "chown socket: %m");
+ if (chmod(sep->se_service, sep->se_sockmode) < 0)
+ syslog(LOG_ERR, "chmod socket: %m");
+ umask(mask);
+ }
if (sep->se_rpc) {
int i;
socklen_t len = sep->se_ctrladdr_size;
@@ -1301,9 +1329,15 @@ int
matchservent(name1, name2, proto)
char *name1, *name2, *proto;
{
- char **alias;
+ char **alias, *p;
struct servent *se;
+ if (strcmp(proto, "unix") == 0) {
+ if ((p = strrchr(name1, '/')) != NULL)
+ name1 = p + 1;
+ if ((p = strrchr(name2, '/')) != NULL)
+ name2 = p + 1;
+ }
if (strcmp(name1, name2) == 0)
return(1);
if ((se = getservbyname(name1, proto)) != NULL) {
@@ -1483,6 +1517,42 @@ more:
/* got an empty line containing just blanks/tabs. */
goto more;
}
+ if (arg[0] == ':') { /* :user:group:perm: */
+ char *user, *group, *perm;
+ struct passwd *pw;
+ struct group *gr;
+ user = arg+1;
+ if ((group = strchr(user, ':')) == NULL) {
+ syslog(LOG_ERR, "no group after user '%s'", user);
+ goto more;
+ }
+ *group++ = '\0';
+ if ((perm = strchr(group, ':')) == NULL) {
+ syslog(LOG_ERR, "no mode after group '%s'", group);
+ goto more;
+ }
+ *perm++ = '\0';
+ if ((pw = getpwnam(user)) == NULL) {
+ syslog(LOG_ERR, "no such user '%s'", user);
+ goto more;
+ }
+ sep->se_sockuid = pw->pw_uid;
+ if ((gr = getgrnam(group)) == NULL) {
+ syslog(LOG_ERR, "no such user '%s'", group);
+ goto more;
+ }
+ sep->se_sockgid = gr->gr_gid;
+ sep->se_sockmode = strtol(perm, &arg, 8);
+ if (*arg != ':') {
+ syslog(LOG_ERR, "bad mode '%s'", perm);
+ goto more;
+ }
+ *arg++ = '\0';
+ } else {
+ sep->se_sockuid = euid;
+ sep->se_sockgid = egid;
+ sep->se_sockmode = 0200;
+ }
if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
char *c = arg + MUX_LEN;
if (*c == '+') {
@@ -1589,6 +1659,9 @@ more:
freeconfig(sep);
goto more;
}
+ if (strcmp(sep->se_proto, "unix") == 0) {
+ sep->se_family = AF_UNIX;
+ } else
#ifdef INET6
if (v6bind != 0) {
sep->se_family = AF_INET6;
@@ -1619,6 +1692,18 @@ more:
sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr6);
break;
#endif
+ case AF_UNIX:
+ if (strlen(sep->se_service) >= sizeof(sep->se_ctrladdr_un.sun_path)) {
+ syslog(LOG_ERR,
+ "domain socket pathname too long for service %s",
+ sep->se_service);
+ goto more;
+ }
+ memset(&sep->se_ctrladdr, 0, sizeof(sep->se_ctrladdr));
+ sep->se_ctrladdr_un.sun_family = sep->se_family;
+ sep->se_ctrladdr_un.sun_len = strlen(sep->se_service);
+ strcpy(sep->se_ctrladdr_un.sun_path, sep->se_service);
+ sep->se_ctrladdr_size = SUN_LEN(&sep->se_ctrladdr_un);
}
arg = sskip(&cp);
if (!strncmp(arg, "wait", 4))
diff --git a/usr.sbin/inetd/inetd.h b/usr.sbin/inetd/inetd.h
index f54447f..7790880 100644
--- a/usr.sbin/inetd/inetd.h
+++ b/usr.sbin/inetd/inetd.h
@@ -35,6 +35,7 @@
#include <sys/time.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
@@ -80,11 +81,16 @@ struct servtab {
struct sockaddr se_un_ctrladdr;
struct sockaddr_in se_un_ctrladdr4;
struct sockaddr_in6 se_un_ctrladdr6;
+ struct sockaddr_un se_un_ctrladdr_un;
} se_un;
#define se_ctrladdr se_un.se_un_ctrladdr
#define se_ctrladdr4 se_un.se_un_ctrladdr4
#define se_ctrladdr6 se_un.se_un_ctrladdr6
+#define se_ctrladdr_un se_un.se_un_ctrladdr_un
socklen_t se_ctrladdr_size;
+ uid_t se_sockuid; /* Owner for unix domain socket */
+ gid_t se_sockgid; /* Group for unix domain socket */
+ mode_t se_sockmode; /* Mode for unix domain socket */
u_char se_type; /* type: normal, mux, or mux+ */
u_char se_checked; /* looked at during merge */
u_char se_accept; /* i.e., wait/nowait mode */
OpenPOWER on IntegriCloud