summaryrefslogtreecommitdiffstats
path: root/usr.sbin/inetd
diff options
context:
space:
mode:
authordwmalone <dwmalone@FreeBSD.org>2001-06-16 18:54:54 +0000
committerdwmalone <dwmalone@FreeBSD.org>2001-06-16 18:54:54 +0000
commit229831d19f3c3478e62ef382202f3da4cee2b0c1 (patch)
tree26042e92d7262a06440395c55be13a2795624e5d /usr.sbin/inetd
parent68be106995a68a6e76ce3951bb8742dde6f57485 (diff)
downloadFreeBSD-src-229831d19f3c3478e62ef382202f3da4cee2b0c1.zip
FreeBSD-src-229831d19f3c3478e62ef382202f3da4cee2b0c1.tar.gz
Give inetd the ability to manage unix domain sockets. Details of
how to use this feature are in the man page. This is based on work by Lyndon Nerenberg. (The only difficult part about this patch is the fact that you can't fchown a unix domain socket, which means the sockets must be put in a secure directory). Reviewed by: dillon
Diffstat (limited to 'usr.sbin/inetd')
-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