]>
git.saurik.com Git - apple/network_cmds.git/blob - inetd.tproj/inetd.c
b5a70db5cabb4bac0301530356553b9fe1fef5f3
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 1983, 1991, 1993, 1994
27 * The Regents of the University of California. All rights reserved.
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 static char copyright
[] =
60 "@(#) Copyright (c) 1983, 1991, 1993, 1994\n\
61 The Regents of the University of California. All rights reserved.\n";
65 static char sccsid
[] = "@(#)inetd.c 8.4 (Berkeley) 4/13/94";
69 * Inetd - Internet super-server
71 * This program invokes all internet services as needed. Connection-oriented
72 * services are invoked each time a connection is made, by creating a process.
73 * This process is passed the connection as file descriptor 0 and is expected
74 * to do a getpeername to find out the source host and port.
76 * Datagram oriented services are invoked when a datagram
77 * arrives; a process is created and passed a pending message
78 * on file descriptor 0. Datagram servers may either connect
79 * to their peer, freeing up the original socket for inetd
80 * to receive further messages on, or ``take over the socket'',
81 * processing all arriving datagrams and, eventually, timing
82 * out. The first type of server is said to be ``multi-threaded'';
83 * the second type of server ``single-threaded''.
85 * Inetd uses a configuration file which is read at startup
86 * and, possibly, at some later time in response to a hangup signal.
87 * The configuration file is ``free format'' with fields given in the
88 * order shown below. Continuation lines for an entry must being with
89 * a space or tab. All fields must be present in each entry.
91 * service name must be in /etc/services or must
92 * name a tcpmux service
93 * socket type stream/dgram/raw/rdm/seqpacket
94 * protocol must be in /etc/protocols
95 * wait/nowait single-threaded/multi-threaded
96 * user user to run daemon as
97 * server program full path name
98 * server program arguments maximum of MAXARGS (20)
100 * TCP services without official port numbers are handled with the
101 * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for
102 * requests. When a connection is made from a foreign host, the service
103 * requested is passed to tcpmux, which looks it up in the servtab list
104 * and returns the proper entry for the service. Tcpmux returns a
105 * negative reply if the service doesn't exist, otherwise the invoked
106 * server is expected to return the positive reply if the service type in
107 * inetd.conf file has the prefix "tcpmux/". If the service type has the
108 * prefix "tcpmux/+", tcpmux will return the positive reply for the
109 * process; this is for compatibility with older server code, and also
110 * allows you to invoke programs that use stdin/stdout without putting any
111 * special server code in them. Services that use tcpmux are "nowait"
112 * because they do not have a well-known port and hence cannot listen
115 * Comment lines are indicated by a `#' in column 1.
117 #include <sys/param.h>
118 #include <sys/stat.h>
119 #include <sys/ioctl.h>
120 #include <sys/socket.h>
121 #include <sys/wait.h>
122 #include <sys/time.h>
123 #include <sys/resource.h>
125 #include <netinet/in.h>
126 #include <arpa/inet.h>
139 #include "pathnames.h"
141 #define TOOMANY 100 /* don't start more than TOOMANY */
142 #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */
143 #define RETRYTIME (60*10) /* retry after bind or server fail */
145 #define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
153 int toomany
= TOOMANY
;
157 char *se_service
; /* name of service */
158 int se_socktype
; /* type of socket to use */
159 char *se_proto
; /* protocol used */
160 short se_wait
; /* single threaded server */
161 short se_checked
; /* looked at during merge */
162 char *se_user
; /* user name to run as */
163 struct biltin
*se_bi
; /* if built-in, description */
164 char *se_server
; /* server program */
166 char *se_argv
[MAXARGV
+1]; /* program arguments */
167 int se_fd
; /* open descriptor */
168 int se_type
; /* type */
169 struct sockaddr_in se_ctrladdr
;/* bound address */
170 int se_count
; /* number started since se_time */
171 struct timeval se_time
; /* start of se_count */
172 struct servtab
*se_next
;
177 #define MUXPLUS_TYPE 2
178 #define ISMUX(sep) (((sep)->se_type == MUX_TYPE) || \
179 ((sep)->se_type == MUXPLUS_TYPE))
180 #define ISMUXPLUS(sep) ((sep)->se_type == MUXPLUS_TYPE)
183 void chargen_dg
__P((int, struct servtab
*));
184 void chargen_stream
__P((int, struct servtab
*));
185 void close_sep
__P((struct servtab
*));
186 void config
__P((int));
187 void daytime_dg
__P((int, struct servtab
*));
188 void daytime_stream
__P((int, struct servtab
*));
189 void discard_dg
__P((int, struct servtab
*));
190 void discard_stream
__P((int, struct servtab
*));
191 void echo_dg
__P((int, struct servtab
*));
192 void echo_stream
__P((int, struct servtab
*));
193 void endconfig
__P((void));
194 struct servtab
*enter
__P((struct servtab
*));
195 void freeconfig
__P((struct servtab
*));
196 struct servtab
*getconfigent
__P((void));
197 void machtime_dg
__P((int, struct servtab
*));
198 void machtime_stream
__P((int, struct servtab
*));
199 char *newstr
__P((char *));
200 char *nextline
__P((FILE *));
201 void print_service
__P((char *, struct servtab
*));
202 void reapchild
__P((int));
203 void retry
__P((int));
204 int setconfig
__P((void));
205 void setup
__P((struct servtab
*));
206 char *sskip
__P((char **));
207 char *skip
__P((char **));
208 struct servtab
*tcpmux
__P((int));
211 char *bi_service
; /* internally provided service name */
212 int bi_socktype
; /* type of socket supported */
213 short bi_fork
; /* 1 if should fork before call */
214 short bi_wait
; /* 1 if should wait for child */
215 void (*bi_fn
)(); /* function which performs it */
217 /* Echo received data */
218 { "echo", SOCK_STREAM
, 1, 0, echo_stream
},
219 { "echo", SOCK_DGRAM
, 0, 0, echo_dg
},
221 /* Internet /dev/null */
222 { "discard", SOCK_STREAM
, 1, 0, discard_stream
},
223 { "discard", SOCK_DGRAM
, 0, 0, discard_dg
},
225 /* Return 32 bit time since 1970 */
226 { "time", SOCK_STREAM
, 0, 0, machtime_stream
},
227 { "time", SOCK_DGRAM
, 0, 0, machtime_dg
},
229 /* Return human-readable time */
230 { "daytime", SOCK_STREAM
, 0, 0, daytime_stream
},
231 { "daytime", SOCK_DGRAM
, 0, 0, daytime_dg
},
233 /* Familiar character generator */
234 { "chargen", SOCK_STREAM
, 1, 0, chargen_stream
},
235 { "chargen", SOCK_DGRAM
, 0, 0, chargen_dg
},
237 { "tcpmux", SOCK_STREAM
, 1, 0, (void (*)())tcpmux
},
242 #define NUMINT (sizeof(intab) / sizeof(struct inent))
243 char *CONFIG
= _PATH_INETDCONF
;
244 char *pid_file
= _PATH_INETDPID
;
249 main(argc
, argv
, envp
)
251 char *argv
[], *envp
[];
256 int tmpint
, ch
, dofork
;
261 if (envp
== 0 || *envp
== 0)
265 LastArg
= envp
[-1] + strlen(envp
[-1]);
267 openlog("inetd", LOG_PID
| LOG_NOWAIT
, LOG_DAEMON
);
269 while ((ch
= getopt(argc
, argv
, "dR:p:")) != EOF
)
275 case 'R': { /* invocation rate */
278 tmpint
= strtol(optarg
, &p
, 0);
279 if (tmpint
< 1 || *p
)
281 "-R %s: bad value for service invocation rate",
293 "usage: inetd [-d] [-R rate] [conf-file]");
306 fp
= fopen(pid_file
, "w");
308 fprintf(fp
, "%ld\n", (long)pid
);
311 syslog(LOG_WARNING
, "%s: %m", pid_file
);
314 memset(&sv
, 0, sizeof(sv
));
315 sv
.sv_mask
= SIGBLOCK
;
316 sv
.sv_handler
= retry
;
317 sigvec(SIGALRM
, &sv
, (struct sigvec
*)0);
319 sv
.sv_handler
= config
;
320 sigvec(SIGHUP
, &sv
, (struct sigvec
*)0);
321 sv
.sv_handler
= reapchild
;
322 sigvec(SIGCHLD
, &sv
, (struct sigvec
*)0);
325 /* space for daemons to overwrite environment for ps */
326 #define DUMMYSIZE 100
327 char dummy
[DUMMYSIZE
];
329 (void)memset(dummy
, 'x', sizeof(DUMMYSIZE
) - 1);
330 dummy
[DUMMYSIZE
- 1] = '\0';
331 (void)setenv("inetd_dummy", dummy
, 1);
339 (void) sigblock(SIGBLOCK
);
342 (void) sigsetmask(0L);
345 if ((n
= select(maxsock
+ 1, &readable
, (fd_set
*)0,
346 (fd_set
*)0, (struct timeval
*)0)) <= 0) {
347 if (n
< 0 && errno
!= EINTR
) {
348 syslog(LOG_WARNING
, "select: %m");
353 for (sep
= servtab
; n
&& sep
; sep
= sep
->se_next
)
354 if (sep
->se_fd
!= -1 && FD_ISSET(sep
->se_fd
, &readable
)) {
357 fprintf(stderr
, "someone wants %s\n",
359 if (!sep
->se_wait
&& sep
->se_socktype
== SOCK_STREAM
) {
360 ctrl
= accept(sep
->se_fd
, (struct sockaddr
*)0,
363 fprintf(stderr
, "accept, ctrl %d\n", ctrl
);
367 "accept (for %s): %m",
372 * Call tcpmux to find the real service to exec.
375 sep
->se_bi
->bi_fn
== (void (*)()) tcpmux
) {
384 (void) sigblock(SIGBLOCK
);
386 dofork
= (sep
->se_bi
== 0 || sep
->se_bi
->bi_fork
);
388 if (sep
->se_count
++ == 0)
389 (void)gettimeofday(&sep
->se_time
,
390 (struct timezone
*)0);
391 else if (sep
->se_count
>= toomany
) {
394 (void)gettimeofday(&now
, (struct timezone
*)0);
395 if (now
.tv_sec
- sep
->se_time
.tv_sec
>
401 "%s/%s server failing (looping), service terminated",
402 sep
->se_service
, sep
->se_proto
);
415 syslog(LOG_ERR
, "fork: %m");
417 sep
->se_socktype
== SOCK_STREAM
)
423 if (pid
&& sep
->se_wait
) {
425 if (sep
->se_fd
>= 0) {
426 FD_CLR(sep
->se_fd
, &allsock
);
436 fprintf(stderr
, "+ Closing from %d\n",
438 for (tmpint
= maxsock
; tmpint
> 2; tmpint
--)
443 (*sep
->se_bi
->bi_fn
)(ctrl
, sep
);
446 fprintf(stderr
, "%d execl %s\n",
447 getpid(), sep
->se_server
);
452 if ((pwd
= getpwnam(sep
->se_user
)) == NULL
) {
454 "%s/%s: %s: No such user",
455 sep
->se_service
, sep
->se_proto
,
457 if (sep
->se_socktype
!= SOCK_STREAM
)
458 recv(0, buf
, sizeof (buf
), 0);
462 if (setgid(pwd
->pw_gid
) < 0) {
464 "%s: can't set gid %d: %m",
465 sep
->se_service
, pwd
->pw_gid
);
468 (void) initgroups(pwd
->pw_name
,
470 if (setuid(pwd
->pw_uid
) < 0) {
472 "%s: can't set uid %d: %m",
473 sep
->se_service
, pwd
->pw_uid
);
477 execv(sep
->se_server
, sep
->se_argv
);
478 if (sep
->se_socktype
!= SOCK_STREAM
)
479 recv(0, buf
, sizeof (buf
), 0);
481 "cannot execute %s: %m", sep
->se_server
);
485 if (!sep
->se_wait
&& sep
->se_socktype
== SOCK_STREAM
)
500 pid
= wait3(&status
, WNOHANG
, (struct rusage
*)0);
504 fprintf(stderr
, "%d reaped, status %#x\n",
506 for (sep
= servtab
; sep
; sep
= sep
->se_next
)
507 if (sep
->se_wait
== pid
) {
510 "%s: exit status 0x%x",
511 sep
->se_server
, status
);
513 fprintf(stderr
, "restored %s, fd %d\n",
514 sep
->se_service
, sep
->se_fd
);
515 FD_SET(sep
->se_fd
, &allsock
);
526 struct servtab
*sep
, *cp
, **sepp
;
531 syslog(LOG_ERR
, "%s: %m", CONFIG
);
534 for (sep
= servtab
; sep
; sep
= sep
->se_next
)
536 while (cp
= getconfigent()) {
537 if ((pwd
= getpwnam(cp
->se_user
)) == NULL
) {
539 "%s/%s: No such user '%s', service ignored",
540 cp
->se_service
, cp
->se_proto
, cp
->se_user
);
543 for (sep
= servtab
; sep
; sep
= sep
->se_next
)
544 if (strcmp(sep
->se_service
, cp
->se_service
) == 0 &&
545 strcmp(sep
->se_proto
, cp
->se_proto
) == 0)
550 omask
= sigblock(SIGBLOCK
);
552 * sep->se_wait may be holding the pid of a daemon
553 * that we're waiting for. If so, don't overwrite
554 * it unless the config file explicitly says don't
557 if (cp
->se_bi
== 0 &&
558 (sep
->se_wait
== 1 || cp
->se_wait
== 0))
559 sep
->se_wait
= cp
->se_wait
;
560 #define SWAP(a, b) { char *c = a; a = b; b = c; }
562 SWAP(sep
->se_user
, cp
->se_user
);
564 SWAP(sep
->se_server
, cp
->se_server
);
565 for (i
= 0; i
< MAXARGV
; i
++)
566 SWAP(sep
->se_argv
[i
], cp
->se_argv
[i
]);
570 print_service("REDO", sep
);
574 print_service("ADD ", sep
);
581 sp
= getservbyname(sep
->se_service
, sep
->se_proto
);
583 syslog(LOG_ERR
, "%s/%s: unknown service",
584 sep
->se_service
, sep
->se_proto
);
588 if (sp
->s_port
!= sep
->se_ctrladdr
.sin_port
) {
589 sep
->se_ctrladdr
.sin_family
= AF_INET
;
590 sep
->se_ctrladdr
.sin_port
= sp
->s_port
;
594 if (sep
->se_fd
== -1)
599 * Purge anything not looked at above.
601 omask
= sigblock(SIGBLOCK
);
603 while (sep
= *sepp
) {
604 if (sep
->se_checked
) {
605 sepp
= &sep
->se_next
;
608 *sepp
= sep
->se_next
;
612 print_service("FREE", sep
);
616 (void) sigsetmask(omask
);
626 for (sep
= servtab
; sep
; sep
= sep
->se_next
)
627 if (sep
->se_fd
== -1)
637 if ((sep
->se_fd
= socket(AF_INET
, sep
->se_socktype
, 0)) < 0) {
639 fprintf(stderr
, "socket failed on %s/%s: %s\n",
640 sep
->se_service
, sep
->se_proto
,
642 syslog(LOG_ERR
, "%s/%s: socket: %m",
643 sep
->se_service
, sep
->se_proto
);
646 #define turnon(fd, opt) \
647 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
648 if (strcmp(sep
->se_proto
, "tcp") == 0 && (options
& SO_DEBUG
) &&
649 turnon(sep
->se_fd
, SO_DEBUG
) < 0)
650 syslog(LOG_ERR
, "setsockopt (SO_DEBUG): %m");
651 if (turnon(sep
->se_fd
, SO_REUSEADDR
) < 0)
652 syslog(LOG_ERR
, "setsockopt (SO_REUSEADDR): %m");
654 if (bind(sep
->se_fd
, (struct sockaddr
*)&sep
->se_ctrladdr
,
655 sizeof (sep
->se_ctrladdr
)) < 0) {
657 fprintf(stderr
, "bind failed on %s/%s: %s\n",
658 sep
->se_service
, sep
->se_proto
,
660 syslog(LOG_ERR
, "%s/%s: bind: %m",
661 sep
->se_service
, sep
->se_proto
);
662 (void) close(sep
->se_fd
);
670 if (sep
->se_socktype
== SOCK_STREAM
)
671 listen(sep
->se_fd
, 10);
672 FD_SET(sep
->se_fd
, &allsock
);
674 if (sep
->se_fd
> maxsock
)
675 maxsock
= sep
->se_fd
;
677 fprintf(stderr
, "registered %s on %d\n",
678 sep
->se_server
, sep
->se_fd
);
683 * Finish with a service and its socket.
689 if (sep
->se_fd
>= 0) {
691 FD_CLR(sep
->se_fd
, &allsock
);
692 (void) close(sep
->se_fd
);
697 * Don't keep the pid of this running deamon: when reapchild()
698 * reaps this pid, it would erroneously increment nsock.
700 if (sep
->se_wait
> 1)
711 sep
= (struct servtab
*)malloc(sizeof (*sep
));
712 if (sep
== (struct servtab
*)0) {
713 syslog(LOG_ERR
, "Out of memory.");
718 omask
= sigblock(SIGBLOCK
);
719 sep
->se_next
= servtab
;
725 FILE *fconfig
= NULL
;
733 if (fconfig
!= NULL
) {
734 fseek(fconfig
, 0L, SEEK_SET
);
737 fconfig
= fopen(CONFIG
, "r");
738 return (fconfig
!= NULL
);
745 (void) fclose(fconfig
);
753 struct servtab
*sep
= &serv
;
756 static char TCPMUX_TOKEN
[] = "tcpmux/";
757 #define MUX_LEN (sizeof(TCPMUX_TOKEN)-1)
760 while ((cp
= nextline(fconfig
)) && (*cp
== '#' || *cp
== '\0'))
763 return ((struct servtab
*)0);
765 * clear the static buffer, since some fields (se_ctrladdr,
766 * for example) don't get initialized here.
768 memset((caddr_t
)sep
, 0, sizeof *sep
);
771 /* got an empty line containing just blanks/tabs. */
774 if (strncmp(arg
, TCPMUX_TOKEN
, MUX_LEN
) == 0) {
775 char *c
= arg
+ MUX_LEN
;
777 sep
->se_type
= MUXPLUS_TYPE
;
780 sep
->se_type
= MUX_TYPE
;
781 sep
->se_service
= newstr(c
);
783 sep
->se_service
= newstr(arg
);
784 sep
->se_type
= NORM_TYPE
;
787 if (strcmp(arg
, "stream") == 0)
788 sep
->se_socktype
= SOCK_STREAM
;
789 else if (strcmp(arg
, "dgram") == 0)
790 sep
->se_socktype
= SOCK_DGRAM
;
791 else if (strcmp(arg
, "rdm") == 0)
792 sep
->se_socktype
= SOCK_RDM
;
793 else if (strcmp(arg
, "seqpacket") == 0)
794 sep
->se_socktype
= SOCK_SEQPACKET
;
795 else if (strcmp(arg
, "raw") == 0)
796 sep
->se_socktype
= SOCK_RAW
;
798 sep
->se_socktype
= -1;
799 sep
->se_proto
= newstr(sskip(&cp
));
801 sep
->se_wait
= strcmp(arg
, "wait") == 0;
804 * Silently enforce "nowait" for TCPMUX services since
805 * they don't have an assigned port to listen on.
809 if (strcmp(sep
->se_proto
, "tcp")) {
811 "%s: bad protocol for tcpmux service %s",
812 CONFIG
, sep
->se_service
);
815 if (sep
->se_socktype
!= SOCK_STREAM
) {
817 "%s: bad socket type for tcpmux service %s",
818 CONFIG
, sep
->se_service
);
822 sep
->se_user
= newstr(sskip(&cp
));
823 sep
->se_server
= newstr(sskip(&cp
));
824 if (strcmp(sep
->se_server
, "internal") == 0) {
827 for (bi
= biltins
; bi
->bi_service
; bi
++)
828 if (bi
->bi_socktype
== sep
->se_socktype
&&
829 strcmp(bi
->bi_service
, sep
->se_service
) == 0)
831 if (bi
->bi_service
== 0) {
832 syslog(LOG_ERR
, "internal service %s unknown",
837 sep
->se_wait
= bi
->bi_wait
;
841 for (arg
= skip(&cp
); cp
; arg
= skip(&cp
))
843 sep
->se_argv
[argc
++] = newstr(arg
);
844 while (argc
<= MAXARGV
)
845 sep
->se_argv
[argc
++] = NULL
;
856 free(cp
->se_service
);
863 for (i
= 0; i
< MAXARGV
; i
++)
865 free(cp
->se_argv
[i
]);
870 * Safe skip - if skip returns null, log a syntax error in the
871 * configuration file and exit.
881 syslog(LOG_ERR
, "%s: syntax error", CONFIG
);
895 while (*cp
== ' ' || *cp
== '\t')
901 (void) ungetc(c
, fconfig
);
902 if (c
== ' ' || c
== '\t')
903 if (cp
= nextline(fconfig
))
909 while (*cp
&& *cp
!= ' ' && *cp
!= '\t')
923 if (fgets(line
, sizeof (line
), fd
) == NULL
)
925 cp
= strchr(line
, '\n');
935 if (cp
= strdup(cp
? cp
: ""))
937 syslog(LOG_ERR
, "strdup: %m");
948 struct sockaddr_in sin
;
953 if (getpeername(s
, (struct sockaddr
*)&sin
, &size
) == 0)
954 (void) sprintf(buf
, "-%s [%s]", a
, inet_ntoa(sin
.sin_addr
));
956 (void) sprintf(buf
, "-%s", a
);
957 strncpy(cp
, buf
, LastArg
- cp
);
964 * Internet services provided internally by inetd:
970 echo_stream(s
, sep
) /* Echo service -- echo data back */
974 char buffer
[BUFSIZE
];
977 setproctitle(sep
->se_service
, s
);
978 while ((i
= read(s
, buffer
, sizeof(buffer
))) > 0 &&
979 write(s
, buffer
, i
) > 0)
986 echo_dg(s
, sep
) /* Echo service -- echo data back */
990 char buffer
[BUFSIZE
];
995 if ((i
= recvfrom(s
, buffer
, sizeof(buffer
), 0, &sa
, &size
)) < 0)
997 (void) sendto(s
, buffer
, i
, 0, &sa
, sizeof(sa
));
1002 discard_stream(s
, sep
) /* Discard service -- ignore data */
1004 struct servtab
*sep
;
1007 char buffer
[BUFSIZE
];
1009 setproctitle(sep
->se_service
, s
);
1011 while ((ret
= read(s
, buffer
, sizeof(buffer
))) > 0)
1013 if (ret
== 0 || errno
!= EINTR
)
1021 discard_dg(s
, sep
) /* Discard service -- ignore data */
1023 struct servtab
*sep
;
1025 char buffer
[BUFSIZE
];
1027 (void) read(s
, buffer
, sizeof(buffer
));
1042 for (i
= 0; i
<= 128; ++i
)
1049 chargen_stream(s
, sep
) /* Character generator */
1051 struct servtab
*sep
;
1054 char *rs
, text
[LINESIZ
+2];
1056 setproctitle(sep
->se_service
, s
);
1063 text
[LINESIZ
] = '\r';
1064 text
[LINESIZ
+ 1] = '\n';
1066 if ((len
= endring
- rs
) >= LINESIZ
)
1067 memmove(text
, rs
, LINESIZ
);
1069 memmove(text
, rs
, len
);
1070 memmove(text
+ len
, ring
, LINESIZ
- len
);
1072 if (++rs
== endring
)
1074 if (write(s
, text
, sizeof(text
)) != sizeof(text
))
1082 chargen_dg(s
, sep
) /* Character generator */
1084 struct servtab
*sep
;
1089 char text
[LINESIZ
+2];
1097 if (recvfrom(s
, text
, sizeof(text
), 0, &sa
, &size
) < 0)
1100 if ((len
= endring
- rs
) >= LINESIZ
)
1101 memmove(text
, rs
, LINESIZ
);
1103 memmove(text
, rs
, len
);
1104 memmove(text
+ len
, ring
, LINESIZ
- len
);
1106 if (++rs
== endring
)
1108 text
[LINESIZ
] = '\r';
1109 text
[LINESIZ
+ 1] = '\n';
1110 (void) sendto(s
, text
, sizeof(text
), 0, &sa
, sizeof(sa
));
1114 * Return a machine readable date and time, in the form of the
1115 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
1116 * returns the number of seconds since midnight, Jan 1, 1970,
1117 * we must add 2208988800 seconds to this figure to make up for
1118 * some seventy years Bell Labs was asleep.
1126 if (gettimeofday(&tv
, (struct timezone
*)0) < 0) {
1128 fprintf(stderr
, "Unable to get time of day\n");
1131 #define OFFSET ((u_long)25567 * 24*60*60)
1132 return (htonl((long)(tv
.tv_sec
+ OFFSET
)));
1138 machtime_stream(s
, sep
)
1140 struct servtab
*sep
;
1144 result
= machtime();
1145 (void) write(s
, (char *) &result
, sizeof(result
));
1152 struct servtab
*sep
;
1159 if (recvfrom(s
, (char *)&result
, sizeof(result
), 0, &sa
, &size
) < 0)
1161 result
= machtime();
1162 (void) sendto(s
, (char *) &result
, sizeof(result
), 0, &sa
, sizeof(sa
));
1167 daytime_stream(s
, sep
) /* Return human-readable time of day */
1169 struct servtab
*sep
;
1174 clock
= time((time_t *) 0);
1176 (void) sprintf(buffer
, "%.24s\r\n", ctime(&clock
));
1177 (void) write(s
, buffer
, strlen(buffer
));
1182 daytime_dg(s
, sep
) /* Return human-readable time of day */
1184 struct servtab
*sep
;
1191 clock
= time((time_t *) 0);
1194 if (recvfrom(s
, buffer
, sizeof(buffer
), 0, &sa
, &size
) < 0)
1196 (void) sprintf(buffer
, "%.24s\r\n", ctime(&clock
));
1197 (void) sendto(s
, buffer
, strlen(buffer
), 0, &sa
, sizeof(sa
));
1202 * Dump relevant information to stderr
1205 print_service(action
, sep
)
1207 struct servtab
*sep
;
1210 "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
1211 action
, sep
->se_service
, sep
->se_proto
,
1212 sep
->se_wait
, sep
->se_user
, (int)sep
->se_bi
, sep
->se_server
);
1216 * Based on TCPMUX.C by Mark K. Lottor November 1988
1217 * sri-nic::ps:<mkl>tcpmux.c
1221 static int /* # of characters upto \r,\n or \0 */
1222 getline(fd
, buf
, len
)
1230 n
= read(fd
, buf
, len
-count
);
1236 if (*buf
== '\r' || *buf
== '\n' || *buf
== '\0')
1241 } while (count
< len
);
1245 #define MAX_SERV_LEN (256+2) /* 2 bytes for \r\n */
1247 #define strwrite(fd, buf) (void) write(fd, buf, sizeof(buf)-1)
1253 struct servtab
*sep
;
1254 char service
[MAX_SERV_LEN
+1];
1257 /* Get requested service name */
1258 if ((len
= getline(s
, service
, MAX_SERV_LEN
)) < 0) {
1259 strwrite(s
, "-Error reading service name\r\n");
1262 service
[len
] = '\0';
1265 fprintf(stderr
, "tcpmux: someone wants %s\n", service
);
1268 * Help is a required command, and lists available services,
1271 if (!strcasecmp(service
, "help")) {
1272 for (sep
= servtab
; sep
; sep
= sep
->se_next
) {
1275 (void)write(s
,sep
->se_service
,strlen(sep
->se_service
));
1276 strwrite(s
, "\r\n");
1281 /* Try matching a service in inetd.conf with the request */
1282 for (sep
= servtab
; sep
; sep
= sep
->se_next
) {
1285 if (!strcasecmp(service
, sep
->se_service
)) {
1286 if (ISMUXPLUS(sep
)) {
1287 strwrite(s
, "+Go\r\n");
1292 strwrite(s
, "-Service not available\r\n");