]>
git.saurik.com Git - apple/network_cmds.git/blob - inetd.tproj/inetd.c
1b93a68a8c8ecbb12a89ec79b88bb7b89b018a4e
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * Copyright (c) 1983, 1991, 1993, 1994
26 * The Regents of the University of California. All rights reserved.
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 static char copyright
[] =
59 "@(#) Copyright (c) 1983, 1991, 1993, 1994\n\
60 The Regents of the University of California. All rights reserved.\n";
64 static char sccsid
[] = "@(#)inetd.c 8.4 (Berkeley) 4/13/94";
68 * Inetd - Internet super-server
70 * This program invokes all internet services as needed. Connection-oriented
71 * services are invoked each time a connection is made, by creating a process.
72 * This process is passed the connection as file descriptor 0 and is expected
73 * to do a getpeername to find out the source host and port.
75 * Datagram oriented services are invoked when a datagram
76 * arrives; a process is created and passed a pending message
77 * on file descriptor 0. Datagram servers may either connect
78 * to their peer, freeing up the original socket for inetd
79 * to receive further messages on, or ``take over the socket'',
80 * processing all arriving datagrams and, eventually, timing
81 * out. The first type of server is said to be ``multi-threaded'';
82 * the second type of server ``single-threaded''.
84 * Inetd uses a configuration file which is read at startup
85 * and, possibly, at some later time in response to a hangup signal.
86 * The configuration file is ``free format'' with fields given in the
87 * order shown below. Continuation lines for an entry must being with
88 * a space or tab. All fields must be present in each entry.
90 * service name must be in /etc/services or must
91 * name a tcpmux service
92 * socket type stream/dgram/raw/rdm/seqpacket
93 * protocol must be in /etc/protocols
94 * wait/nowait single-threaded/multi-threaded
95 * user user to run daemon as
96 * server program full path name
97 * server program arguments maximum of MAXARGS (20)
99 * TCP services without official port numbers are handled with the
100 * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for
101 * requests. When a connection is made from a foreign host, the service
102 * requested is passed to tcpmux, which looks it up in the servtab list
103 * and returns the proper entry for the service. Tcpmux returns a
104 * negative reply if the service doesn't exist, otherwise the invoked
105 * server is expected to return the positive reply if the service type in
106 * inetd.conf file has the prefix "tcpmux/". If the service type has the
107 * prefix "tcpmux/+", tcpmux will return the positive reply for the
108 * process; this is for compatibility with older server code, and also
109 * allows you to invoke programs that use stdin/stdout without putting any
110 * special server code in them. Services that use tcpmux are "nowait"
111 * because they do not have a well-known port and hence cannot listen
114 * Comment lines are indicated by a `#' in column 1.
116 #include <sys/param.h>
117 #include <sys/stat.h>
118 #include <sys/ioctl.h>
119 #include <sys/socket.h>
120 #include <sys/wait.h>
121 #include <sys/time.h>
122 #include <sys/resource.h>
124 #include <netinet/in.h>
125 #include <arpa/inet.h>
138 #include "pathnames.h"
140 #define TOOMANY 100 /* don't start more than TOOMANY */
141 #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */
142 #define RETRYTIME (60*10) /* retry after bind or server fail */
144 #define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
152 int toomany
= TOOMANY
;
156 char *se_service
; /* name of service */
157 int se_socktype
; /* type of socket to use */
158 char *se_proto
; /* protocol used */
159 short se_wait
; /* single threaded server */
160 short se_checked
; /* looked at during merge */
161 char *se_user
; /* user name to run as */
162 struct biltin
*se_bi
; /* if built-in, description */
163 char *se_server
; /* server program */
165 char *se_argv
[MAXARGV
+1]; /* program arguments */
166 int se_fd
; /* open descriptor */
167 int se_type
; /* type */
168 struct sockaddr_in se_ctrladdr
;/* bound address */
169 int se_count
; /* number started since se_time */
170 struct timeval se_time
; /* start of se_count */
171 struct servtab
*se_next
;
176 #define MUXPLUS_TYPE 2
177 #define ISMUX(sep) (((sep)->se_type == MUX_TYPE) || \
178 ((sep)->se_type == MUXPLUS_TYPE))
179 #define ISMUXPLUS(sep) ((sep)->se_type == MUXPLUS_TYPE)
182 void chargen_dg
__P((int, struct servtab
*));
183 void chargen_stream
__P((int, struct servtab
*));
184 void close_sep
__P((struct servtab
*));
185 void config
__P((int));
186 void daytime_dg
__P((int, struct servtab
*));
187 void daytime_stream
__P((int, struct servtab
*));
188 void discard_dg
__P((int, struct servtab
*));
189 void discard_stream
__P((int, struct servtab
*));
190 void echo_dg
__P((int, struct servtab
*));
191 void echo_stream
__P((int, struct servtab
*));
192 void endconfig
__P((void));
193 struct servtab
*enter
__P((struct servtab
*));
194 void freeconfig
__P((struct servtab
*));
195 struct servtab
*getconfigent
__P((void));
196 void machtime_dg
__P((int, struct servtab
*));
197 void machtime_stream
__P((int, struct servtab
*));
198 char *newstr
__P((char *));
199 char *nextline
__P((FILE *));
200 void print_service
__P((char *, struct servtab
*));
201 void reapchild
__P((int));
202 void retry
__P((int));
203 int setconfig
__P((void));
204 void setup
__P((struct servtab
*));
205 char *sskip
__P((char **));
206 char *skip
__P((char **));
207 struct servtab
*tcpmux
__P((int));
210 char *bi_service
; /* internally provided service name */
211 int bi_socktype
; /* type of socket supported */
212 short bi_fork
; /* 1 if should fork before call */
213 short bi_wait
; /* 1 if should wait for child */
214 void (*bi_fn
)(); /* function which performs it */
216 /* Echo received data */
217 { "echo", SOCK_STREAM
, 1, 0, echo_stream
},
218 { "echo", SOCK_DGRAM
, 0, 0, echo_dg
},
220 /* Internet /dev/null */
221 { "discard", SOCK_STREAM
, 1, 0, discard_stream
},
222 { "discard", SOCK_DGRAM
, 0, 0, discard_dg
},
224 /* Return 32 bit time since 1970 */
225 { "time", SOCK_STREAM
, 0, 0, machtime_stream
},
226 { "time", SOCK_DGRAM
, 0, 0, machtime_dg
},
228 /* Return human-readable time */
229 { "daytime", SOCK_STREAM
, 0, 0, daytime_stream
},
230 { "daytime", SOCK_DGRAM
, 0, 0, daytime_dg
},
232 /* Familiar character generator */
233 { "chargen", SOCK_STREAM
, 1, 0, chargen_stream
},
234 { "chargen", SOCK_DGRAM
, 0, 0, chargen_dg
},
236 { "tcpmux", SOCK_STREAM
, 1, 0, (void (*)())tcpmux
},
241 #define NUMINT (sizeof(intab) / sizeof(struct inent))
242 char *CONFIG
= _PATH_INETDCONF
;
243 char *pid_file
= _PATH_INETDPID
;
248 main(argc
, argv
, envp
)
250 char *argv
[], *envp
[];
255 int tmpint
, ch
, dofork
;
260 if (envp
== 0 || *envp
== 0)
264 LastArg
= envp
[-1] + strlen(envp
[-1]);
266 openlog("inetd", LOG_PID
| LOG_NOWAIT
, LOG_DAEMON
);
268 while ((ch
= getopt(argc
, argv
, "dR:p:")) != EOF
)
274 case 'R': { /* invocation rate */
277 tmpint
= strtol(optarg
, &p
, 0);
278 if (tmpint
< 1 || *p
)
280 "-R %s: bad value for service invocation rate",
292 "usage: inetd [-d] [-R rate] [conf-file]");
305 fp
= fopen(pid_file
, "w");
307 fprintf(fp
, "%ld\n", (long)pid
);
310 syslog(LOG_WARNING
, "%s: %m", pid_file
);
313 memset(&sv
, 0, sizeof(sv
));
314 sv
.sv_mask
= SIGBLOCK
;
315 sv
.sv_handler
= retry
;
316 sigvec(SIGALRM
, &sv
, (struct sigvec
*)0);
318 sv
.sv_handler
= config
;
319 sigvec(SIGHUP
, &sv
, (struct sigvec
*)0);
320 sv
.sv_handler
= reapchild
;
321 sigvec(SIGCHLD
, &sv
, (struct sigvec
*)0);
324 /* space for daemons to overwrite environment for ps */
325 #define DUMMYSIZE 100
326 char dummy
[DUMMYSIZE
];
328 (void)memset(dummy
, 'x', sizeof(DUMMYSIZE
) - 1);
329 dummy
[DUMMYSIZE
- 1] = '\0';
330 (void)setenv("inetd_dummy", dummy
, 1);
338 (void) sigblock(SIGBLOCK
);
341 (void) sigsetmask(0L);
344 if ((n
= select(maxsock
+ 1, &readable
, (fd_set
*)0,
345 (fd_set
*)0, (struct timeval
*)0)) <= 0) {
346 if (n
< 0 && errno
!= EINTR
) {
347 syslog(LOG_WARNING
, "select: %m");
352 for (sep
= servtab
; n
&& sep
; sep
= sep
->se_next
)
353 if (sep
->se_fd
!= -1 && FD_ISSET(sep
->se_fd
, &readable
)) {
356 fprintf(stderr
, "someone wants %s\n",
358 if (!sep
->se_wait
&& sep
->se_socktype
== SOCK_STREAM
) {
359 ctrl
= accept(sep
->se_fd
, (struct sockaddr
*)0,
362 fprintf(stderr
, "accept, ctrl %d\n", ctrl
);
366 "accept (for %s): %m",
371 * Call tcpmux to find the real service to exec.
374 sep
->se_bi
->bi_fn
== (void (*)()) tcpmux
) {
383 (void) sigblock(SIGBLOCK
);
385 dofork
= (sep
->se_bi
== 0 || sep
->se_bi
->bi_fork
);
387 if (sep
->se_count
++ == 0)
388 (void)gettimeofday(&sep
->se_time
,
389 (struct timezone
*)0);
390 else if (sep
->se_count
>= toomany
) {
393 (void)gettimeofday(&now
, (struct timezone
*)0);
394 if (now
.tv_sec
- sep
->se_time
.tv_sec
>
400 "%s/%s server failing (looping), service terminated",
401 sep
->se_service
, sep
->se_proto
);
414 syslog(LOG_ERR
, "fork: %m");
416 sep
->se_socktype
== SOCK_STREAM
)
422 if (pid
&& sep
->se_wait
) {
424 if (sep
->se_fd
>= 0) {
425 FD_CLR(sep
->se_fd
, &allsock
);
435 fprintf(stderr
, "+ Closing from %d\n",
437 for (tmpint
= maxsock
; tmpint
> 2; tmpint
--)
442 (*sep
->se_bi
->bi_fn
)(ctrl
, sep
);
445 fprintf(stderr
, "%d execl %s\n",
446 getpid(), sep
->se_server
);
451 if ((pwd
= getpwnam(sep
->se_user
)) == NULL
) {
453 "%s/%s: %s: No such user",
454 sep
->se_service
, sep
->se_proto
,
456 if (sep
->se_socktype
!= SOCK_STREAM
)
457 recv(0, buf
, sizeof (buf
), 0);
461 if (setgid(pwd
->pw_gid
) < 0) {
463 "%s: can't set gid %d: %m",
464 sep
->se_service
, pwd
->pw_gid
);
467 (void) initgroups(pwd
->pw_name
,
469 if (setuid(pwd
->pw_uid
) < 0) {
471 "%s: can't set uid %d: %m",
472 sep
->se_service
, pwd
->pw_uid
);
476 execv(sep
->se_server
, sep
->se_argv
);
477 if (sep
->se_socktype
!= SOCK_STREAM
)
478 recv(0, buf
, sizeof (buf
), 0);
480 "cannot execute %s: %m", sep
->se_server
);
484 if (!sep
->se_wait
&& sep
->se_socktype
== SOCK_STREAM
)
499 pid
= wait3(&status
, WNOHANG
, (struct rusage
*)0);
503 fprintf(stderr
, "%d reaped, status %#x\n",
505 for (sep
= servtab
; sep
; sep
= sep
->se_next
)
506 if (sep
->se_wait
== pid
) {
509 "%s: exit status 0x%x",
510 sep
->se_server
, status
);
512 fprintf(stderr
, "restored %s, fd %d\n",
513 sep
->se_service
, sep
->se_fd
);
514 FD_SET(sep
->se_fd
, &allsock
);
525 struct servtab
*sep
, *cp
, **sepp
;
530 syslog(LOG_ERR
, "%s: %m", CONFIG
);
533 for (sep
= servtab
; sep
; sep
= sep
->se_next
)
535 while (cp
= getconfigent()) {
536 if ((pwd
= getpwnam(cp
->se_user
)) == NULL
) {
538 "%s/%s: No such user '%s', service ignored",
539 cp
->se_service
, cp
->se_proto
, cp
->se_user
);
542 for (sep
= servtab
; sep
; sep
= sep
->se_next
)
543 if (strcmp(sep
->se_service
, cp
->se_service
) == 0 &&
544 strcmp(sep
->se_proto
, cp
->se_proto
) == 0)
549 omask
= sigblock(SIGBLOCK
);
551 * sep->se_wait may be holding the pid of a daemon
552 * that we're waiting for. If so, don't overwrite
553 * it unless the config file explicitly says don't
556 if (cp
->se_bi
== 0 &&
557 (sep
->se_wait
== 1 || cp
->se_wait
== 0))
558 sep
->se_wait
= cp
->se_wait
;
559 #define SWAP(a, b) { char *c = a; a = b; b = c; }
561 SWAP(sep
->se_user
, cp
->se_user
);
563 SWAP(sep
->se_server
, cp
->se_server
);
564 for (i
= 0; i
< MAXARGV
; i
++)
565 SWAP(sep
->se_argv
[i
], cp
->se_argv
[i
]);
569 print_service("REDO", sep
);
573 print_service("ADD ", sep
);
580 sp
= getservbyname(sep
->se_service
, sep
->se_proto
);
582 syslog(LOG_ERR
, "%s/%s: unknown service",
583 sep
->se_service
, sep
->se_proto
);
587 if (sp
->s_port
!= sep
->se_ctrladdr
.sin_port
) {
588 sep
->se_ctrladdr
.sin_family
= AF_INET
;
589 sep
->se_ctrladdr
.sin_port
= sp
->s_port
;
593 if (sep
->se_fd
== -1)
598 * Purge anything not looked at above.
600 omask
= sigblock(SIGBLOCK
);
602 while (sep
= *sepp
) {
603 if (sep
->se_checked
) {
604 sepp
= &sep
->se_next
;
607 *sepp
= sep
->se_next
;
611 print_service("FREE", sep
);
615 (void) sigsetmask(omask
);
625 for (sep
= servtab
; sep
; sep
= sep
->se_next
)
626 if (sep
->se_fd
== -1)
636 if ((sep
->se_fd
= socket(AF_INET
, sep
->se_socktype
, 0)) < 0) {
638 fprintf(stderr
, "socket failed on %s/%s: %s\n",
639 sep
->se_service
, sep
->se_proto
,
641 syslog(LOG_ERR
, "%s/%s: socket: %m",
642 sep
->se_service
, sep
->se_proto
);
645 #define turnon(fd, opt) \
646 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
647 if (strcmp(sep
->se_proto
, "tcp") == 0 && (options
& SO_DEBUG
) &&
648 turnon(sep
->se_fd
, SO_DEBUG
) < 0)
649 syslog(LOG_ERR
, "setsockopt (SO_DEBUG): %m");
650 if (turnon(sep
->se_fd
, SO_REUSEADDR
) < 0)
651 syslog(LOG_ERR
, "setsockopt (SO_REUSEADDR): %m");
653 if (bind(sep
->se_fd
, (struct sockaddr
*)&sep
->se_ctrladdr
,
654 sizeof (sep
->se_ctrladdr
)) < 0) {
656 fprintf(stderr
, "bind failed on %s/%s: %s\n",
657 sep
->se_service
, sep
->se_proto
,
659 syslog(LOG_ERR
, "%s/%s: bind: %m",
660 sep
->se_service
, sep
->se_proto
);
661 (void) close(sep
->se_fd
);
669 if (sep
->se_socktype
== SOCK_STREAM
)
670 listen(sep
->se_fd
, 10);
671 FD_SET(sep
->se_fd
, &allsock
);
673 if (sep
->se_fd
> maxsock
)
674 maxsock
= sep
->se_fd
;
676 fprintf(stderr
, "registered %s on %d\n",
677 sep
->se_server
, sep
->se_fd
);
682 * Finish with a service and its socket.
688 if (sep
->se_fd
>= 0) {
690 FD_CLR(sep
->se_fd
, &allsock
);
691 (void) close(sep
->se_fd
);
696 * Don't keep the pid of this running deamon: when reapchild()
697 * reaps this pid, it would erroneously increment nsock.
699 if (sep
->se_wait
> 1)
710 sep
= (struct servtab
*)malloc(sizeof (*sep
));
711 if (sep
== (struct servtab
*)0) {
712 syslog(LOG_ERR
, "Out of memory.");
717 omask
= sigblock(SIGBLOCK
);
718 sep
->se_next
= servtab
;
724 FILE *fconfig
= NULL
;
732 if (fconfig
!= NULL
) {
733 fseek(fconfig
, 0L, SEEK_SET
);
736 fconfig
= fopen(CONFIG
, "r");
737 return (fconfig
!= NULL
);
744 (void) fclose(fconfig
);
752 struct servtab
*sep
= &serv
;
755 static char TCPMUX_TOKEN
[] = "tcpmux/";
756 #define MUX_LEN (sizeof(TCPMUX_TOKEN)-1)
759 while ((cp
= nextline(fconfig
)) && (*cp
== '#' || *cp
== '\0'))
762 return ((struct servtab
*)0);
764 * clear the static buffer, since some fields (se_ctrladdr,
765 * for example) don't get initialized here.
767 memset((caddr_t
)sep
, 0, sizeof *sep
);
770 /* got an empty line containing just blanks/tabs. */
773 if (strncmp(arg
, TCPMUX_TOKEN
, MUX_LEN
) == 0) {
774 char *c
= arg
+ MUX_LEN
;
776 sep
->se_type
= MUXPLUS_TYPE
;
779 sep
->se_type
= MUX_TYPE
;
780 sep
->se_service
= newstr(c
);
782 sep
->se_service
= newstr(arg
);
783 sep
->se_type
= NORM_TYPE
;
786 if (strcmp(arg
, "stream") == 0)
787 sep
->se_socktype
= SOCK_STREAM
;
788 else if (strcmp(arg
, "dgram") == 0)
789 sep
->se_socktype
= SOCK_DGRAM
;
790 else if (strcmp(arg
, "rdm") == 0)
791 sep
->se_socktype
= SOCK_RDM
;
792 else if (strcmp(arg
, "seqpacket") == 0)
793 sep
->se_socktype
= SOCK_SEQPACKET
;
794 else if (strcmp(arg
, "raw") == 0)
795 sep
->se_socktype
= SOCK_RAW
;
797 sep
->se_socktype
= -1;
798 sep
->se_proto
= newstr(sskip(&cp
));
800 sep
->se_wait
= strcmp(arg
, "wait") == 0;
803 * Silently enforce "nowait" for TCPMUX services since
804 * they don't have an assigned port to listen on.
808 if (strcmp(sep
->se_proto
, "tcp")) {
810 "%s: bad protocol for tcpmux service %s",
811 CONFIG
, sep
->se_service
);
814 if (sep
->se_socktype
!= SOCK_STREAM
) {
816 "%s: bad socket type for tcpmux service %s",
817 CONFIG
, sep
->se_service
);
821 sep
->se_user
= newstr(sskip(&cp
));
822 sep
->se_server
= newstr(sskip(&cp
));
823 if (strcmp(sep
->se_server
, "internal") == 0) {
826 for (bi
= biltins
; bi
->bi_service
; bi
++)
827 if (bi
->bi_socktype
== sep
->se_socktype
&&
828 strcmp(bi
->bi_service
, sep
->se_service
) == 0)
830 if (bi
->bi_service
== 0) {
831 syslog(LOG_ERR
, "internal service %s unknown",
836 sep
->se_wait
= bi
->bi_wait
;
840 for (arg
= skip(&cp
); cp
; arg
= skip(&cp
))
842 sep
->se_argv
[argc
++] = newstr(arg
);
843 while (argc
<= MAXARGV
)
844 sep
->se_argv
[argc
++] = NULL
;
855 free(cp
->se_service
);
862 for (i
= 0; i
< MAXARGV
; i
++)
864 free(cp
->se_argv
[i
]);
869 * Safe skip - if skip returns null, log a syntax error in the
870 * configuration file and exit.
880 syslog(LOG_ERR
, "%s: syntax error", CONFIG
);
894 while (*cp
== ' ' || *cp
== '\t')
900 (void) ungetc(c
, fconfig
);
901 if (c
== ' ' || c
== '\t')
902 if (cp
= nextline(fconfig
))
908 while (*cp
&& *cp
!= ' ' && *cp
!= '\t')
922 if (fgets(line
, sizeof (line
), fd
) == NULL
)
924 cp
= strchr(line
, '\n');
934 if (cp
= strdup(cp
? cp
: ""))
936 syslog(LOG_ERR
, "strdup: %m");
947 struct sockaddr_in sin
;
952 if (getpeername(s
, (struct sockaddr
*)&sin
, &size
) == 0)
953 (void) sprintf(buf
, "-%s [%s]", a
, inet_ntoa(sin
.sin_addr
));
955 (void) sprintf(buf
, "-%s", a
);
956 strncpy(cp
, buf
, LastArg
- cp
);
963 * Internet services provided internally by inetd:
969 echo_stream(s
, sep
) /* Echo service -- echo data back */
973 char buffer
[BUFSIZE
];
976 setproctitle(sep
->se_service
, s
);
977 while ((i
= read(s
, buffer
, sizeof(buffer
))) > 0 &&
978 write(s
, buffer
, i
) > 0)
985 echo_dg(s
, sep
) /* Echo service -- echo data back */
989 char buffer
[BUFSIZE
];
994 if ((i
= recvfrom(s
, buffer
, sizeof(buffer
), 0, &sa
, &size
)) < 0)
996 (void) sendto(s
, buffer
, i
, 0, &sa
, sizeof(sa
));
1001 discard_stream(s
, sep
) /* Discard service -- ignore data */
1003 struct servtab
*sep
;
1006 char buffer
[BUFSIZE
];
1008 setproctitle(sep
->se_service
, s
);
1010 while ((ret
= read(s
, buffer
, sizeof(buffer
))) > 0)
1012 if (ret
== 0 || errno
!= EINTR
)
1020 discard_dg(s
, sep
) /* Discard service -- ignore data */
1022 struct servtab
*sep
;
1024 char buffer
[BUFSIZE
];
1026 (void) read(s
, buffer
, sizeof(buffer
));
1041 for (i
= 0; i
<= 128; ++i
)
1048 chargen_stream(s
, sep
) /* Character generator */
1050 struct servtab
*sep
;
1053 char *rs
, text
[LINESIZ
+2];
1055 setproctitle(sep
->se_service
, s
);
1062 text
[LINESIZ
] = '\r';
1063 text
[LINESIZ
+ 1] = '\n';
1065 if ((len
= endring
- rs
) >= LINESIZ
)
1066 memmove(text
, rs
, LINESIZ
);
1068 memmove(text
, rs
, len
);
1069 memmove(text
+ len
, ring
, LINESIZ
- len
);
1071 if (++rs
== endring
)
1073 if (write(s
, text
, sizeof(text
)) != sizeof(text
))
1081 chargen_dg(s
, sep
) /* Character generator */
1083 struct servtab
*sep
;
1088 char text
[LINESIZ
+2];
1096 if (recvfrom(s
, text
, sizeof(text
), 0, &sa
, &size
) < 0)
1099 if ((len
= endring
- rs
) >= LINESIZ
)
1100 memmove(text
, rs
, LINESIZ
);
1102 memmove(text
, rs
, len
);
1103 memmove(text
+ len
, ring
, LINESIZ
- len
);
1105 if (++rs
== endring
)
1107 text
[LINESIZ
] = '\r';
1108 text
[LINESIZ
+ 1] = '\n';
1109 (void) sendto(s
, text
, sizeof(text
), 0, &sa
, sizeof(sa
));
1113 * Return a machine readable date and time, in the form of the
1114 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
1115 * returns the number of seconds since midnight, Jan 1, 1970,
1116 * we must add 2208988800 seconds to this figure to make up for
1117 * some seventy years Bell Labs was asleep.
1125 if (gettimeofday(&tv
, (struct timezone
*)0) < 0) {
1127 fprintf(stderr
, "Unable to get time of day\n");
1130 #define OFFSET ((u_long)25567 * 24*60*60)
1131 return (htonl((long)(tv
.tv_sec
+ OFFSET
)));
1137 machtime_stream(s
, sep
)
1139 struct servtab
*sep
;
1143 result
= machtime();
1144 (void) write(s
, (char *) &result
, sizeof(result
));
1151 struct servtab
*sep
;
1158 if (recvfrom(s
, (char *)&result
, sizeof(result
), 0, &sa
, &size
) < 0)
1160 result
= machtime();
1161 (void) sendto(s
, (char *) &result
, sizeof(result
), 0, &sa
, sizeof(sa
));
1166 daytime_stream(s
, sep
) /* Return human-readable time of day */
1168 struct servtab
*sep
;
1173 clock
= time((time_t *) 0);
1175 (void) sprintf(buffer
, "%.24s\r\n", ctime(&clock
));
1176 (void) write(s
, buffer
, strlen(buffer
));
1181 daytime_dg(s
, sep
) /* Return human-readable time of day */
1183 struct servtab
*sep
;
1190 clock
= time((time_t *) 0);
1193 if (recvfrom(s
, buffer
, sizeof(buffer
), 0, &sa
, &size
) < 0)
1195 (void) sprintf(buffer
, "%.24s\r\n", ctime(&clock
));
1196 (void) sendto(s
, buffer
, strlen(buffer
), 0, &sa
, sizeof(sa
));
1201 * Dump relevant information to stderr
1204 print_service(action
, sep
)
1206 struct servtab
*sep
;
1209 "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
1210 action
, sep
->se_service
, sep
->se_proto
,
1211 sep
->se_wait
, sep
->se_user
, (int)sep
->se_bi
, sep
->se_server
);
1215 * Based on TCPMUX.C by Mark K. Lottor November 1988
1216 * sri-nic::ps:<mkl>tcpmux.c
1220 static int /* # of characters upto \r,\n or \0 */
1221 getline(fd
, buf
, len
)
1229 n
= read(fd
, buf
, len
-count
);
1235 if (*buf
== '\r' || *buf
== '\n' || *buf
== '\0')
1240 } while (count
< len
);
1244 #define MAX_SERV_LEN (256+2) /* 2 bytes for \r\n */
1246 #define strwrite(fd, buf) (void) write(fd, buf, sizeof(buf)-1)
1252 struct servtab
*sep
;
1253 char service
[MAX_SERV_LEN
+1];
1256 /* Get requested service name */
1257 if ((len
= getline(s
, service
, MAX_SERV_LEN
)) < 0) {
1258 strwrite(s
, "-Error reading service name\r\n");
1261 service
[len
] = '\0';
1264 fprintf(stderr
, "tcpmux: someone wants %s\n", service
);
1267 * Help is a required command, and lists available services,
1270 if (!strcasecmp(service
, "help")) {
1271 for (sep
= servtab
; sep
; sep
= sep
->se_next
) {
1274 (void)write(s
,sep
->se_service
,strlen(sep
->se_service
));
1275 strwrite(s
, "\r\n");
1280 /* Try matching a service in inetd.conf with the request */
1281 for (sep
= servtab
; sep
; sep
= sep
->se_next
) {
1284 if (!strcasecmp(service
, sep
->se_service
)) {
1285 if (ISMUXPLUS(sep
)) {
1286 strwrite(s
, "+Go\r\n");
1291 strwrite(s
, "-Service not available\r\n");