* Copyright (c) 1983 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
"@(#) Copyright (c) 1983 Regents of the University of California.\n\
static char sccsid
[] = "@(#)inetd.c 5.2 (Berkeley) %G%";
* Inetd - Internet super-server
* This program invokes all internet services as needed.
* connection-oriented services are invoked each time a
* connection is made, by creating a process. This process
* is passed the connection as file descriptor 0 and is
* expected to do a getpeername to find out the source host
* Datagram oriented services are invoked when a datagram
* arrives; a process is created and passed a pending message
* on file descriptor 0. Datagram servers may either connect
* to their peer, freeing up the original socket for inetd
* to receive further messages on, or ``take over the socket'',
* processing all arriving datagrams and, eventually, timing
* out. The first type of server is said to be ``multi-threaded'';
* the second type of server ``single-threaded''.
* Inetd uses a configuration file which is read at startup
* and, possibly, at some later time in response to a hangup signal.
* The configuration file is ``free format'' with fields given in the
* order shown below. Continuation lines for an entry must being with
* a space or tab. All fields must be present in each entry.
* service name must be in /etc/services
* socket type stream/dgram/raw/rdm/seqpacket
* protocol must be in /etc/protocols
* wait/nowait single-threaded/multi-threaded
* user user to run daemon as
* server program full path name
* server program arguments maximum of MAXARGS (5)
* Comment lines are indicated by a `#' in column 1.
char *se_service
; /* name of service */
int se_socktype
; /* type of socket to use */
char *se_proto
; /* protocol used */
short se_wait
; /* single threaded server */
short se_checked
; /* looked at during merge */
char *se_user
; /* user name to run as */
char *se_server
; /* server program */
char *se_argv
[MAXARGV
+1]; /* program arguments */
int se_fd
; /* open descriptor */
struct sockaddr_in se_ctrladdr
;/* bound address */
char *CONFIG
= "/etc/inetd.conf";
register struct servtab
*sep
;
register struct passwd
*pwd
;
while (argc
> 0 && *argv
[0] == '-') {
for (cp
= &argv
[0][1]; *cp
; cp
++) switch (*cp
) {
"inetd: Unknown flag -%c ignored.\n", *cp
);
(void) open("/", O_RDONLY
);
{ int tt
= open("/dev/tty", O_RDWR
);
openlog("inetd", LOG_PID
, LOG_DAEMON
);
signal(SIGCHLD
, reapchild
);
if (select(32, &readable
, 0, 0, 0) <= 0)
for (sep
= servtab
; sep
; sep
= sep
->se_next
)
fprintf(stderr
, "someone wants %s\n", sep
->se_service
);
if (sep
->se_socktype
== SOCK_STREAM
) {
fprintf(stderr
, "accept, ctrl %d\n", ctrl
);
syslog(LOG_WARNING
, "accept: %m");
#define mask(sig) (1 << (sig - 1))
sigblock(mask(SIGCHLD
)|mask(SIGHUP
));
if (sep
->se_socktype
== SOCK_STREAM
)
int tt
= open("/dev/tty", O_RDWR
);
dup2(ctrl
, 0), close(ctrl
), dup2(0, 1);
for (i
= getdtablesize(); --i
> 2; )
if ((pwd
= getpwnam(sep
->se_user
)) == NULL
) {
syslog(LOG_ERR
, "getpwnam: %s: No such user"
(void) setgid(pwd
->pw_gid
);
initgroups(pwd
->pw_name
, pwd
->pw_gid
);
(void) setuid(pwd
->pw_uid
);
fprintf(stderr
, "%d execl %s\n",
getpid(), sep
->se_server
);
execv(sep
->se_server
, sep
->se_argv
);
if (sep
->se_socktype
!= SOCK_STREAM
)
recv(0, buf
, sizeof (buf
), 0);
syslog(LOG_ERR
, "execv %s: %m", sep
->se_server
);
if (sep
->se_socktype
== SOCK_STREAM
)
register struct servtab
*sep
;
pid
= wait3(&status
, WNOHANG
, 0);
fprintf(stderr
, "%d reaped\n", pid
);
for (sep
= servtab
; sep
; sep
= sep
->se_next
)
if (sep
->se_wait
== pid
) {
fprintf(stderr
, "restored %s, fd %d\n",
sep
->se_service
, sep
->se_fd
);
allsock
|= 1 << sep
->se_fd
;
register struct servtab
*sep
, *cp
, **sepp
;
struct servtab
*getconfigent(), *enter();
syslog(LOG_ERR
, "%s: %m", CONFIG
);
for (sep
= servtab
; sep
; sep
= sep
->se_next
)
while (cp
= getconfigent()) {
for (sep
= servtab
; sep
; sep
= sep
->se_next
)
if (strcmp(sep
->se_service
, cp
->se_service
) == 0 &&
strcmp(sep
->se_proto
, cp
->se_proto
) == 0)
omask
= sigblock(mask(SIGCHLD
));
sep
->se_wait
= cp
->se_wait
;
#define SWAP(a, b) { char *c = a; a = b; b = c; }
SWAP(sep
->se_server
, cp
->se_server
);
for (i
= 0; i
< MAXARGV
; i
++)
SWAP(sep
->se_argv
[i
], cp
->se_argv
[i
]);
sp
= getservbyname(sep
->se_service
, sep
->se_proto
);
syslog(LOG_ERR
, "%s/%s: unknown service",
sep
->se_service
, sep
->se_proto
);
sep
->se_ctrladdr
.sin_port
= sp
->s_port
;
if ((sep
->se_fd
= socket(AF_INET
, sep
->se_socktype
, 0)) < 0) {
syslog(LOG_ERR
, "%s/%s: socket: %m",
sep
->se_service
, sep
->se_proto
);
#define turnon(fd, opt) \
setsockopt(fd, SOL_SOCKET, opt, &on, sizeof (on))
if (strcmp(sep
->se_proto
, "tcp") == 0 && (options
& SO_DEBUG
) &&
turnon(sep
->se_fd
, SO_DEBUG
) < 0)
syslog(LOG_ERR
, "setsockopt (SO_DEBUG): %m");
if (turnon(sep
->se_fd
, SO_REUSEADDR
) < 0)
syslog(LOG_ERR
, "setsockopt (SO_REUSEADDR): %m");
if (bind(sep
->se_fd
, &sep
->se_ctrladdr
,
sizeof (sep
->se_ctrladdr
), 0) < 0) {
syslog(LOG_ERR
, "%s/%s: bind: %m",
sep
->se_service
, sep
->se_proto
);
if (sep
->se_socktype
== SOCK_STREAM
)
allsock
|= 1 << sep
->se_fd
;
* Purge anything not looked at above.
omask
= sigblock(mask(SIGCHLD
));
allsock
&= ~(1 << sep
->se_fd
);
(void) close(sep
->se_fd
);
(void) sigsetmask(omask
);
register struct servtab
*sep
;
sep
= (struct servtab
*)malloc(sizeof (*sep
));
if (sep
== (struct servtab
*)0) {
syslog(LOG_ERR
, "Out of memory.");
omask
= sigblock(mask(SIGCHLD
));
char *skip(), *nextline();
fseek(fconfig
, 0, L_SET
);
fconfig
= fopen(CONFIG
, "r");
return (fconfig
!= NULL
);
register struct servtab
*sep
= &serv
;
while ((cp
= nextline(fconfig
)) && *cp
== '#')
return ((struct servtab
*)0);
sep
->se_service
= strdup(skip(&cp
));
if (strcmp(arg
, "stream") == 0)
sep
->se_socktype
= SOCK_STREAM
;
else if (strcmp(arg
, "dgram") == 0)
sep
->se_socktype
= SOCK_DGRAM
;
else if (strcmp(arg
, "rdm") == 0)
sep
->se_socktype
= SOCK_RDM
;
else if (strcmp(arg
, "seqpacket") == 0)
sep
->se_socktype
= SOCK_SEQPACKET
;
else if (strcmp(arg
, "raw") == 0)
sep
->se_socktype
= SOCK_RAW
;
sep
->se_proto
= strdup(skip(&cp
));
sep
->se_wait
= strcmp(arg
, "wait") == 0;
sep
->se_user
= strdup(skip(&cp
));
sep
->se_server
= strdup(skip(&cp
));
for (arg
= skip(&cp
); cp
; arg
= skip(&cp
))
sep
->se_argv
[argc
++] = strdup(arg
);
sep
->se_argv
[argc
++] = NULL
;
register struct servtab
*cp
;
for (i
= 0; i
< MAXARGV
; i
++)
register char *cp
= *cpp
;
while (*cp
== ' ' || *cp
== '\t')
if (c
== ' ' || c
== '\t')
if (cp
= nextline(fconfig
))
while (*cp
&& *cp
!= ' ' && *cp
!= '\t')
if (fgets(line
, sizeof (line
), fconfig
) == NULL
)
new = malloc(strlen(cp
) + 1);
syslog(LOG_ERR
, "Out of memory.");