Ultrix-3.1/src/etc/miscd.c
/**********************************************************************
* Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. *
* All Rights Reserved. *
* Reference "/usr/src/COPYRIGHT" for applicable restrictions. *
**********************************************************************/
#ifndef lint
static char *sccsid = "@(#)miscd.c 3.0 (ULTRIX-11) 4/22/86";
/*
* Based on "@(#)miscd.c 1.1 (ULTRIX-32) 4/11/85";
*/
#endif lint
/*-----------------------------------------------------------------------
* Modification History
*
* 4/5/85 -- jrs
* Created to serve under inetd to implement some of
* the cheap internet services. Based on a concept by
* Marshall Rose of UC Irvine and Chris Kent of Purdue.
*
*-----------------------------------------------------------------------
*/
#include <stdio.h>
#include <signal.h>
#ifdef pdp11
#define signal sigset
#endif pdp11
#include <sys/types.h>
#include <sys/socket.h>
#ifndef pdp11
#include <sys/time.h>
#endif pdp11
#include <netinet/in.h>
#include <netdb.h>
#include <syslog.h>
#define TIMEOUT 120
#define BUFFERCNT 4096
#define LINECNT 80
char *daemoname;
int timeout();
FILE *popen();
/*
* This program performs some of the small internet utility functions.
* It runs subservient to inetd.
*
* The main routine determines the port and protocol. We look it
* up in the /etc/services table and then call the action switcher
*/
main(argc, argv)
int argc;
char **argv;
{
int on = 1, socklen;
int tcpsock;
struct sockaddr_in sock;
struct servent *serv;
char servnam[16];
/* This is to try and find if we are tcp or udp.
When a better way is found, this code should be replaced */
socklen = sizeof (sock);
if (getpeername(0, &sock, &socklen) < 0) {
tcpsock = 0;
} else {
tcpsock = 1;
}
socklen = sizeof (sock);
if (getsockname(0, &sock, &socklen) < 0) {
openlog(argv[0], LOG_PID);
syslog(LOG_ERR, "getsockname: %m");
closelog();
exit(1);
}
serv = getservbyport(sock.sin_port, tcpsock? "tcp": "udp");
if (serv == NULL) {
openlog(argv[0], LOG_PID);
syslog(LOG_ERR, "getservbyport failed");
closelog();
exit(1);
}
(void) signal(SIGALRM, timeout);
if (tcpsock == 0) {
(void) alarm(TIMEOUT);
} else {
if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
openlog(argv[0], LOG_PID);
syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
closelog();
}
}
(void) strcpy(servnam, serv->s_name);
daemoname = argv[0];
doit(0, servnam, tcpsock);
}
/*
* This routine acts as the main switcher for all functionality
* Note that the code is designed to handle both tcp and udp
* sockets. When invoked on tcp sockets, the server will terminate
* immediately when the connection is closed. For the udp case,
* we will stay alive until two minutes go by without incoming
* packets.
*/
doit(f, servnam, tcpsock)
int f;
char *servnam;
int tcpsock;
{
int count;
char buffer[BUFFERCNT];
char line[LINECNT];
struct sockaddr from;
int fromlen;
int rotate;
#ifndef pdp11
struct timeval nowtime;
struct timezone nowzone;
unsigned long nowbias;
#else pdp11
long nowbias;
#endif pdp11
/* simple echo of recieved packet */
if (strcmp(servnam, "echo") == 0) {
if (tcpsock == 0) {
while (1) {
fromlen = sizeof(from);
count = recvfrom(f, buffer, sizeof(buffer),
0, &from, &fromlen);
(void) alarm(TIMEOUT);
if (count < 0) {
openlog(daemoname, LOG_PID);
syslog(LOG_ERR, "recvfrom: %m");
closelog();
exit(1);
}
if (sendto(f, buffer, count, 0, &from, fromlen)
< 0) {
openlog(daemoname, LOG_PID);
syslog(LOG_ERR, "sendto: %m");
closelog();
exit(1);
}
}
} else {
while ((count = read(f, buffer, sizeof(buffer))) > 0) {
(void) alarm(TIMEOUT);
if (write(f, buffer, count) != count) {
break;
}
(void) alarm(0);
}
}
/* throw away imcoming data (without error) */
} else if (strcmp(servnam, "discard") == 0) {
if (tcpsock == 0) {
while (1) {
fromlen = sizeof(from);
count = recvfrom(f, buffer, sizeof(buffer),
0, &from, &fromlen);
(void) alarm(TIMEOUT);
if (count < 0) {
openlog(daemoname, LOG_PID);
syslog(LOG_ERR, "recvfrom: %m");
closelog();
exit(1);
}
}
} else {
while ((count = read(f, buffer, sizeof(buffer))) > 0) {
;
}
}
/* return ascii text giving our list of users */
} else if (strcmp(servnam, "systat") == 0) {
if (tcpsock == 0) {
while (1) {
fromlen = sizeof(from);
count = recvfrom(f, buffer, sizeof(buffer),
0, &from, &fromlen);
(void) alarm(TIMEOUT);
if (count < 0) {
openlog(daemoname, LOG_PID);
syslog(LOG_ERR, "recvfrom: %m");
closelog();
exit(1);
}
count = invoke("who", buffer, BUFFERCNT);
if (sendto(f, buffer, count, 0, &from, fromlen)
< 0) {
openlog(daemoname, LOG_PID);
syslog(LOG_ERR, "sendto: %m");
closelog();
exit(1);
}
}
} else {
count = invoke("who", buffer, BUFFERCNT);
(void) alarm(TIMEOUT);
(void) write(f, buffer, count);
(void) alarm(0);
}
/* return ascii string giving our idea of time */
} else if (strcmp(servnam, "daytime") == 0) {
if (tcpsock == 0) {
while (1) {
fromlen = sizeof(from);
count = recvfrom(f, buffer, sizeof(buffer),
0, &from, &fromlen);
(void) alarm(TIMEOUT);
if (count < 0) {
openlog(daemoname, LOG_PID);
syslog(LOG_ERR, "recvfrom: %m");
closelog();
exit(1);
}
count = invoke("date", buffer, BUFFERCNT);
if (sendto(f, buffer, count, 0, &from, fromlen)
< 0) {
openlog(daemoname, LOG_PID);
syslog(LOG_ERR, "sendto: %m");
closelog();
exit(1);
}
}
} else {
count = invoke("date", buffer, BUFFERCNT);
(void) alarm(TIMEOUT);
(void) write(f, buffer, count);
(void) alarm(0);
}
/* return ascii text buffer of short length - we use fortune to gen */
} else if (strcmp(servnam, "quote") == 0) {
if (tcpsock == 0) {
while (1) {
fromlen = sizeof(from);
count = recvfrom(f, buffer, sizeof(buffer),
0, &from, &fromlen);
(void) alarm(TIMEOUT);
if (count < 0) {
openlog(daemoname, LOG_PID);
syslog(LOG_ERR, "recvfrom: %m");
closelog();
exit(1);
}
count = invoke("/usr/games/fortune",
buffer, BUFFERCNT);
if (sendto(f, buffer, count, 0, &from, fromlen)
< 0) {
openlog(daemoname, LOG_PID);
syslog(LOG_ERR, "sendto: %m");
closelog();
exit(1);
}
}
} else {
count = invoke("/usr/games/fortune", buffer, BUFFERCNT);
(void) alarm(TIMEOUT);
(void) write(f, buffer, count);
(void) alarm(0);
}
/* generate character pattern (silly for udp, but..) */
} else if (strcmp(servnam, "chargen") == 0) {
(void) strcpy(line, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
(void) strcat(line, "abcdefghijklmnopqrstuvwxyz");
(void) strcat(line, "0123456789");
(void) strcat(line, "!@#$%^&*()-=+[]{}");
rotate = 0;
if (tcpsock == 0) {
while (1) {
fromlen = sizeof(from);
count = recvfrom(f, buffer, sizeof(buffer),
0, &from, &fromlen);
(void) alarm(TIMEOUT);
if (count < 0) {
openlog(daemoname, LOG_PID);
syslog(LOG_ERR, "recvfrom: %m");
closelog();
exit(1);
}
*buffer = '\0';
for (count = 0; count < 8; count++) {
(void) strcat(buffer, &line[rotate]);
(void) strncat(buffer, line, rotate);
(void) strcat(buffer, "\r\n");
rotate = (rotate + 1) % strlen(line);
}
count = strlen(buffer);
if (sendto(f, buffer, count, 0, &from, fromlen)
< 0) {
openlog(daemoname, LOG_PID);
syslog(LOG_ERR, "sendto: %m");
closelog();
exit(1);
}
}
} else {
while (1) {
(void) strcpy(buffer, &line[rotate]);
(void) strncat(buffer, line, rotate);
(void) strcat(buffer, "\r\n");
rotate = (rotate + 1) % strlen(line);
count = strlen(buffer);
(void) alarm(TIMEOUT);
if (write(f, buffer, count) != count) {
break;
}
(void) alarm(0);
}
}
/* return longword giving biased time in seconds since 1900 */
} else if (strcmp(servnam, "time") == 0) {
if (tcpsock == 0) {
while (1) {
fromlen = sizeof(from);
count = recvfrom(f, buffer, sizeof(buffer),
0, &from, &fromlen);
(void) alarm(TIMEOUT);
if (count < 0) {
openlog(daemoname, LOG_PID);
syslog(LOG_ERR, "recvfrom: %m");
closelog();
exit(1);
}
#ifndef pdp11
(void) gettimeofday(&nowtime, &nowzone);
nowbias = htonl(nowtime.tv_sec + 2208988800l);
#else pdp11
time(&nowbias);
nowbias += 2208988800L;
nowbias = htonl(nowbias);
#endif pdp11
if (sendto(f, &nowbias, sizeof(nowbias), 0,
&from, fromlen) < 0) {
openlog(daemoname, LOG_PID);
syslog(LOG_ERR, "sendto: %m");
closelog();
exit(1);
}
}
} else {
#ifndef pdp11
(void) gettimeofday(&nowtime, &nowzone);
nowbias = htonl(nowtime.tv_sec + 2208988800l);
#else pdp11
time(&nowbias);
nowbias += 2208988800L;
nowbias = htonl(nowbias);
#endif pdp11
(void) alarm(TIMEOUT);
(void) write(f, &nowbias, sizeof(nowbias));
(void) alarm(0);
}
/* we have been called to do something we don't know how */
} else {
openlog(daemoname, LOG_PID);
syslog(LOG_WARNING, "unimplemented service: %s/%s", servnam,
tcpsock? "tcp": "udp");
closelog();
}
}
/*
* Gracefully handle final alarm for udp shutdown
*/
timeout()
{
exit(0);
}
/*
* Invoke given command and return buffer full of output.
* Add carriage returns to each line as that's how internet
* likes to see things.
*/
invoke(command, buffer, size)
char *command;
char *buffer;
int size;
{
int count;
register char *bp;
FILE *cmd;
if ((cmd = popen(command, "r")) == NULL) {
openlog(daemoname, LOG_PID);
syslog(LOG_ERR, "command failure: %m");
closelog();
exit(1);
}
count = 0;
bp = buffer;
while (fgets(bp, size - count - 1, cmd) != NULL) {
bp = buffer + strlen(buffer) - 1;
if (*bp != '\n') {
break;
}
*bp++ = '\r';
*bp++ = '\n';
*bp = '\0';
count = bp - buffer;
}
(void) pclose(cmd);
return(count);
}