builtins.c revision 49089
149004Sgreen/*-
249004Sgreen * Copyright (c) 1983, 1991, 1993, 1994
349004Sgreen *	The Regents of the University of California.  All rights reserved.
449004Sgreen *
549004Sgreen * Redistribution and use in source and binary forms, with or without
649004Sgreen * modification, are permitted provided that the following conditions
749004Sgreen * are met:
849004Sgreen * 1. Redistributions of source code must retain the above copyright
949004Sgreen *    notice, this list of conditions and the following disclaimer.
1049004Sgreen * 2. Redistributions in binary form must reproduce the above copyright
1149004Sgreen *    notice, this list of conditions and the following disclaimer in the
1249004Sgreen *    documentation and/or other materials provided with the distribution.
1349004Sgreen *
1449004Sgreen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1549004Sgreen * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1649004Sgreen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1749004Sgreen * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1849004Sgreen * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1949004Sgreen * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2049004Sgreen * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2149004Sgreen * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2249004Sgreen * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2349004Sgreen * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2449004Sgreen * SUCH DAMAGE.
2549004Sgreen *
2649089Sgreen * $Id: builtins.c,v 1.11 1999/07/24 17:06:05 green Exp $
2749004Sgreen *
2849004Sgreen */
2949004Sgreen
3049004Sgreen#include <sys/filio.h>
3149004Sgreen#include <sys/ioccom.h>
3248981Ssheldonh#include <sys/param.h>
3348981Ssheldonh#include <sys/stat.h>
3448981Ssheldonh#include <sys/socket.h>
3548981Ssheldonh#include <sys/sysctl.h>
3648981Ssheldonh#include <sys/ucred.h>
3748981Ssheldonh#include <sys/uio.h>
3849004Sgreen#include <sys/utsname.h>
3948981Ssheldonh
4048981Ssheldonh#include <ctype.h>
4148981Ssheldonh#include <err.h>
4248981Ssheldonh#include <errno.h>
4348981Ssheldonh#include <limits.h>
4448981Ssheldonh#include <pwd.h>
4548981Ssheldonh#include <signal.h>
4649004Sgreen#include <stdlib.h>
4748981Ssheldonh#include <string.h>
4849030Ssheldonh#include <sysexits.h>
4949030Ssheldonh#include <syslog.h>
5048981Ssheldonh#include <unistd.h>
5148981Ssheldonh
5248981Ssheldonh#include "inetd.h"
5348981Ssheldonh
5448981Ssheldonhextern int	 debug;
5548981Ssheldonhextern struct servtab *servtab;
5648981Ssheldonh
5748981Ssheldonhchar ring[128];
5848981Ssheldonhchar *endring;
5948981Ssheldonh
6048981Ssheldonhint check_loop __P((struct sockaddr_in *, struct servtab *sep));
6148981Ssheldonhvoid inetd_setproctitle __P((char *, int));
6248981Ssheldonh
6348981Ssheldonhstruct biltin biltins[] = {
6448981Ssheldonh	/* Echo received data */
6548981Ssheldonh	{ "echo",	SOCK_STREAM,	1, -1,	echo_stream },
6648981Ssheldonh	{ "echo",	SOCK_DGRAM,	0, 1,	echo_dg },
6748981Ssheldonh
6848981Ssheldonh	/* Internet /dev/null */
6948981Ssheldonh	{ "discard",	SOCK_STREAM,	1, -1,	discard_stream },
7048981Ssheldonh	{ "discard",	SOCK_DGRAM,	0, 1,	discard_dg },
7148981Ssheldonh
7248981Ssheldonh	/* Return 32 bit time since 1970 */
7348981Ssheldonh	{ "time",	SOCK_STREAM,	0, -1,	machtime_stream },
7448981Ssheldonh	{ "time",	SOCK_DGRAM,	0, 1,	machtime_dg },
7548981Ssheldonh
7648981Ssheldonh	/* Return human-readable time */
7748981Ssheldonh	{ "daytime",	SOCK_STREAM,	0, -1,	daytime_stream },
7848981Ssheldonh	{ "daytime",	SOCK_DGRAM,	0, 1,	daytime_dg },
7948981Ssheldonh
8048981Ssheldonh	/* Familiar character generator */
8148981Ssheldonh	{ "chargen",	SOCK_STREAM,	1, -1,	chargen_stream },
8248981Ssheldonh	{ "chargen",	SOCK_DGRAM,	0, 1,	chargen_dg },
8348981Ssheldonh
8448981Ssheldonh	{ "tcpmux",	SOCK_STREAM,	1, -1,	(void (*)())tcpmux },
8548981Ssheldonh
8648981Ssheldonh	{ "auth",	SOCK_STREAM,	1, -1,	ident_stream },
8748981Ssheldonh
8848981Ssheldonh	{ NULL }
8948981Ssheldonh};
9048981Ssheldonh
9149052Ssheldonh/*
9249052Ssheldonh * RFC864 Character Generator Protocol. Generates character data without
9349052Ssheldonh * any regard for input.
9449052Ssheldonh */
9549052Ssheldonh
9648981Ssheldonhvoid
9748981Ssheldonhinitring()
9848981Ssheldonh{
9948981Ssheldonh	int i;
10048981Ssheldonh
10148981Ssheldonh	endring = ring;
10248981Ssheldonh
10348981Ssheldonh	for (i = 0; i <= 128; ++i)
10448981Ssheldonh		if (isprint(i))
10548981Ssheldonh			*endring++ = i;
10648981Ssheldonh}
10748981Ssheldonh
10848981Ssheldonh/* ARGSUSED */
10948981Ssheldonhvoid
11048981Ssheldonhchargen_dg(s, sep)		/* Character generator */
11148981Ssheldonh	int s;
11248981Ssheldonh	struct servtab *sep;
11348981Ssheldonh{
11448981Ssheldonh	struct sockaddr_in sin;
11548981Ssheldonh	static char *rs;
11648981Ssheldonh	int len, size;
11748981Ssheldonh	char text[LINESIZ+2];
11848981Ssheldonh
11948981Ssheldonh	if (endring == 0) {
12048981Ssheldonh		initring();
12148981Ssheldonh		rs = ring;
12248981Ssheldonh	}
12348981Ssheldonh
12448981Ssheldonh	size = sizeof(sin);
12548981Ssheldonh	if (recvfrom(s, text, sizeof(text), 0,
12648981Ssheldonh		     (struct sockaddr *)&sin, &size) < 0)
12748981Ssheldonh		return;
12848981Ssheldonh
12948981Ssheldonh	if (check_loop(&sin, sep))
13048981Ssheldonh		return;
13148981Ssheldonh
13248981Ssheldonh	if ((len = endring - rs) >= LINESIZ)
13348981Ssheldonh		memmove(text, rs, LINESIZ);
13448981Ssheldonh	else {
13548981Ssheldonh		memmove(text, rs, len);
13648981Ssheldonh		memmove(text + len, ring, LINESIZ - len);
13748981Ssheldonh	}
13848981Ssheldonh	if (++rs == endring)
13948981Ssheldonh		rs = ring;
14048981Ssheldonh	text[LINESIZ] = '\r';
14148981Ssheldonh	text[LINESIZ + 1] = '\n';
14248981Ssheldonh	(void) sendto(s, text, sizeof(text), 0,
14348981Ssheldonh		      (struct sockaddr *)&sin, sizeof(sin));
14448981Ssheldonh}
14548981Ssheldonh
14648981Ssheldonh/* ARGSUSED */
14748981Ssheldonhvoid
14848981Ssheldonhchargen_stream(s, sep)		/* Character generator */
14948981Ssheldonh	int s;
15048981Ssheldonh	struct servtab *sep;
15148981Ssheldonh{
15248981Ssheldonh	int len;
15348981Ssheldonh	char *rs, text[LINESIZ+2];
15448981Ssheldonh
15548981Ssheldonh	inetd_setproctitle(sep->se_service, s);
15648981Ssheldonh
15748981Ssheldonh	if (!endring) {
15848981Ssheldonh		initring();
15948981Ssheldonh		rs = ring;
16048981Ssheldonh	}
16148981Ssheldonh
16248981Ssheldonh	text[LINESIZ] = '\r';
16348981Ssheldonh	text[LINESIZ + 1] = '\n';
16448981Ssheldonh	for (rs = ring;;) {
16548981Ssheldonh		if ((len = endring - rs) >= LINESIZ)
16648981Ssheldonh			memmove(text, rs, LINESIZ);
16748981Ssheldonh		else {
16848981Ssheldonh			memmove(text, rs, len);
16948981Ssheldonh			memmove(text + len, ring, LINESIZ - len);
17048981Ssheldonh		}
17148981Ssheldonh		if (++rs == endring)
17248981Ssheldonh			rs = ring;
17348981Ssheldonh		if (write(s, text, sizeof(text)) != sizeof(text))
17448981Ssheldonh			break;
17548981Ssheldonh	}
17648981Ssheldonh	exit(0);
17748981Ssheldonh}
17848981Ssheldonh
17949052Ssheldonh/*
18049052Ssheldonh * RFC867 Daytime Protocol. Sends the current date and time as an ascii
18149052Ssheldonh * character string without any regard for input.
18249052Ssheldonh */
18349052Ssheldonh
18448981Ssheldonh/* ARGSUSED */
18548981Ssheldonhvoid
18648981Ssheldonhdaytime_dg(s, sep)		/* Return human-readable time of day */
18748981Ssheldonh	int s;
18848981Ssheldonh	struct servtab *sep;
18948981Ssheldonh{
19048981Ssheldonh	char buffer[256];
19148981Ssheldonh	time_t clock;
19248981Ssheldonh	struct sockaddr_in sin;
19348981Ssheldonh	int size;
19448981Ssheldonh
19548981Ssheldonh	clock = time((time_t *) 0);
19648981Ssheldonh
19748981Ssheldonh	size = sizeof(sin);
19848981Ssheldonh	if (recvfrom(s, buffer, sizeof(buffer), 0,
19948981Ssheldonh		     (struct sockaddr *)&sin, &size) < 0)
20048981Ssheldonh		return;
20148981Ssheldonh
20248981Ssheldonh	if (check_loop(&sin, sep))
20348981Ssheldonh		return;
20448981Ssheldonh
20548981Ssheldonh	(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
20648981Ssheldonh	(void) sendto(s, buffer, strlen(buffer), 0,
20748981Ssheldonh		      (struct sockaddr *)&sin, sizeof(sin));
20848981Ssheldonh}
20948981Ssheldonh
21048981Ssheldonh/* ARGSUSED */
21148981Ssheldonhvoid
21248981Ssheldonhdaytime_stream(s, sep)		/* Return human-readable time of day */
21348981Ssheldonh	int s;
21448981Ssheldonh	struct servtab *sep;
21548981Ssheldonh{
21648981Ssheldonh	char buffer[256];
21748981Ssheldonh	time_t clock;
21848981Ssheldonh
21948981Ssheldonh	clock = time((time_t *) 0);
22048981Ssheldonh
22148981Ssheldonh	(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
22248981Ssheldonh	(void) write(s, buffer, strlen(buffer));
22348981Ssheldonh}
22448981Ssheldonh
22549052Ssheldonh/*
22649052Ssheldonh * RFC863 Discard Protocol. Any data received is thrown away and no response
22749052Ssheldonh * is sent.
22849052Ssheldonh */
22949052Ssheldonh
23048981Ssheldonh/* ARGSUSED */
23148981Ssheldonhvoid
23248981Ssheldonhdiscard_dg(s, sep)		/* Discard service -- ignore data */
23348981Ssheldonh	int s;
23448981Ssheldonh	struct servtab *sep;
23548981Ssheldonh{
23648981Ssheldonh	char buffer[BUFSIZE];
23748981Ssheldonh
23848981Ssheldonh	(void) read(s, buffer, sizeof(buffer));
23948981Ssheldonh}
24048981Ssheldonh
24148981Ssheldonh/* ARGSUSED */
24248981Ssheldonhvoid
24348981Ssheldonhdiscard_stream(s, sep)		/* Discard service -- ignore data */
24448981Ssheldonh	int s;
24548981Ssheldonh	struct servtab *sep;
24648981Ssheldonh{
24748981Ssheldonh	int ret;
24848981Ssheldonh	char buffer[BUFSIZE];
24948981Ssheldonh
25048981Ssheldonh	inetd_setproctitle(sep->se_service, s);
25148981Ssheldonh	while (1) {
25248981Ssheldonh		while ((ret = read(s, buffer, sizeof(buffer))) > 0)
25348981Ssheldonh			;
25448981Ssheldonh		if (ret == 0 || errno != EINTR)
25548981Ssheldonh			break;
25648981Ssheldonh	}
25748981Ssheldonh	exit(0);
25848981Ssheldonh}
25948981Ssheldonh
26049052Ssheldonh/*
26149052Ssheldonh * RFC862 Echo Protocol. Any data received is sent back to the sender as
26249052Ssheldonh * received.
26349052Ssheldonh */
26449052Ssheldonh
26548981Ssheldonh/* ARGSUSED */
26648981Ssheldonhvoid
26748981Ssheldonhecho_dg(s, sep)			/* Echo service -- echo data back */
26848981Ssheldonh	int s;
26948981Ssheldonh	struct servtab *sep;
27048981Ssheldonh{
27148981Ssheldonh	char buffer[BUFSIZE];
27248981Ssheldonh	int i, size;
27348981Ssheldonh	struct sockaddr_in sin;
27448981Ssheldonh
27548981Ssheldonh	size = sizeof(sin);
27648981Ssheldonh	if ((i = recvfrom(s, buffer, sizeof(buffer), 0,
27748981Ssheldonh			  (struct sockaddr *)&sin, &size)) < 0)
27848981Ssheldonh		return;
27948981Ssheldonh
28048981Ssheldonh	if (check_loop(&sin, sep))
28148981Ssheldonh		return;
28248981Ssheldonh
28348981Ssheldonh	(void) sendto(s, buffer, i, 0, (struct sockaddr *)&sin,
28448981Ssheldonh		      sizeof(sin));
28548981Ssheldonh}
28648981Ssheldonh
28748981Ssheldonh/* ARGSUSED */
28848981Ssheldonhvoid
28948981Ssheldonhecho_stream(s, sep)		/* Echo service -- echo data back */
29048981Ssheldonh	int s;
29148981Ssheldonh	struct servtab *sep;
29248981Ssheldonh{
29348981Ssheldonh	char buffer[BUFSIZE];
29448981Ssheldonh	int i;
29548981Ssheldonh
29648981Ssheldonh	inetd_setproctitle(sep->se_service, s);
29748981Ssheldonh	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
29848981Ssheldonh	    write(s, buffer, i) > 0)
29948981Ssheldonh		;
30048981Ssheldonh	exit(0);
30148981Ssheldonh}
30248981Ssheldonh
30349052Ssheldonh/*
30449052Ssheldonh * RFC1413 Identification Protocol. Given a TCP port number pair, return a
30549052Ssheldonh * character string which identifies the owner of that connection on the
30649057Sgreen * server's system. Extended to allow for ~/.fakeid support and ~/.noident
30749057Sgreen * support.
30849052Ssheldonh */
30949052Ssheldonh
31049057Sgreen/*
31149057Sgreen * NOTE: If any of the asprintf()s here fail, rest assured that faulting
31249057Sgreen * in the buffers for using snprintf() would have also failed.
31349057Sgreen * Asprintf() is the proper way to do what we do.
31449057Sgreen */
31549057Sgreen
31648981Ssheldonh/* ARGSUSED */
31748981Ssheldonhvoid
31849004Sgreeniderror(lport, fport, s, er)
31949004Sgreen	int lport, fport, s, er;
32048981Ssheldonh{
32149004Sgreen	char *p;
32249004Sgreen
32349030Ssheldonh	asprintf(&p, "%d , %d : ERROR : %s\r\n", lport, fport,
32448981Ssheldonh	    er == -1 ? "HIDDEN-USER" : er ? strerror(er) : "UNKNOWN-ERROR");
32549030Ssheldonh	if (p == NULL) {
32649057Sgreen		syslog(LOG_ERR, "asprintf: %m");
32749030Ssheldonh		exit(EX_OSERR);
32849030Ssheldonh	}
32949004Sgreen	write(s, p, strlen(p));
33049004Sgreen	free(p);
33148981Ssheldonh
33248981Ssheldonh	exit(0);
33348981Ssheldonh}
33448981Ssheldonh
33548981Ssheldonh/* ARGSUSED */
33648981Ssheldonhvoid
33748981Ssheldonhident_stream(s, sep)		/* Ident service */
33848981Ssheldonh	int s;
33948981Ssheldonh	struct servtab *sep;
34048981Ssheldonh{
34149089Sgreen	struct utsname un;
34249089Sgreen	struct stat sb;
34348981Ssheldonh	struct sockaddr_in sin[2];
34448981Ssheldonh	struct ucred uc;
34549004Sgreen	struct timeval tv = {
34649004Sgreen		10,
34749004Sgreen		0
34849004Sgreen	};
34949054Sgreen	struct passwd *pw;
35049004Sgreen	fd_set fdset;
35149004Sgreen	char buf[BUFSIZE], *cp = NULL, *p, **av, *osname = NULL;
35249057Sgreen	int len, c, fflag = 0, nflag = 0, rflag = 0, argc = 0;
35348981Ssheldonh	u_short lport, fport;
35448981Ssheldonh
35548981Ssheldonh	inetd_setproctitle(sep->se_service, s);
35648981Ssheldonh	optind = 1;
35748981Ssheldonh	optreset = 1;
35848981Ssheldonh	for (av = sep->se_argv; *av; av++)
35948981Ssheldonh		argc++;
36048981Ssheldonh	if (argc) {
36149054Sgreen		int sec, usec;
36249054Sgreen
36349057Sgreen		while ((c = getopt(argc, sep->se_argv, "fno:rt:")) != -1)
36448981Ssheldonh			switch (c) {
36548981Ssheldonh			case 'f':
36648981Ssheldonh				fflag = 1;
36748981Ssheldonh				break;
36849057Sgreen			case 'n':
36949057Sgreen				nflag = 1;
37048981Ssheldonh				break;
37149004Sgreen			case 'o':
37249004Sgreen				osname = optarg;
37349004Sgreen				break;
37449057Sgreen			case 'r':
37549057Sgreen				rflag = 1;
37649057Sgreen				break;
37749051Ssheldonh			case 't':
37849030Ssheldonh				switch (sscanf(optarg, "%d.%d", &sec, &usec)) {
37949030Ssheldonh				case 2:
38049030Ssheldonh					tv.tv_usec = usec;
38149030Ssheldonh				case 1:
38249030Ssheldonh					tv.tv_sec = sec;
38349030Ssheldonh					break;
38449030Ssheldonh				default:
38549030Ssheldonh					if (debug)
38649030Ssheldonh						warnx("bad -t argument");
38749030Ssheldonh					break;
38849030Ssheldonh				}
38949054Sgreen				break;
39048981Ssheldonh			default:
39148981Ssheldonh				break;
39248981Ssheldonh			}
39348981Ssheldonh	}
39449004Sgreen	if (osname == NULL) {
39549033Sgreen		if (uname(&un) == -1)
39649004Sgreen			iderror(0, 0, s, errno);
39749004Sgreen		osname = un.sysname;
39849004Sgreen	}
39948981Ssheldonh	len = sizeof(sin[0]);
40048981Ssheldonh	if (getsockname(s, (struct sockaddr *)&sin[0], &len) == -1)
40149004Sgreen		iderror(0, 0, s, errno);
40248981Ssheldonh	len = sizeof(sin[1]);
40348981Ssheldonh	if (getpeername(s, (struct sockaddr *)&sin[1], &len) == -1)
40449004Sgreen		iderror(0, 0, s, errno);
40549004Sgreen	FD_ZERO(&fdset);
40649004Sgreen	FD_SET(s, &fdset);
40749004Sgreen	if (select(s + 1, &fdset, NULL, NULL, &tv) == -1)
40849004Sgreen		iderror(0, 0, s, errno);
40949004Sgreen	if (ioctl(s, FIONREAD, &len) == -1)
41049004Sgreen		iderror(0, 0, s, errno);
41149004Sgreen	if (len >= sizeof(buf))
41249004Sgreen		len = sizeof(buf) - 1;
41349004Sgreen	len = read(s, buf, len);
41449004Sgreen	if (len == -1)
41549004Sgreen		iderror(0, 0, s, errno);
41649004Sgreen	buf[len] = '\0';
41749015Sgreen	if (sscanf(buf, "%hu , %hu", &lport, &fport) != 2)
41849004Sgreen		iderror(0, 0, s, 0);
41948981Ssheldonh	if (!rflag)
42049004Sgreen		iderror(lport, fport, s, -1);
42148981Ssheldonh	sin[0].sin_port = htons(lport);
42248981Ssheldonh	sin[1].sin_port = htons(fport);
42348981Ssheldonh	len = sizeof(uc);
42448981Ssheldonh	if (sysctlbyname("net.inet.tcp.getcred", &uc, &len, sin,
42548981Ssheldonh	    sizeof(sin)) == -1)
42649004Sgreen		iderror(lport, fport, s, errno);
42748981Ssheldonh	pw = getpwuid(uc.cr_uid);
42848981Ssheldonh	if (pw == NULL)
42949004Sgreen		iderror(lport, fport, s, errno);
43049057Sgreen	if (nflag) {
43149089Sgreen		if (asprintf(&p, "%s/.noident", pw->pw_dir) == -1)
43249057Sgreen			iderror(lport, fport, s, errno);
43349089Sgreen		if (lstat(p, &sb) == 0) {
43449089Sgreen			free(p);
43549057Sgreen			iderror(lport, fport, s, -1);
43649057Sgreen		}
43749089Sgreen		free(p);
43849057Sgreen	}
43948981Ssheldonh	if (fflag) {
44049033Sgreen		FILE *fakeid = NULL;
44149033Sgreen
44249089Sgreen		if (asprintf(&p, "%s/.fakeid", pw->pw_dir) == -1)
44349057Sgreen			iderror(lport, fport, s, errno);
44448981Ssheldonh		seteuid(pw->pw_uid);
44548981Ssheldonh		setegid(pw->pw_gid);
44649089Sgreen		fakeid = fopen(p, "r");
44749089Sgreen		free(p);
44849089Sgreen		if (fakeid != NULL &&
44948981Ssheldonh		    fstat(fileno(fakeid), &sb) != -1 && S_ISREG(sb.st_mode)) {
45048981Ssheldonh			buf[sizeof(buf) - 1] = '\0';
45148981Ssheldonh			if (fgets(buf, sizeof(buf), fakeid) == NULL) {
45248981Ssheldonh				cp = pw->pw_name;
45348981Ssheldonh				fclose(fakeid);
45448981Ssheldonh				goto printit;
45548981Ssheldonh			}
45648981Ssheldonh			fclose(fakeid);
45748981Ssheldonh			strtok(buf, "\r\n");
45848981Ssheldonh			if (strlen(buf) > 16)
45948981Ssheldonh				buf[16] = '\0';
46048981Ssheldonh			cp = buf;
46148981Ssheldonh			while (isspace(*cp))
46248981Ssheldonh				cp++;
46348981Ssheldonh			strtok(cp, " \t");
46448981Ssheldonh			if (!*cp || getpwnam(cp))
46548981Ssheldonh				cp = getpwuid(uc.cr_uid)->pw_name;
46648981Ssheldonh		} else
46748981Ssheldonh			cp = pw->pw_name;
46848981Ssheldonh	} else
46948981Ssheldonh		cp = pw->pw_name;
47048981Ssheldonhprintit:
47149004Sgreen	if (asprintf(&p, "%d , %d : USERID : %s : %s\r\n", lport, fport, osname,
47249051Ssheldonh	    cp) == -1) {
47349057Sgreen		syslog(LOG_ERR, "asprintf: %m");
47449051Ssheldonh		exit(EX_OSERR);
47549051Ssheldonh	}
47649004Sgreen	write(s, p, strlen(p));
47749004Sgreen	free(p);
47848981Ssheldonh
47948981Ssheldonh	exit(0);
48048981Ssheldonh}
48148981Ssheldonh
48248981Ssheldonh/*
48349052Ssheldonh * RFC738 Time Server.
48448981Ssheldonh * Return a machine readable date and time, in the form of the
48548981Ssheldonh * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
48648981Ssheldonh * returns the number of seconds since midnight, Jan 1, 1970,
48748981Ssheldonh * we must add 2208988800 seconds to this figure to make up for
48848981Ssheldonh * some seventy years Bell Labs was asleep.
48948981Ssheldonh */
49048981Ssheldonh
49148981Ssheldonhunsigned long
49248981Ssheldonhmachtime()
49348981Ssheldonh{
49448981Ssheldonh	struct timeval tv;
49548981Ssheldonh
49648981Ssheldonh	if (gettimeofday(&tv, (struct timezone *)NULL) < 0) {
49748981Ssheldonh		if (debug)
49848981Ssheldonh			warnx("unable to get time of day");
49948981Ssheldonh		return (0L);
50048981Ssheldonh	}
50148981Ssheldonh#define	OFFSET ((u_long)25567 * 24*60*60)
50248981Ssheldonh	return (htonl((long)(tv.tv_sec + OFFSET)));
50348981Ssheldonh#undef OFFSET
50448981Ssheldonh}
50548981Ssheldonh
50648981Ssheldonh/* ARGSUSED */
50748981Ssheldonhvoid
50848981Ssheldonhmachtime_dg(s, sep)
50948981Ssheldonh	int s;
51048981Ssheldonh	struct servtab *sep;
51148981Ssheldonh{
51248981Ssheldonh	unsigned long result;
51348981Ssheldonh	struct sockaddr_in sin;
51448981Ssheldonh	int size;
51548981Ssheldonh
51648981Ssheldonh	size = sizeof(sin);
51748981Ssheldonh	if (recvfrom(s, (char *)&result, sizeof(result), 0,
51848981Ssheldonh		     (struct sockaddr *)&sin, &size) < 0)
51948981Ssheldonh		return;
52048981Ssheldonh
52148981Ssheldonh	if (check_loop(&sin, sep))
52248981Ssheldonh		return;
52348981Ssheldonh
52448981Ssheldonh	result = machtime();
52548981Ssheldonh	(void) sendto(s, (char *) &result, sizeof(result), 0,
52648981Ssheldonh		      (struct sockaddr *)&sin, sizeof(sin));
52748981Ssheldonh}
52848981Ssheldonh
52948981Ssheldonh/* ARGSUSED */
53048981Ssheldonhvoid
53148981Ssheldonhmachtime_stream(s, sep)
53248981Ssheldonh	int s;
53348981Ssheldonh	struct servtab *sep;
53448981Ssheldonh{
53548981Ssheldonh	unsigned long result;
53648981Ssheldonh
53748981Ssheldonh	result = machtime();
53848981Ssheldonh	(void) write(s, (char *) &result, sizeof(result));
53948981Ssheldonh}
54048981Ssheldonh
54148981Ssheldonh/*
54249052Ssheldonh * RFC1078 TCP Port Service Multiplexer (TCPMUX). Service connections to
54349052Ssheldonh * services based on the service name sent.
54449052Ssheldonh *
54548981Ssheldonh *  Based on TCPMUX.C by Mark K. Lottor November 1988
54648981Ssheldonh *  sri-nic::ps:<mkl>tcpmux.c
54748981Ssheldonh */
54848981Ssheldonh
54948981Ssheldonh#define MAX_SERV_LEN	(256+2)		/* 2 bytes for \r\n */
55048981Ssheldonh#define strwrite(fd, buf)	(void) write(fd, buf, sizeof(buf)-1)
55148981Ssheldonh
55248981Ssheldonhstatic int		/* # of characters upto \r,\n or \0 */
55348981Ssheldonhgetline(fd, buf, len)
55448981Ssheldonh	int fd;
55548981Ssheldonh	char *buf;
55648981Ssheldonh	int len;
55748981Ssheldonh{
55848981Ssheldonh	int count = 0, n;
55948981Ssheldonh	struct sigaction sa;
56048981Ssheldonh
56148981Ssheldonh	sa.sa_flags = 0;
56248981Ssheldonh	sigemptyset(&sa.sa_mask);
56348981Ssheldonh	sa.sa_handler = SIG_DFL;
56448981Ssheldonh	sigaction(SIGALRM, &sa, (struct sigaction *)0);
56548981Ssheldonh	do {
56648981Ssheldonh		alarm(10);
56748981Ssheldonh		n = read(fd, buf, len-count);
56848981Ssheldonh		alarm(0);
56948981Ssheldonh		if (n == 0)
57048981Ssheldonh			return (count);
57148981Ssheldonh		if (n < 0)
57248981Ssheldonh			return (-1);
57348981Ssheldonh		while (--n >= 0) {
57448981Ssheldonh			if (*buf == '\r' || *buf == '\n' || *buf == '\0')
57548981Ssheldonh				return (count);
57648981Ssheldonh			count++;
57748981Ssheldonh			buf++;
57848981Ssheldonh		}
57948981Ssheldonh	} while (count < len);
58048981Ssheldonh	return (count);
58148981Ssheldonh}
58248981Ssheldonh
58348981Ssheldonhstruct servtab *
58448981Ssheldonhtcpmux(s)
58548981Ssheldonh	int s;
58648981Ssheldonh{
58748981Ssheldonh	struct servtab *sep;
58848981Ssheldonh	char service[MAX_SERV_LEN+1];
58948981Ssheldonh	int len;
59048981Ssheldonh
59148981Ssheldonh	/* Get requested service name */
59248981Ssheldonh	if ((len = getline(s, service, MAX_SERV_LEN)) < 0) {
59348981Ssheldonh		strwrite(s, "-Error reading service name\r\n");
59448981Ssheldonh		return (NULL);
59548981Ssheldonh	}
59648981Ssheldonh	service[len] = '\0';
59748981Ssheldonh
59848981Ssheldonh	if (debug)
59948981Ssheldonh		warnx("tcpmux: someone wants %s", service);
60048981Ssheldonh
60148981Ssheldonh	/*
60248981Ssheldonh	 * Help is a required command, and lists available services,
60348981Ssheldonh	 * one per line.
60448981Ssheldonh	 */
60548981Ssheldonh	if (!strcasecmp(service, "help")) {
60648981Ssheldonh		for (sep = servtab; sep; sep = sep->se_next) {
60748981Ssheldonh			if (!ISMUX(sep))
60848981Ssheldonh				continue;
60948981Ssheldonh			(void)write(s,sep->se_service,strlen(sep->se_service));
61048981Ssheldonh			strwrite(s, "\r\n");
61148981Ssheldonh		}
61248981Ssheldonh		return (NULL);
61348981Ssheldonh	}
61448981Ssheldonh
61548981Ssheldonh	/* Try matching a service in inetd.conf with the request */
61648981Ssheldonh	for (sep = servtab; sep; sep = sep->se_next) {
61748981Ssheldonh		if (!ISMUX(sep))
61848981Ssheldonh			continue;
61948981Ssheldonh		if (!strcasecmp(service, sep->se_service)) {
62048981Ssheldonh			if (ISMUXPLUS(sep)) {
62148981Ssheldonh				strwrite(s, "+Go\r\n");
62248981Ssheldonh			}
62348981Ssheldonh			return (sep);
62448981Ssheldonh		}
62548981Ssheldonh	}
62648981Ssheldonh	strwrite(s, "-Service not available\r\n");
62748981Ssheldonh	return (NULL);
62848981Ssheldonh}
629