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 */ 2649004Sgreen 2798563Sjmallett#include <sys/cdefs.h> 2898563Sjmallett__FBSDID("$FreeBSD: releng/11.0/usr.sbin/inetd/builtins.c 299356 2016-05-10 11:12:31Z bapt $"); 2998563Sjmallett 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> 4369144Sgreen#include <fcntl.h> 4448981Ssheldonh#include <limits.h> 4548981Ssheldonh#include <pwd.h> 4648981Ssheldonh#include <signal.h> 4749004Sgreen#include <stdlib.h> 4848981Ssheldonh#include <string.h> 4949030Ssheldonh#include <sysexits.h> 5049030Ssheldonh#include <syslog.h> 5148981Ssheldonh#include <unistd.h> 5248981Ssheldonh 5348981Ssheldonh#include "inetd.h" 5448981Ssheldonh 5598562Sjmallettvoid chargen_dg(int, struct servtab *); 5698562Sjmallettvoid chargen_stream(int, struct servtab *); 5798562Sjmallettvoid daytime_dg(int, struct servtab *); 5898562Sjmallettvoid daytime_stream(int, struct servtab *); 5998562Sjmallettvoid discard_dg(int, struct servtab *); 6098562Sjmallettvoid discard_stream(int, struct servtab *); 6198562Sjmallettvoid echo_dg(int, struct servtab *); 6298562Sjmallettvoid echo_stream(int, struct servtab *); 63299356Sbaptstatic int get_line(int, char *, int); 6498562Sjmallettvoid iderror(int, int, int, const char *); 6598562Sjmallettvoid ident_stream(int, struct servtab *); 6698562Sjmallettvoid initring(void); 67157816Sdwmaloneuint32_t machtime(void); 6898562Sjmallettvoid machtime_dg(int, struct servtab *); 6998562Sjmallettvoid machtime_stream(int, struct servtab *); 7048981Ssheldonh 7148981Ssheldonhchar ring[128]; 7248981Ssheldonhchar *endring; 7348981Ssheldonh 7448981Ssheldonh 7548981Ssheldonhstruct biltin biltins[] = { 7648981Ssheldonh /* Echo received data */ 7748981Ssheldonh { "echo", SOCK_STREAM, 1, -1, echo_stream }, 7848981Ssheldonh { "echo", SOCK_DGRAM, 0, 1, echo_dg }, 7948981Ssheldonh 8048981Ssheldonh /* Internet /dev/null */ 8148981Ssheldonh { "discard", SOCK_STREAM, 1, -1, discard_stream }, 8248981Ssheldonh { "discard", SOCK_DGRAM, 0, 1, discard_dg }, 8348981Ssheldonh 8477685Sdwmalone /* Return 32 bit time since 1900 */ 8548981Ssheldonh { "time", SOCK_STREAM, 0, -1, machtime_stream }, 8648981Ssheldonh { "time", SOCK_DGRAM, 0, 1, machtime_dg }, 8748981Ssheldonh 8848981Ssheldonh /* Return human-readable time */ 8948981Ssheldonh { "daytime", SOCK_STREAM, 0, -1, daytime_stream }, 9048981Ssheldonh { "daytime", SOCK_DGRAM, 0, 1, daytime_dg }, 9148981Ssheldonh 9248981Ssheldonh /* Familiar character generator */ 9348981Ssheldonh { "chargen", SOCK_STREAM, 1, -1, chargen_stream }, 9448981Ssheldonh { "chargen", SOCK_DGRAM, 0, 1, chargen_dg }, 9548981Ssheldonh 9678694Sdwmalone { "tcpmux", SOCK_STREAM, 1, -1, (bi_fn_t *)tcpmux }, 9748981Ssheldonh 9848981Ssheldonh { "auth", SOCK_STREAM, 1, -1, ident_stream }, 9948981Ssheldonh 10078694Sdwmalone { NULL, 0, 0, 0, NULL } 10148981Ssheldonh}; 10248981Ssheldonh 10349052Ssheldonh/* 10449052Ssheldonh * RFC864 Character Generator Protocol. Generates character data without 10549052Ssheldonh * any regard for input. 10649052Ssheldonh */ 10749052Ssheldonh 10848981Ssheldonhvoid 10998558Sjmallettinitring(void) 11048981Ssheldonh{ 11148981Ssheldonh int i; 11248981Ssheldonh 11348981Ssheldonh endring = ring; 11448981Ssheldonh 11548981Ssheldonh for (i = 0; i <= 128; ++i) 11648981Ssheldonh if (isprint(i)) 11748981Ssheldonh *endring++ = i; 11848981Ssheldonh} 11948981Ssheldonh 120157820Sdwmalone/* Character generator 121157820Sdwmalone * The RFC says that we should send back a random number of 122157820Sdwmalone * characters chosen from the range 0 to 512. We send LINESIZ+2. 123157820Sdwmalone */ 12448981Ssheldonh/* ARGSUSED */ 12548981Ssheldonhvoid 12698559Sjmallettchargen_dg(int s, struct servtab *sep) 12748981Ssheldonh{ 12856590Sshin struct sockaddr_storage ss; 12948981Ssheldonh static char *rs; 13057857Sshin int len; 13157857Sshin socklen_t size; 13248981Ssheldonh char text[LINESIZ+2]; 13348981Ssheldonh 13448981Ssheldonh if (endring == 0) { 13548981Ssheldonh initring(); 13648981Ssheldonh rs = ring; 13748981Ssheldonh } 13848981Ssheldonh 13956590Sshin size = sizeof(ss); 14048981Ssheldonh if (recvfrom(s, text, sizeof(text), 0, 14156590Sshin (struct sockaddr *)&ss, &size) < 0) 14248981Ssheldonh return; 14348981Ssheldonh 14456590Sshin if (check_loop((struct sockaddr *)&ss, sep)) 14548981Ssheldonh return; 14648981Ssheldonh 14748981Ssheldonh if ((len = endring - rs) >= LINESIZ) 14848981Ssheldonh memmove(text, rs, LINESIZ); 14948981Ssheldonh else { 15048981Ssheldonh memmove(text, rs, len); 15148981Ssheldonh memmove(text + len, ring, LINESIZ - len); 15248981Ssheldonh } 15348981Ssheldonh if (++rs == endring) 15448981Ssheldonh rs = ring; 15548981Ssheldonh text[LINESIZ] = '\r'; 15648981Ssheldonh text[LINESIZ + 1] = '\n'; 15757857Sshin (void) sendto(s, text, sizeof(text), 0, (struct sockaddr *)&ss, size); 15848981Ssheldonh} 15948981Ssheldonh 16098559Sjmallett/* Character generator */ 16148981Ssheldonh/* ARGSUSED */ 16248981Ssheldonhvoid 16398559Sjmallettchargen_stream(int s, struct servtab *sep) 16448981Ssheldonh{ 16548981Ssheldonh int len; 16648981Ssheldonh char *rs, text[LINESIZ+2]; 16748981Ssheldonh 16848981Ssheldonh inetd_setproctitle(sep->se_service, s); 16948981Ssheldonh 17048981Ssheldonh if (!endring) { 17148981Ssheldonh initring(); 17248981Ssheldonh rs = ring; 17348981Ssheldonh } 17448981Ssheldonh 17548981Ssheldonh text[LINESIZ] = '\r'; 17648981Ssheldonh text[LINESIZ + 1] = '\n'; 17748981Ssheldonh for (rs = ring;;) { 17848981Ssheldonh if ((len = endring - rs) >= LINESIZ) 17948981Ssheldonh memmove(text, rs, LINESIZ); 18048981Ssheldonh else { 18148981Ssheldonh memmove(text, rs, len); 18248981Ssheldonh memmove(text + len, ring, LINESIZ - len); 18348981Ssheldonh } 18448981Ssheldonh if (++rs == endring) 18548981Ssheldonh rs = ring; 18648981Ssheldonh if (write(s, text, sizeof(text)) != sizeof(text)) 18748981Ssheldonh break; 18848981Ssheldonh } 18948981Ssheldonh exit(0); 19048981Ssheldonh} 19148981Ssheldonh 19249052Ssheldonh/* 19349052Ssheldonh * RFC867 Daytime Protocol. Sends the current date and time as an ascii 19449052Ssheldonh * character string without any regard for input. 19549052Ssheldonh */ 19649052Ssheldonh 19798559Sjmallett/* Return human-readable time of day */ 19848981Ssheldonh/* ARGSUSED */ 19948981Ssheldonhvoid 20098559Sjmallettdaytime_dg(int s, struct servtab *sep) 20148981Ssheldonh{ 20248981Ssheldonh char buffer[256]; 20378694Sdwmalone time_t now; 20456590Sshin struct sockaddr_storage ss; 20557857Sshin socklen_t size; 20648981Ssheldonh 20778694Sdwmalone now = time((time_t *) 0); 20848981Ssheldonh 20956590Sshin size = sizeof(ss); 21048981Ssheldonh if (recvfrom(s, buffer, sizeof(buffer), 0, 21156590Sshin (struct sockaddr *)&ss, &size) < 0) 21248981Ssheldonh return; 21348981Ssheldonh 21456590Sshin if (check_loop((struct sockaddr *)&ss, sep)) 21548981Ssheldonh return; 21648981Ssheldonh 21778694Sdwmalone (void) sprintf(buffer, "%.24s\r\n", ctime(&now)); 21848981Ssheldonh (void) sendto(s, buffer, strlen(buffer), 0, 21957857Sshin (struct sockaddr *)&ss, size); 22048981Ssheldonh} 22148981Ssheldonh 22298559Sjmallett/* Return human-readable time of day */ 22348981Ssheldonh/* ARGSUSED */ 22448981Ssheldonhvoid 22598559Sjmallettdaytime_stream(int s, struct servtab *sep __unused) 22648981Ssheldonh{ 22748981Ssheldonh char buffer[256]; 22878694Sdwmalone time_t now; 22948981Ssheldonh 23078694Sdwmalone now = time((time_t *) 0); 23148981Ssheldonh 23278694Sdwmalone (void) sprintf(buffer, "%.24s\r\n", ctime(&now)); 23358735Ssheldonh (void) send(s, buffer, strlen(buffer), MSG_EOF); 23448981Ssheldonh} 23548981Ssheldonh 23649052Ssheldonh/* 23749052Ssheldonh * RFC863 Discard Protocol. Any data received is thrown away and no response 23849052Ssheldonh * is sent. 23949052Ssheldonh */ 24049052Ssheldonh 24198559Sjmallett/* Discard service -- ignore data */ 24248981Ssheldonh/* ARGSUSED */ 24348981Ssheldonhvoid 24498561Sjmallettdiscard_dg(int s, struct servtab *sep __unused) 24548981Ssheldonh{ 24648981Ssheldonh char buffer[BUFSIZE]; 24748981Ssheldonh 24848981Ssheldonh (void) read(s, buffer, sizeof(buffer)); 24948981Ssheldonh} 25048981Ssheldonh 25198559Sjmallett/* Discard service -- ignore data */ 25248981Ssheldonh/* ARGSUSED */ 25348981Ssheldonhvoid 25498559Sjmallettdiscard_stream(int s, struct servtab *sep) 25548981Ssheldonh{ 25648981Ssheldonh int ret; 25748981Ssheldonh char buffer[BUFSIZE]; 25848981Ssheldonh 25948981Ssheldonh inetd_setproctitle(sep->se_service, s); 26048981Ssheldonh while (1) { 26148981Ssheldonh while ((ret = read(s, buffer, sizeof(buffer))) > 0) 26248981Ssheldonh ; 26348981Ssheldonh if (ret == 0 || errno != EINTR) 26448981Ssheldonh break; 26548981Ssheldonh } 26648981Ssheldonh exit(0); 26748981Ssheldonh} 26848981Ssheldonh 26949052Ssheldonh/* 27049052Ssheldonh * RFC862 Echo Protocol. Any data received is sent back to the sender as 27149052Ssheldonh * received. 27249052Ssheldonh */ 27349052Ssheldonh 27498559Sjmallett/* Echo service -- echo data back */ 27548981Ssheldonh/* ARGSUSED */ 27648981Ssheldonhvoid 27798559Sjmallettecho_dg(int s, struct servtab *sep) 27848981Ssheldonh{ 27977231Sdwmalone char buffer[65536]; /* Should be sizeof(max datagram). */ 28057857Sshin int i; 28157857Sshin socklen_t size; 28256590Sshin struct sockaddr_storage ss; 28348981Ssheldonh 28456590Sshin size = sizeof(ss); 28548981Ssheldonh if ((i = recvfrom(s, buffer, sizeof(buffer), 0, 28656590Sshin (struct sockaddr *)&ss, &size)) < 0) 28748981Ssheldonh return; 28848981Ssheldonh 28956590Sshin if (check_loop((struct sockaddr *)&ss, sep)) 29048981Ssheldonh return; 29148981Ssheldonh 29257857Sshin (void) sendto(s, buffer, i, 0, (struct sockaddr *)&ss, size); 29348981Ssheldonh} 29448981Ssheldonh 29598559Sjmallett/* Echo service -- echo data back */ 29648981Ssheldonh/* ARGSUSED */ 29748981Ssheldonhvoid 29898559Sjmallettecho_stream(int s, struct servtab *sep) 29948981Ssheldonh{ 30048981Ssheldonh char buffer[BUFSIZE]; 30148981Ssheldonh int i; 30248981Ssheldonh 30348981Ssheldonh inetd_setproctitle(sep->se_service, s); 30448981Ssheldonh while ((i = read(s, buffer, sizeof(buffer))) > 0 && 30548981Ssheldonh write(s, buffer, i) > 0) 30648981Ssheldonh ; 30748981Ssheldonh exit(0); 30848981Ssheldonh} 30948981Ssheldonh 31049052Ssheldonh/* 31149052Ssheldonh * RFC1413 Identification Protocol. Given a TCP port number pair, return a 31249052Ssheldonh * character string which identifies the owner of that connection on the 31349057Sgreen * server's system. Extended to allow for ~/.fakeid support and ~/.noident 31449057Sgreen * support. 31549052Ssheldonh */ 31649052Ssheldonh 31777684Sdwmalone/* RFC 1413 says the following are the only errors you can return. */ 31877684Sdwmalone#define ID_INVALID "INVALID-PORT" /* Port number improperly specified. */ 31977684Sdwmalone#define ID_NOUSER "NO-USER" /* Port not in use/not identifable. */ 32077684Sdwmalone#define ID_HIDDEN "HIDDEN-USER" /* Hiden at user's request. */ 32177684Sdwmalone#define ID_UNKNOWN "UNKNOWN-ERROR" /* Everything else. */ 32277684Sdwmalone 32398559Sjmallett/* Generic ident_stream error-sending func */ 32448981Ssheldonh/* ARGSUSED */ 32548981Ssheldonhvoid 32698559Sjmallettiderror(int lport, int fport, int s, const char *er) 32748981Ssheldonh{ 32849004Sgreen char *p; 32949004Sgreen 33077684Sdwmalone asprintf(&p, "%d , %d : ERROR : %s\r\n", lport, fport, er); 33149030Ssheldonh if (p == NULL) { 33249057Sgreen syslog(LOG_ERR, "asprintf: %m"); 33349030Ssheldonh exit(EX_OSERR); 33449030Ssheldonh } 33558735Ssheldonh send(s, p, strlen(p), MSG_EOF); 33649004Sgreen free(p); 33748981Ssheldonh 33848981Ssheldonh exit(0); 33948981Ssheldonh} 34048981Ssheldonh 34198559Sjmallett/* Ident service (AKA "auth") */ 34248981Ssheldonh/* ARGSUSED */ 34348981Ssheldonhvoid 34498559Sjmallettident_stream(int s, struct servtab *sep) 34548981Ssheldonh{ 34649089Sgreen struct utsname un; 34749089Sgreen struct stat sb; 34878694Sdwmalone struct sockaddr_in sin4[2]; 34957906Sshin#ifdef INET6 35056590Sshin struct sockaddr_in6 sin6[2]; 35157906Sshin#endif 35256590Sshin struct sockaddr_storage ss[2]; 35372650Sgreen struct xucred uc; 35449004Sgreen struct timeval tv = { 35549004Sgreen 10, 35649004Sgreen 0 35763045Sdwmalone }, to; 35856298Sgreen struct passwd *pw = NULL; 35949004Sgreen fd_set fdset; 36077684Sdwmalone char buf[BUFSIZE], *p, **av, *osname = NULL, e; 36177684Sdwmalone char idbuf[MAXLOGNAME] = ""; /* Big enough to hold uid in decimal. */ 36261099Sgreen socklen_t socklen; 36361099Sgreen ssize_t ssize; 36463045Sdwmalone size_t size, bufsiz; 36577684Sdwmalone int c, fflag = 0, nflag = 0, rflag = 0, argc = 0; 36677684Sdwmalone int gflag = 0, iflag = 0, Fflag = 0, getcredfail = 0, onreadlen; 36748981Ssheldonh u_short lport, fport; 36848981Ssheldonh 36948981Ssheldonh inetd_setproctitle(sep->se_service, s); 37049104Sgreen /* 37149104Sgreen * Reset getopt() since we are a fork() but not an exec() from 37249104Sgreen * a parent which used getopt() already. 37349104Sgreen */ 37448981Ssheldonh optind = 1; 37548981Ssheldonh optreset = 1; 37649104Sgreen /* 37749104Sgreen * Take the internal argument vector and count it out to make an 37849104Sgreen * argument count for getopt. This can be used for any internal 37949104Sgreen * service to read arguments and use getopt() easily. 38049104Sgreen */ 38148981Ssheldonh for (av = sep->se_argv; *av; av++) 38248981Ssheldonh argc++; 38348981Ssheldonh if (argc) { 38449054Sgreen int sec, usec; 38556298Sgreen size_t i; 38678694Sdwmalone u_int32_t rnd32; 38749054Sgreen 38877684Sdwmalone while ((c = getopt(argc, sep->se_argv, "d:fFgino:rt:")) != -1) 38948981Ssheldonh switch (c) { 39056298Sgreen case 'd': 39177684Sdwmalone if (!gflag) 39277684Sdwmalone strlcpy(idbuf, optarg, sizeof(idbuf)); 39356298Sgreen break; 39448981Ssheldonh case 'f': 39548981Ssheldonh fflag = 1; 39648981Ssheldonh break; 39769620Sdwmalone case 'F': 39869620Sdwmalone fflag = 1; 39969620Sdwmalone Fflag=1; 40069620Sdwmalone break; 40156298Sgreen case 'g': 40256298Sgreen gflag = 1; 40378694Sdwmalone rnd32 = 0; /* Shush, compiler. */ 40456303Sgreen /* 40578694Sdwmalone * The number of bits in "rnd32" divided 40656303Sgreen * by the number of bits needed per iteration 40756303Sgreen * gives a more optimal way to reload the 40856303Sgreen * random number only when necessary. 40956303Sgreen * 410100498Sfanf * 32 bits from arc4random corresponds to 41177684Sdwmalone * about 6 base-36 digits, so we reseed evey 6. 41256303Sgreen */ 41377684Sdwmalone for (i = 0; i < sizeof(idbuf) - 1; i++) { 41477684Sdwmalone static const char *const base36 = 41556303Sgreen "0123456789" 41656303Sgreen "abcdefghijklmnopqrstuvwxyz"; 41777684Sdwmalone if (i % 6 == 0) 41878694Sdwmalone rnd32 = arc4random(); 41978694Sdwmalone idbuf[i] = base36[rnd32 % 36]; 42078694Sdwmalone rnd32 /= 36; 42156298Sgreen } 42277684Sdwmalone idbuf[i] = '\0'; 42356298Sgreen break; 42477684Sdwmalone case 'i': 42577684Sdwmalone iflag = 1; 42677684Sdwmalone break; 42749057Sgreen case 'n': 42849057Sgreen nflag = 1; 42948981Ssheldonh break; 43049004Sgreen case 'o': 43149004Sgreen osname = optarg; 43249004Sgreen break; 43349057Sgreen case 'r': 43449057Sgreen rflag = 1; 43549057Sgreen break; 43649051Ssheldonh case 't': 43749030Ssheldonh switch (sscanf(optarg, "%d.%d", &sec, &usec)) { 43849030Ssheldonh case 2: 43949030Ssheldonh tv.tv_usec = usec; 44077684Sdwmalone /* FALLTHROUGH */ 44149030Ssheldonh case 1: 44249030Ssheldonh tv.tv_sec = sec; 44349030Ssheldonh break; 44449030Ssheldonh default: 44549030Ssheldonh if (debug) 44649030Ssheldonh warnx("bad -t argument"); 44749030Ssheldonh break; 44849030Ssheldonh } 44949054Sgreen break; 45048981Ssheldonh default: 45148981Ssheldonh break; 45248981Ssheldonh } 45348981Ssheldonh } 45449004Sgreen if (osname == NULL) { 45549033Sgreen if (uname(&un) == -1) 45677684Sdwmalone iderror(0, 0, s, ID_UNKNOWN); 45749004Sgreen osname = un.sysname; 45849004Sgreen } 45977684Sdwmalone 46049104Sgreen /* 46149104Sgreen * We're going to prepare for and execute reception of a 46249104Sgreen * packet of data from the user. The data is in the format 46349104Sgreen * "local_port , foreign_port\r\n" (with local being the 46449104Sgreen * server's port and foreign being the client's.) 46549104Sgreen */ 46663045Sdwmalone gettimeofday(&to, NULL); 46763045Sdwmalone to.tv_sec += tv.tv_sec; 46869532Sgreen to.tv_usec += tv.tv_usec; 46969532Sgreen if (to.tv_usec >= 1000000) { 47063045Sdwmalone to.tv_usec -= 1000000; 47163045Sdwmalone to.tv_sec++; 47263045Sdwmalone } 47363045Sdwmalone 47463045Sdwmalone size = 0; 47563045Sdwmalone bufsiz = sizeof(buf) - 1; 47649004Sgreen FD_ZERO(&fdset); 47774934Sdwmalone while (bufsiz > 0) { 47863045Sdwmalone gettimeofday(&tv, NULL); 47963045Sdwmalone tv.tv_sec = to.tv_sec - tv.tv_sec; 48063045Sdwmalone tv.tv_usec = to.tv_usec - tv.tv_usec; 48163045Sdwmalone if (tv.tv_usec < 0) { 48263045Sdwmalone tv.tv_usec += 1000000; 48363045Sdwmalone tv.tv_sec--; 48463045Sdwmalone } 48563045Sdwmalone if (tv.tv_sec < 0) 48663045Sdwmalone break; 48763045Sdwmalone FD_SET(s, &fdset); 48863045Sdwmalone if (select(s + 1, &fdset, NULL, NULL, &tv) == -1) 48977684Sdwmalone iderror(0, 0, s, ID_UNKNOWN); 49063045Sdwmalone if (ioctl(s, FIONREAD, &onreadlen) == -1) 49177684Sdwmalone iderror(0, 0, s, ID_UNKNOWN); 49278694Sdwmalone if ((size_t)onreadlen > bufsiz) 49363045Sdwmalone onreadlen = bufsiz; 49463045Sdwmalone ssize = read(s, &buf[size], (size_t)onreadlen); 49563045Sdwmalone if (ssize == -1) 49677684Sdwmalone iderror(0, 0, s, ID_UNKNOWN); 49766543Sdwmalone else if (ssize == 0) 49866543Sdwmalone break; 49963045Sdwmalone bufsiz -= ssize; 50063045Sdwmalone size += ssize; 50174934Sdwmalone if (memchr(&buf[size - ssize], '\n', ssize) != NULL) 50274934Sdwmalone break; 50363045Sdwmalone } 50463045Sdwmalone buf[size] = '\0'; 50563045Sdwmalone /* Read two characters, and check for a delimiting character */ 50663045Sdwmalone if (sscanf(buf, "%hu , %hu%c", &lport, &fport, &e) != 3 || isdigit(e)) 50777684Sdwmalone iderror(0, 0, s, ID_INVALID); 50877684Sdwmalone 50977684Sdwmalone /* Send garbage? */ 51077684Sdwmalone if (gflag) 51156298Sgreen goto printit; 51277684Sdwmalone 51349104Sgreen /* 51458712Sgreen * If not "real" (-r), send a HIDDEN-USER error for everything. 51558712Sgreen * If -d is used to set a fallback username, this is used to 51658712Sgreen * override it, and the fallback is returned instead. 51758712Sgreen */ 51858712Sgreen if (!rflag) { 51977684Sdwmalone if (*idbuf == '\0') 52077684Sdwmalone iderror(lport, fport, s, ID_HIDDEN); 52177684Sdwmalone goto printit; 52258712Sgreen } 52377684Sdwmalone 52458712Sgreen /* 52549104Sgreen * We take the input and construct an array of two sockaddr_ins 52649104Sgreen * which contain the local address information and foreign 52749104Sgreen * address information, respectively, used to look up the 52849104Sgreen * credentials for the socket (which are returned by the 52977684Sdwmalone * sysctl "net.inet.tcp.getcred" when we call it.) 53049104Sgreen */ 53177684Sdwmalone socklen = sizeof(ss[0]); 53277684Sdwmalone if (getsockname(s, (struct sockaddr *)&ss[0], &socklen) == -1) 53377684Sdwmalone iderror(lport, fport, s, ID_UNKNOWN); 53477684Sdwmalone socklen = sizeof(ss[1]); 53577684Sdwmalone if (getpeername(s, (struct sockaddr *)&ss[1], &socklen) == -1) 53677684Sdwmalone iderror(lport, fport, s, ID_UNKNOWN); 53756590Sshin if (ss[0].ss_family != ss[1].ss_family) 53877684Sdwmalone iderror(lport, fport, s, ID_UNKNOWN); 53961099Sgreen size = sizeof(uc); 54056590Sshin switch (ss[0].ss_family) { 54156590Sshin case AF_INET: 54278694Sdwmalone sin4[0] = *(struct sockaddr_in *)&ss[0]; 54378694Sdwmalone sin4[0].sin_port = htons(lport); 54478694Sdwmalone sin4[1] = *(struct sockaddr_in *)&ss[1]; 54578694Sdwmalone sin4[1].sin_port = htons(fport); 54678694Sdwmalone if (sysctlbyname("net.inet.tcp.getcred", &uc, &size, sin4, 54778694Sdwmalone sizeof(sin4)) == -1) 54869532Sgreen getcredfail = errno; 54956590Sshin break; 55056590Sshin#ifdef INET6 55156590Sshin case AF_INET6: 55256590Sshin sin6[0] = *(struct sockaddr_in6 *)&ss[0]; 55356590Sshin sin6[0].sin6_port = htons(lport); 55456590Sshin sin6[1] = *(struct sockaddr_in6 *)&ss[1]; 55556590Sshin sin6[1].sin6_port = htons(fport); 55661099Sgreen if (sysctlbyname("net.inet6.tcp6.getcred", &uc, &size, sin6, 55756590Sshin sizeof(sin6)) == -1) 55869532Sgreen getcredfail = errno; 55956590Sshin break; 56056590Sshin#endif 56156590Sshin default: /* should not reach here */ 56269532Sgreen getcredfail = EAFNOSUPPORT; 56356590Sshin break; 56456590Sshin } 56591354Sdd if (getcredfail != 0 || uc.cr_version != XUCRED_VERSION) { 56677684Sdwmalone if (*idbuf == '\0') 56777684Sdwmalone iderror(lport, fport, s, 56877684Sdwmalone getcredfail == ENOENT ? ID_NOUSER : ID_UNKNOWN); 56977684Sdwmalone goto printit; 57056298Sgreen } 57177684Sdwmalone 57277684Sdwmalone /* Look up the pw to get the username and home directory*/ 57377684Sdwmalone errno = 0; 57477684Sdwmalone pw = getpwuid(uc.cr_uid); 57577684Sdwmalone if (pw == NULL) 57677684Sdwmalone iderror(lport, fport, s, errno == 0 ? ID_NOUSER : ID_UNKNOWN); 57777684Sdwmalone 57877684Sdwmalone if (iflag) 57977684Sdwmalone snprintf(idbuf, sizeof(idbuf), "%u", (unsigned)pw->pw_uid); 58077684Sdwmalone else 58177684Sdwmalone strlcpy(idbuf, pw->pw_name, sizeof(idbuf)); 58277684Sdwmalone 58349104Sgreen /* 58449104Sgreen * If enabled, we check for a file named ".noident" in the user's 58549104Sgreen * home directory. If found, we return HIDDEN-USER. 58649104Sgreen */ 58777684Sdwmalone if (nflag) { 58849089Sgreen if (asprintf(&p, "%s/.noident", pw->pw_dir) == -1) 58977684Sdwmalone iderror(lport, fport, s, ID_UNKNOWN); 59049089Sgreen if (lstat(p, &sb) == 0) { 59149089Sgreen free(p); 59277684Sdwmalone iderror(lport, fport, s, ID_HIDDEN); 59349057Sgreen } 59449089Sgreen free(p); 59549057Sgreen } 59677684Sdwmalone 59749104Sgreen /* 59849104Sgreen * Here, if enabled, we read a user's ".fakeid" file in their 59949104Sgreen * home directory. It consists of a line containing the name 60049104Sgreen * they want. 60149104Sgreen */ 60277684Sdwmalone if (fflag) { 60369144Sgreen int fakeid_fd; 60449033Sgreen 60549104Sgreen /* 60649104Sgreen * Here we set ourself to effectively be the user, so we don't 60749104Sgreen * open any files we have no permission to open, especially 60849104Sgreen * symbolic links to sensitive root-owned files or devices. 60949104Sgreen */ 61069144Sgreen if (initgroups(pw->pw_name, pw->pw_gid) == -1) 61177684Sdwmalone iderror(lport, fport, s, ID_UNKNOWN); 61277684Sdwmalone if (seteuid(pw->pw_uid) == -1) 61377684Sdwmalone iderror(lport, fport, s, ID_UNKNOWN); 61449104Sgreen /* 61569532Sgreen * We can't stat() here since that would be a race 61669532Sgreen * condition. 61749104Sgreen * Therefore, we open the file we have permissions to open 61849104Sgreen * and if it's not a regular file, we close it and end up 61949104Sgreen * returning the user's real username. 62049104Sgreen */ 62177684Sdwmalone if (asprintf(&p, "%s/.fakeid", pw->pw_dir) == -1) 62277684Sdwmalone iderror(lport, fport, s, ID_UNKNOWN); 62369144Sgreen fakeid_fd = open(p, O_RDONLY | O_NONBLOCK); 62449089Sgreen free(p); 62577684Sdwmalone if (fakeid_fd == -1 || fstat(fakeid_fd, &sb) == -1 || 62677684Sdwmalone !S_ISREG(sb.st_mode)) 62777684Sdwmalone goto fakeid_fail; 62877684Sdwmalone 62977684Sdwmalone if ((ssize = read(fakeid_fd, buf, sizeof(buf) - 1)) < 0) 63077684Sdwmalone goto fakeid_fail; 63177684Sdwmalone buf[ssize] = '\0'; 63277684Sdwmalone 63377684Sdwmalone /* 63477684Sdwmalone * Usually, the file will have the desired identity 63577684Sdwmalone * in the form "identity\n". Allow for leading white 63677684Sdwmalone * space and trailing white space/end of line. 63777684Sdwmalone */ 63877684Sdwmalone p = buf; 63977684Sdwmalone p += strspn(p, " \t"); 64077684Sdwmalone p[strcspn(p, " \t\r\n")] = '\0'; 64177684Sdwmalone if (strlen(p) > MAXLOGNAME - 1) /* Too long (including nul)? */ 64277684Sdwmalone p[MAXLOGNAME - 1] = '\0'; 64377684Sdwmalone 64477684Sdwmalone /* 64577684Sdwmalone * If the name is a zero-length string or matches it 64677684Sdwmalone * the id or name of another user (unless permitted by -F) 64777684Sdwmalone * then it is invalid. 64877684Sdwmalone */ 64977684Sdwmalone if (*p == '\0') 65077684Sdwmalone goto fakeid_fail; 65177684Sdwmalone if (!Fflag) { 65277684Sdwmalone if (iflag) { 65377684Sdwmalone if (p[strspn(p, "0123456789")] == '\0' && 65477684Sdwmalone getpwuid(atoi(p)) != NULL) 65577684Sdwmalone goto fakeid_fail; 65677684Sdwmalone } else { 65777684Sdwmalone if (getpwnam(p) != NULL) 65877684Sdwmalone goto fakeid_fail; 65948981Ssheldonh } 66077684Sdwmalone } 66177684Sdwmalone 66277684Sdwmalone strlcpy(idbuf, p, sizeof(idbuf)); 66377684Sdwmalone 66477684Sdwmalonefakeid_fail: 66577684Sdwmalone if (fakeid_fd != -1) 66669144Sgreen close(fakeid_fd); 66777684Sdwmalone } 66877684Sdwmalone 66948981Ssheldonhprintit: 67049104Sgreen /* Finally, we make and send the reply. */ 67149004Sgreen if (asprintf(&p, "%d , %d : USERID : %s : %s\r\n", lport, fport, osname, 67277684Sdwmalone idbuf) == -1) { 67349057Sgreen syslog(LOG_ERR, "asprintf: %m"); 67449051Ssheldonh exit(EX_OSERR); 67549051Ssheldonh } 67658735Ssheldonh send(s, p, strlen(p), MSG_EOF); 67749004Sgreen free(p); 67848981Ssheldonh 67948981Ssheldonh exit(0); 68048981Ssheldonh} 68148981Ssheldonh 68248981Ssheldonh/* 683157820Sdwmalone * RFC738/868 Time Server. 68448981Ssheldonh * Return a machine readable date and time, in the form of the 68548981Ssheldonh * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 68648981Ssheldonh * returns the number of seconds since midnight, Jan 1, 1970, 68748981Ssheldonh * we must add 2208988800 seconds to this figure to make up for 68848981Ssheldonh * some seventy years Bell Labs was asleep. 68948981Ssheldonh */ 69048981Ssheldonh 691157816Sdwmaloneuint32_t 69298558Sjmallettmachtime(void) 69348981Ssheldonh{ 69448981Ssheldonh 695157816Sdwmalone#define OFFSET ((uint32_t)25567 * 24*60*60) 696239991Sed return (htonl((uint32_t)(time(NULL) + OFFSET))); 69748981Ssheldonh#undef OFFSET 69848981Ssheldonh} 69948981Ssheldonh 70048981Ssheldonh/* ARGSUSED */ 70148981Ssheldonhvoid 70298558Sjmallettmachtime_dg(int s, struct servtab *sep) 70348981Ssheldonh{ 704157816Sdwmalone uint32_t result; 70556590Sshin struct sockaddr_storage ss; 70657857Sshin socklen_t size; 70748981Ssheldonh 70856590Sshin size = sizeof(ss); 70948981Ssheldonh if (recvfrom(s, (char *)&result, sizeof(result), 0, 71056590Sshin (struct sockaddr *)&ss, &size) < 0) 71148981Ssheldonh return; 71248981Ssheldonh 71356590Sshin if (check_loop((struct sockaddr *)&ss, sep)) 71448981Ssheldonh return; 71548981Ssheldonh 71648981Ssheldonh result = machtime(); 71748981Ssheldonh (void) sendto(s, (char *) &result, sizeof(result), 0, 71857857Sshin (struct sockaddr *)&ss, size); 71948981Ssheldonh} 72048981Ssheldonh 72148981Ssheldonh/* ARGSUSED */ 72248981Ssheldonhvoid 72398561Sjmallettmachtime_stream(int s, struct servtab *sep __unused) 72448981Ssheldonh{ 725157816Sdwmalone uint32_t result; 72648981Ssheldonh 72748981Ssheldonh result = machtime(); 72858735Ssheldonh (void) send(s, (char *) &result, sizeof(result), MSG_EOF); 72948981Ssheldonh} 73048981Ssheldonh 73148981Ssheldonh/* 73249052Ssheldonh * RFC1078 TCP Port Service Multiplexer (TCPMUX). Service connections to 73349052Ssheldonh * services based on the service name sent. 73449052Ssheldonh * 73548981Ssheldonh * Based on TCPMUX.C by Mark K. Lottor November 1988 73648981Ssheldonh * sri-nic::ps:<mkl>tcpmux.c 73748981Ssheldonh */ 73848981Ssheldonh 73948981Ssheldonh#define MAX_SERV_LEN (256+2) /* 2 bytes for \r\n */ 74048981Ssheldonh#define strwrite(fd, buf) (void) write(fd, buf, sizeof(buf)-1) 74148981Ssheldonh 742228990Suqsstatic int /* # of characters up to \r,\n or \0 */ 743299356Sbaptget_line(int fd, char *buf, int len) 74448981Ssheldonh{ 74548981Ssheldonh int count = 0, n; 74648981Ssheldonh struct sigaction sa; 74748981Ssheldonh 74848981Ssheldonh sa.sa_flags = 0; 74948981Ssheldonh sigemptyset(&sa.sa_mask); 75048981Ssheldonh sa.sa_handler = SIG_DFL; 75148981Ssheldonh sigaction(SIGALRM, &sa, (struct sigaction *)0); 75248981Ssheldonh do { 75348981Ssheldonh alarm(10); 75448981Ssheldonh n = read(fd, buf, len-count); 75548981Ssheldonh alarm(0); 75648981Ssheldonh if (n == 0) 75748981Ssheldonh return (count); 75848981Ssheldonh if (n < 0) 75948981Ssheldonh return (-1); 76048981Ssheldonh while (--n >= 0) { 76148981Ssheldonh if (*buf == '\r' || *buf == '\n' || *buf == '\0') 76248981Ssheldonh return (count); 76348981Ssheldonh count++; 76448981Ssheldonh buf++; 76548981Ssheldonh } 76648981Ssheldonh } while (count < len); 76748981Ssheldonh return (count); 76848981Ssheldonh} 76948981Ssheldonh 77048981Ssheldonhstruct servtab * 77198558Sjmalletttcpmux(int s) 77248981Ssheldonh{ 77348981Ssheldonh struct servtab *sep; 77448981Ssheldonh char service[MAX_SERV_LEN+1]; 77548981Ssheldonh int len; 77648981Ssheldonh 77748981Ssheldonh /* Get requested service name */ 778299356Sbapt if ((len = get_line(s, service, MAX_SERV_LEN)) < 0) { 77948981Ssheldonh strwrite(s, "-Error reading service name\r\n"); 78048981Ssheldonh return (NULL); 78148981Ssheldonh } 78248981Ssheldonh service[len] = '\0'; 78348981Ssheldonh 78448981Ssheldonh if (debug) 78548981Ssheldonh warnx("tcpmux: someone wants %s", service); 78648981Ssheldonh 78748981Ssheldonh /* 78848981Ssheldonh * Help is a required command, and lists available services, 78948981Ssheldonh * one per line. 79048981Ssheldonh */ 79148981Ssheldonh if (!strcasecmp(service, "help")) { 79248981Ssheldonh for (sep = servtab; sep; sep = sep->se_next) { 79348981Ssheldonh if (!ISMUX(sep)) 79448981Ssheldonh continue; 79548981Ssheldonh (void)write(s,sep->se_service,strlen(sep->se_service)); 79648981Ssheldonh strwrite(s, "\r\n"); 79748981Ssheldonh } 79848981Ssheldonh return (NULL); 79948981Ssheldonh } 80048981Ssheldonh 80148981Ssheldonh /* Try matching a service in inetd.conf with the request */ 80248981Ssheldonh for (sep = servtab; sep; sep = sep->se_next) { 80348981Ssheldonh if (!ISMUX(sep)) 80448981Ssheldonh continue; 80548981Ssheldonh if (!strcasecmp(service, sep->se_service)) { 80648981Ssheldonh if (ISMUXPLUS(sep)) { 80748981Ssheldonh strwrite(s, "+Go\r\n"); 80848981Ssheldonh } 80948981Ssheldonh return (sep); 81048981Ssheldonh } 81148981Ssheldonh } 81248981Ssheldonh strwrite(s, "-Service not available\r\n"); 81348981Ssheldonh return (NULL); 81448981Ssheldonh} 815