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