summaryrefslogtreecommitdiffstats
path: root/usr.sbin/inetd/inetd.c
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/inetd.c
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/inetd.c')
-rw-r--r--usr.sbin/inetd/inetd.c105
1 files changed, 95 insertions, 10 deletions
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))
OpenPOWER on IntegriCloud