2 * Copyright (c) 1983, 1991, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/usr.sbin/inetd/builtins.c,v 1.19.2.7 2002/07/22 14:05:56 fanf Exp $
27 * $DragonFly: src/usr.sbin/inetd/builtins.c,v 1.5 2004/12/18 22:48:03 swildner Exp $
31 #include <sys/filio.h>
32 #include <sys/param.h>
34 #include <sys/socket.h>
35 #include <sys/sysctl.h>
36 #include <sys/ucred.h>
38 #include <sys/utsname.h>
55 void chargen_dg(int, struct servtab
*);
56 void chargen_stream(int, struct servtab
*);
57 void daytime_dg(int, struct servtab
*);
58 void daytime_stream(int, struct servtab
*);
59 void discard_dg(int, struct servtab
*);
60 void discard_stream(int, struct servtab
*);
61 void echo_dg(int, struct servtab
*);
62 void echo_stream(int, struct servtab
*);
63 static int getline(int, char *, int);
64 void iderror(int, int, int, const char *);
65 void ident_stream(int, struct servtab
*);
67 unsigned long machtime(void);
68 void machtime_dg(int, struct servtab
*);
69 void machtime_stream(int, struct servtab
*);
75 struct biltin biltins
[] = {
76 /* Echo received data */
77 { "echo", SOCK_STREAM
, 1, -1, echo_stream
},
78 { "echo", SOCK_DGRAM
, 0, 1, echo_dg
},
80 /* Internet /dev/null */
81 { "discard", SOCK_STREAM
, 1, -1, discard_stream
},
82 { "discard", SOCK_DGRAM
, 0, 1, discard_dg
},
84 /* Return 32 bit time since 1900 */
85 { "time", SOCK_STREAM
, 0, -1, machtime_stream
},
86 { "time", SOCK_DGRAM
, 0, 1, machtime_dg
},
88 /* Return human-readable time */
89 { "daytime", SOCK_STREAM
, 0, -1, daytime_stream
},
90 { "daytime", SOCK_DGRAM
, 0, 1, daytime_dg
},
92 /* Familiar character generator */
93 { "chargen", SOCK_STREAM
, 1, -1, chargen_stream
},
94 { "chargen", SOCK_DGRAM
, 0, 1, chargen_dg
},
96 { "tcpmux", SOCK_STREAM
, 1, -1, (bi_fn_t
*)tcpmux
},
98 { "auth", SOCK_STREAM
, 1, -1, ident_stream
},
100 { NULL
, 0, 0, 0, NULL
}
104 * RFC864 Character Generator Protocol. Generates character data without
105 * any regard for input.
115 for (i
= 0; i
<= 128; ++i
)
122 chargen_dg(int s
, struct servtab
*sep
) /* Character generator */
124 struct sockaddr_storage ss
;
128 char text
[LINESIZ
+2];
136 if (recvfrom(s
, text
, sizeof(text
), 0,
137 (struct sockaddr
*)&ss
, &size
) < 0)
140 if (check_loop((struct sockaddr
*)&ss
, sep
))
143 if ((len
= endring
- rs
) >= LINESIZ
)
144 memmove(text
, rs
, LINESIZ
);
146 memmove(text
, rs
, len
);
147 memmove(text
+ len
, ring
, LINESIZ
- len
);
151 text
[LINESIZ
] = '\r';
152 text
[LINESIZ
+ 1] = '\n';
153 sendto(s
, text
, sizeof(text
), 0, (struct sockaddr
*)&ss
, size
);
158 chargen_stream(int s
, struct servtab
*sep
) /* Character generator */
161 char *rs
, text
[LINESIZ
+2];
163 inetd_setproctitle(sep
->se_service
, s
);
170 text
[LINESIZ
] = '\r';
171 text
[LINESIZ
+ 1] = '\n';
173 if ((len
= endring
- rs
) >= LINESIZ
)
174 memmove(text
, rs
, LINESIZ
);
176 memmove(text
, rs
, len
);
177 memmove(text
+ len
, ring
, LINESIZ
- len
);
181 if (write(s
, text
, sizeof(text
)) != sizeof(text
))
188 * RFC867 Daytime Protocol. Sends the current date and time as an ascii
189 * character string without any regard for input.
194 daytime_dg(int s
, struct servtab
*sep
) /* Return human-readable time of day */
198 struct sockaddr_storage ss
;
204 if (recvfrom(s
, buffer
, sizeof(buffer
), 0,
205 (struct sockaddr
*)&ss
, &size
) < 0)
208 if (check_loop((struct sockaddr
*)&ss
, sep
))
211 sprintf(buffer
, "%.24s\r\n", ctime(&now
));
212 sendto(s
, buffer
, strlen(buffer
), 0, (struct sockaddr
*)&ss
, size
);
217 daytime_stream(int s
, struct servtab
*sep __unused
) /* Return human-readable time of day */
224 sprintf(buffer
, "%.24s\r\n", ctime(&now
));
225 send(s
, buffer
, strlen(buffer
), MSG_EOF
);
229 * RFC863 Discard Protocol. Any data received is thrown away and no response
235 discard_dg(int s
, struct servtab
*sep __unused
) /* Discard service -- ignore data */
237 char buffer
[BUFSIZE
];
239 read(s
, buffer
, sizeof(buffer
));
244 discard_stream(int s
, struct servtab
*sep
) /* Discard service -- ignore data */
247 char buffer
[BUFSIZE
];
249 inetd_setproctitle(sep
->se_service
, s
);
251 while ((ret
= read(s
, buffer
, sizeof(buffer
))) > 0)
253 if (ret
== 0 || errno
!= EINTR
)
260 * RFC862 Echo Protocol. Any data received is sent back to the sender as
266 echo_dg(int s
, struct servtab
*sep
) /* Echo service -- echo data back */
268 char buffer
[65536]; /* Should be sizeof(max datagram). */
271 struct sockaddr_storage ss
;
274 if ((i
= recvfrom(s
, buffer
, sizeof(buffer
), 0,
275 (struct sockaddr
*)&ss
, &size
)) < 0)
278 if (check_loop((struct sockaddr
*)&ss
, sep
))
281 sendto(s
, buffer
, i
, 0, (struct sockaddr
*)&ss
, size
);
286 echo_stream(int s
, struct servtab
*sep
) /* Echo service -- echo data back */
288 char buffer
[BUFSIZE
];
291 inetd_setproctitle(sep
->se_service
, s
);
292 while ((i
= read(s
, buffer
, sizeof(buffer
))) > 0 &&
293 write(s
, buffer
, i
) > 0)
299 * RFC1413 Identification Protocol. Given a TCP port number pair, return a
300 * character string which identifies the owner of that connection on the
301 * server's system. Extended to allow for ~/.fakeid support and ~/.noident
305 /* RFC 1413 says the following are the only errors you can return. */
306 #define ID_INVALID "INVALID-PORT" /* Port number improperly specified. */
307 #define ID_NOUSER "NO-USER" /* Port not in use/not identifable. */
308 #define ID_HIDDEN "HIDDEN-USER" /* Hiden at user's request. */
309 #define ID_UNKNOWN "UNKNOWN-ERROR" /* Everything else. */
313 iderror(int lport
, int fport
, int s
, const char *er
) /* Generic ident_stream error-sending func */
317 asprintf(&p
, "%d , %d : ERROR : %s\r\n", lport
, fport
, er
);
319 syslog(LOG_ERR
, "asprintf: %m");
322 send(s
, p
, strlen(p
), MSG_EOF
);
330 ident_stream(int s
, struct servtab
*sep
) /* Ident service (AKA "auth") */
334 struct sockaddr_in sin4
[2];
336 struct sockaddr_in6 sin6
[2];
338 struct sockaddr_storage ss
[2];
340 struct timeval tv
= {
344 struct passwd
*pw
= NULL
;
346 char buf
[BUFSIZE
], *p
, **av
, *osname
= NULL
, e
;
347 char idbuf
[MAXLOGNAME
] = ""; /* Big enough to hold uid in decimal. */
351 int c
, fflag
= 0, nflag
= 0, rflag
= 0, argc
= 0;
352 int gflag
= 0, iflag
= 0, Fflag
= 0, getcredfail
= 0, onreadlen
;
353 u_short lport
, fport
;
355 inetd_setproctitle(sep
->se_service
, s
);
357 * Reset getopt() since we are a fork() but not an exec() from
358 * a parent which used getopt() already.
363 * Take the internal argument vector and count it out to make an
364 * argument count for getopt. This can be used for any internal
365 * service to read arguments and use getopt() easily.
367 for (av
= sep
->se_argv
; *av
; av
++)
374 while ((c
= getopt(argc
, sep
->se_argv
, "d:fFgino:rt:")) != -1)
378 strlcpy(idbuf
, optarg
, sizeof(idbuf
));
389 rnd32
= 0; /* Shush, compiler. */
391 * The number of bits in "rnd32" divided
392 * by the number of bits needed per iteration
393 * gives a more optimal way to reload the
394 * random number only when necessary.
396 * 32 bits from arc4random corresponds to
397 * about 6 base-36 digits, so we reseed evey 6.
399 for (i
= 0; i
< sizeof(idbuf
) - 1; i
++) {
400 static const char *const base36
=
402 "abcdefghijklmnopqrstuvwxyz";
404 rnd32
= arc4random();
405 idbuf
[i
] = base36
[rnd32
% 36];
423 switch (sscanf(optarg
, "%d.%d", &sec
, &usec
)) {
432 warnx("bad -t argument");
440 if (osname
== NULL
) {
441 if (uname(&un
) == -1)
442 iderror(0, 0, s
, ID_UNKNOWN
);
447 * We're going to prepare for and execute reception of a
448 * packet of data from the user. The data is in the format
449 * "local_port , foreign_port\r\n" (with local being the
450 * server's port and foreign being the client's.)
452 gettimeofday(&to
, NULL
);
453 to
.tv_sec
+= tv
.tv_sec
;
454 to
.tv_usec
+= tv
.tv_usec
;
455 if (to
.tv_usec
>= 1000000) {
456 to
.tv_usec
-= 1000000;
461 bufsiz
= sizeof(buf
) - 1;
464 gettimeofday(&tv
, NULL
);
465 tv
.tv_sec
= to
.tv_sec
- tv
.tv_sec
;
466 tv
.tv_usec
= to
.tv_usec
- tv
.tv_usec
;
467 if (tv
.tv_usec
< 0) {
468 tv
.tv_usec
+= 1000000;
474 if (select(s
+ 1, &fdset
, NULL
, NULL
, &tv
) == -1)
475 iderror(0, 0, s
, ID_UNKNOWN
);
476 if (ioctl(s
, FIONREAD
, &onreadlen
) == -1)
477 iderror(0, 0, s
, ID_UNKNOWN
);
478 if ((size_t)onreadlen
> bufsiz
)
480 ssize
= read(s
, &buf
[size
], (size_t)onreadlen
);
482 iderror(0, 0, s
, ID_UNKNOWN
);
487 if (memchr(&buf
[size
- ssize
], '\n', ssize
) != NULL
)
491 /* Read two characters, and check for a delimiting character */
492 if (sscanf(buf
, "%hu , %hu%c", &lport
, &fport
, &e
) != 3 || isdigit(e
))
493 iderror(0, 0, s
, ID_INVALID
);
500 * If not "real" (-r), send a HIDDEN-USER error for everything.
501 * If -d is used to set a fallback username, this is used to
502 * override it, and the fallback is returned instead.
506 iderror(lport
, fport
, s
, ID_HIDDEN
);
511 * We take the input and construct an array of two sockaddr_ins
512 * which contain the local address information and foreign
513 * address information, respectively, used to look up the
514 * credentials for the socket (which are returned by the
515 * sysctl "net.inet.tcp.getcred" when we call it.)
517 socklen
= sizeof(ss
[0]);
518 if (getsockname(s
, (struct sockaddr
*)&ss
[0], &socklen
) == -1)
519 iderror(lport
, fport
, s
, ID_UNKNOWN
);
520 socklen
= sizeof(ss
[1]);
521 if (getpeername(s
, (struct sockaddr
*)&ss
[1], &socklen
) == -1)
522 iderror(lport
, fport
, s
, ID_UNKNOWN
);
523 if (ss
[0].ss_family
!= ss
[1].ss_family
)
524 iderror(lport
, fport
, s
, ID_UNKNOWN
);
526 switch (ss
[0].ss_family
) {
528 sin4
[0] = *(struct sockaddr_in
*)&ss
[0];
529 sin4
[0].sin_port
= htons(lport
);
530 sin4
[1] = *(struct sockaddr_in
*)&ss
[1];
531 sin4
[1].sin_port
= htons(fport
);
532 if (sysctlbyname("net.inet.tcp.getcred", &uc
, &size
, sin4
,
538 sin6
[0] = *(struct sockaddr_in6
*)&ss
[0];
539 sin6
[0].sin6_port
= htons(lport
);
540 sin6
[1] = *(struct sockaddr_in6
*)&ss
[1];
541 sin6
[1].sin6_port
= htons(fport
);
542 if (sysctlbyname("net.inet6.tcp6.getcred", &uc
, &size
, sin6
,
547 default: /* should not reach here */
548 getcredfail
= EAFNOSUPPORT
;
551 if (getcredfail
!= 0) {
553 iderror(lport
, fport
, s
,
554 getcredfail
== ENOENT
? ID_NOUSER
: ID_UNKNOWN
);
558 /* Look up the pw to get the username and home directory*/
560 pw
= getpwuid(uc
.cr_uid
);
562 iderror(lport
, fport
, s
, errno
== 0 ? ID_NOUSER
: ID_UNKNOWN
);
565 snprintf(idbuf
, sizeof(idbuf
), "%u", (unsigned)pw
->pw_uid
);
567 strlcpy(idbuf
, pw
->pw_name
, sizeof(idbuf
));
570 * If enabled, we check for a file named ".noident" in the user's
571 * home directory. If found, we return HIDDEN-USER.
574 if (asprintf(&p
, "%s/.noident", pw
->pw_dir
) == -1)
575 iderror(lport
, fport
, s
, ID_UNKNOWN
);
576 if (lstat(p
, &sb
) == 0) {
578 iderror(lport
, fport
, s
, ID_HIDDEN
);
584 * Here, if enabled, we read a user's ".fakeid" file in their
585 * home directory. It consists of a line containing the name
592 * Here we set ourself to effectively be the user, so we don't
593 * open any files we have no permission to open, especially
594 * symbolic links to sensitive root-owned files or devices.
596 if (initgroups(pw
->pw_name
, pw
->pw_gid
) == -1)
597 iderror(lport
, fport
, s
, ID_UNKNOWN
);
598 if (seteuid(pw
->pw_uid
) == -1)
599 iderror(lport
, fport
, s
, ID_UNKNOWN
);
601 * We can't stat() here since that would be a race
603 * Therefore, we open the file we have permissions to open
604 * and if it's not a regular file, we close it and end up
605 * returning the user's real username.
607 if (asprintf(&p
, "%s/.fakeid", pw
->pw_dir
) == -1)
608 iderror(lport
, fport
, s
, ID_UNKNOWN
);
609 fakeid_fd
= open(p
, O_RDONLY
| O_NONBLOCK
);
611 if (fakeid_fd
== -1 || fstat(fakeid_fd
, &sb
) == -1 ||
612 !S_ISREG(sb
.st_mode
))
615 if ((ssize
= read(fakeid_fd
, buf
, sizeof(buf
) - 1)) < 0)
620 * Usually, the file will have the desired identity
621 * in the form "identity\n". Allow for leading white
622 * space and trailing white space/end of line.
625 p
+= strspn(p
, " \t");
626 p
[strcspn(p
, " \t\r\n")] = '\0';
627 if (strlen(p
) > MAXLOGNAME
- 1) /* Too long (including nul)? */
628 p
[MAXLOGNAME
- 1] = '\0';
631 * If the name is a zero-length string or matches it
632 * the id or name of another user (unless permitted by -F)
633 * then it is invalid.
639 if (p
[strspn(p
, "0123456789")] == '\0' &&
640 getpwuid(atoi(p
)) != NULL
)
643 if (getpwnam(p
) != NULL
)
648 strlcpy(idbuf
, p
, sizeof(idbuf
));
656 /* Finally, we make and send the reply. */
657 if (asprintf(&p
, "%d , %d : USERID : %s : %s\r\n", lport
, fport
, osname
,
659 syslog(LOG_ERR
, "asprintf: %m");
662 send(s
, p
, strlen(p
), MSG_EOF
);
669 * RFC738 Time Server.
670 * Return a machine readable date and time, in the form of the
671 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
672 * returns the number of seconds since midnight, Jan 1, 1970,
673 * we must add 2208988800 seconds to this figure to make up for
674 * some seventy years Bell Labs was asleep.
682 if (gettimeofday(&tv
, NULL
) < 0) {
684 warnx("unable to get time of day");
687 #define OFFSET ((u_long)25567 * 24*60*60)
688 return (htonl((long)(tv
.tv_sec
+ OFFSET
)));
694 machtime_dg(int s
, struct servtab
*sep
)
696 unsigned long result
;
697 struct sockaddr_storage ss
;
701 if (recvfrom(s
, (char *)&result
, sizeof(result
), 0,
702 (struct sockaddr
*)&ss
, &size
) < 0)
705 if (check_loop((struct sockaddr
*)&ss
, sep
))
709 sendto(s
, (char *) &result
, sizeof(result
), 0,
710 (struct sockaddr
*)&ss
, size
);
715 machtime_stream(int s
, struct servtab
*sep __unused
)
717 unsigned long result
;
720 send(s
, (char *) &result
, sizeof(result
), MSG_EOF
);
724 * RFC1078 TCP Port Service Multiplexer (TCPMUX). Service connections to
725 * services based on the service name sent.
727 * Based on TCPMUX.C by Mark K. Lottor November 1988
728 * sri-nic::ps:<mkl>tcpmux.c
731 #define MAX_SERV_LEN (256+2) /* 2 bytes for \r\n */
732 #define strwrite(fd, buf) write(fd, buf, sizeof(buf)-1)
734 static int /* # of characters upto \r,\n or \0 */
735 getline(int fd
, char *buf
, int len
)
741 sigemptyset(&sa
.sa_mask
);
742 sa
.sa_handler
= SIG_DFL
;
743 sigaction(SIGALRM
, &sa
, NULL
);
746 n
= read(fd
, buf
, len
-count
);
753 if (*buf
== '\r' || *buf
== '\n' || *buf
== '\0')
758 } while (count
< len
);
766 char service
[MAX_SERV_LEN
+1];
769 /* Get requested service name */
770 if ((len
= getline(s
, service
, MAX_SERV_LEN
)) < 0) {
771 strwrite(s
, "-Error reading service name\r\n");
777 warnx("tcpmux: someone wants %s", service
);
780 * Help is a required command, and lists available services,
783 if (!strcasecmp(service
, "help")) {
784 for (sep
= servtab
; sep
; sep
= sep
->se_next
) {
787 write(s
,sep
->se_service
,strlen(sep
->se_service
));
793 /* Try matching a service in inetd.conf with the request */
794 for (sep
= servtab
; sep
; sep
= sep
->se_next
) {
797 if (!strcasecmp(service
, sep
->se_service
)) {
798 if (ISMUXPLUS(sep
)) {
799 strwrite(s
, "+Go\r\n");
804 strwrite(s
, "-Service not available\r\n");