1 /* This file is part of GNU Pies.
2    Copyright (C) 2009-2020 Sergey Poznyakoff
3 
4    GNU Pies is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3, or (at your option)
7    any later version.
8 
9    GNU Pies is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with GNU Pies.  If not, see <http://www.gnu.org/licenses/>. */
16 
17 #include "pies.h"
18 #include "prog.h"
19 #include <netdb.h>
20 
21 #define INTBUFSIZE	8192
22 
23 /* Echo protocol, RFC 862 */
24 static void
echo_stream(int fd,struct component const * comp)25 echo_stream (int fd, struct component const *comp)
26 {
27   int rc;
28   char buffer[INTBUFSIZE];
29 
30   while ((rc = read (fd, buffer, sizeof buffer)) > 0
31 	 && write (fd, buffer, rc) > 0)
32     ;
33 }
34 
35 static void
echo_dg(int fd,struct component const * comp)36 echo_dg (int fd, struct component const *comp)
37 {
38   int rc;
39   char buffer[INTBUFSIZE];
40   struct sockaddr sa;
41   socklen_t size = sizeof sa;
42 
43   rc = recvfrom (fd, buffer, sizeof buffer, 0, &sa, &size);
44   if (rc < 0)
45     return;
46   sendto (fd, buffer, rc, 0, &sa, sizeof sa);
47 }
48 
49 /* Discard protocol, RFC 863 */
50 static void
discard_stream(int fd,struct component const * comp)51 discard_stream (int fd, struct component const *comp)
52 {
53   int rc;
54   char buffer[INTBUFSIZE];
55 
56   while (1)
57     {
58       while ((rc = read (fd, buffer, sizeof buffer)) > 0)
59 	;
60       if (rc == 0 || errno != EINTR)
61 	break;
62     }
63 }
64 
65 static void
discard_dg(int fd,struct component const * comp)66 discard_dg (int fd, struct component const *comp)
67 {
68   char buffer[INTBUFSIZE];
69   read (fd, buffer, sizeof buffer);
70 }
71 
72 
73 /* Time Protocol, RFC 868 */
74 
75 /* Return a machine readable date and time as seconds since
76    midnight, Jan 1, 1900. */
77 
78 #define SEVENTY_YEARS ((unsigned long)25567 * 24 * 60 * 60)
79 
80 static unsigned long
time_since_1900(void)81 time_since_1900 (void)
82 {
83   struct timeval tv;
84 
85   if (gettimeofday (&tv, NULL) < 0)
86     {
87       logmsg (LOG_ERR, "gettimeofday: %s", strerror (errno));
88       return 0;
89     }
90   return htonl ((long) (tv.tv_sec + SEVENTY_YEARS));
91 }
92 
93 static void
time_stream(int fd,struct component const * comp)94 time_stream (int fd, struct component const *comp)
95 {
96   unsigned long result = time_since_1900 ();
97   if (write (fd, (char *) &result, sizeof result) == -1)
98     logmsg (LOG_ERR, "write: %s", strerror (errno));
99 }
100 
101 static void
time_dg(int fd,struct component const * comp)102 time_dg (int fd, struct component const *comp)
103 {
104   unsigned long result;
105   struct sockaddr sa;
106   socklen_t size = sizeof sa;
107 
108   if (recvfrom (fd, (char *) &result, sizeof result, 0, &sa, &size) < 0)
109     return;
110   result = time_since_1900 ();
111   sendto (fd, (char *) &result, sizeof result, 0, &sa, sizeof sa);
112 }
113 
114 /* Daytime Protocol, RFC 867 */
115 static void
daytime_stream(int fd,struct component const * comp)116 daytime_stream (int fd, struct component const *comp)
117 {
118   char buffer[27];
119   time_t now;
120 
121   time (&now);
122   sprintf (buffer, "%.24s\r\n", ctime (&now));
123   if (write (fd, buffer, strlen (buffer)) == -1)
124     logmsg (LOG_ERR, "write: %s", strerror (errno));
125 }
126 
127 static void
daytime_dg(int fd,struct component const * comp)128 daytime_dg (int fd, struct component const *comp)
129 {
130   char buffer[27];
131   time_t now;
132   struct sockaddr sa;
133   socklen_t size = sizeof sa;
134 
135   time (&now);
136 
137   if (recvfrom (fd, buffer, sizeof buffer, 0, &sa, &size) < 0)
138     return;
139   sprintf (buffer, "%.24s\r\n", ctime (&now));
140   sendto (fd, buffer, strlen (buffer), 0, &sa, sizeof sa);
141 }
142 
143 /* Character Generator Protocol, RFC 864 */
144 
145 #define LINESIZ 72
146 
147 static void
chargen_next_line(char * text)148 chargen_next_line (char *text)
149 {
150   static int ch = 0;
151   int i, c;
152 
153   do
154     ch = (ch + 1) % 128;
155   while (!c_isprint (ch));
156 
157   for (i = 0, c = ch; i < LINESIZ; )
158     {
159       if (c_isprint (c))
160 	text[i++] = c;
161       c = (c + 1) % 128;
162     }
163 }
164 
165 static void
chargen_stream(int fd,struct component const * comp)166 chargen_stream (int fd, struct component const *comp)
167 {
168   char text[LINESIZ + 2];
169 
170   text[LINESIZ] = '\r';
171   text[LINESIZ + 1] = '\n';
172 
173   while (1)
174     {
175       chargen_next_line (text);
176       if (write (fd, text, sizeof text) != sizeof text)
177 	break;
178     }
179 }
180 
181 static void
chargen_dg(int fd,struct component const * comp)182 chargen_dg (int fd, struct component const *comp)
183 {
184   struct sockaddr sa;
185   socklen_t size = sizeof sa;
186   char text[LINESIZ + 2];
187 
188   if (recvfrom (fd, text, sizeof text, 0, &sa, &size) < 0)
189     return;
190   text[LINESIZ] = '\r';
191   text[LINESIZ + 1] = '\n';
192   chargen_next_line (text);
193   sendto (fd, text, sizeof text, 0, &sa, sizeof sa);
194 }
195 
196 
197 /* Quote of the Day Protocol, RFC 865 */
198 
199 #define QOTD_MAX 512
200 #define QOTD_DEF "Quote of the Day\r\n"
201 
202 static size_t
trnl(char * text,size_t size)203 trnl (char *text, size_t size)
204 {
205   size_t off = size;
206 
207   for (; off > 0; off--)
208     if (text[off] == '\n')
209       {
210 	if (text[off-1] == '\r')
211 	  off--;
212 	else
213 	  {
214 	    if (size == QOTD_MAX)
215 	      size--;
216 	    memmove (text + off + 1, text + off, size - off);
217 	    text[off] = '\r';
218 	    size++;
219 	  }
220       }
221   return size;
222 }
223 
224 static size_t
qotd_read(char * text)225 qotd_read (char *text)
226 {
227   ssize_t rc;
228   int fd = open (qotdfile, O_RDONLY);
229   if (fd == -1)
230     {
231       logmsg (LOG_ERR, _("cannot open file %s: %s"), qotdfile,
232 	      strerror (errno));
233       strncpy (text, QOTD_DEF, QOTD_MAX);
234       rc = QOTD_MAX;
235     }
236   else
237     {
238       rc = read (fd, text, QOTD_MAX);
239       if (rc >= 0)
240 	rc = trnl (text, rc);
241       else
242 	{
243 	  logmsg (LOG_ERR, _("error reading %s: %s"),
244 		  qotdfile, strerror (errno));
245 	  strncpy (text, QOTD_DEF, QOTD_MAX);
246 	  rc = QOTD_MAX;
247 	}
248     }
249   close (fd);
250   return rc;
251 }
252 
253 static void
qotd_stream(int fd,struct component const * comp)254 qotd_stream (int fd, struct component const *comp)
255 {
256   char text[QOTD_MAX];
257   size_t len = qotd_read (text);
258   if (write (fd, text, len) == -1)
259     logmsg (LOG_ERR, "write: %s", strerror (errno));
260 }
261 
262 static void
qotd_dg(int fd,struct component const * comp)263 qotd_dg (int fd, struct component const *comp)
264 {
265   char text[QOTD_MAX];
266   struct sockaddr sa;
267   socklen_t size = sizeof sa;
268   size_t len;
269   if (recvfrom (fd, text, sizeof text, 0, &sa, &size) < 0)
270     return;
271   len = qotd_read (text);
272   sendto (fd, text, len, 0, &sa, sizeof sa);
273 }
274 
275 
276 /* TCPMUX service, RFC 1078 */
277 #define MAX_SERV_LEN    (256+2)
278 
279 static int
fd_getline(int fd,char * buf,int len)280 fd_getline (int fd, char *buf, int len)
281 {
282   int count = 0, n;
283 
284   do
285     {
286       n = read (fd, buf, len - count);
287       if (n == 0)
288 	return count;
289       if (n < 0)
290 	return -1;
291       while (--n >= 0)
292 	{
293 	  if (*buf == '\r' || *buf == '\n' || *buf == '\0')
294 	    return count;
295 	  count++;
296 	  buf++;
297 	}
298     }
299   while (count < len);
300   return count;
301 }
302 
303 static int
tcpmux_help(struct component * comp,void * data)304 tcpmux_help (struct component *comp, void *data)
305 {
306   int *pfd = data;
307 
308   if (ISCF_TCPMUX (comp->flags) && comp->prog && comp->prog->active)
309     {
310       fd_report (*pfd, comp->service);
311       fd_report (*pfd, "\r\n");
312     }
313   return 0;
314 }
315 
316 static void
tcpmux(int fd,struct component const * comp)317 tcpmux (int fd, struct component const *comp)
318 {
319   char service[MAX_SERV_LEN + 1];
320   size_t len;
321   struct component *srv_comp;
322   union pies_sockaddr_storage sa;
323   socklen_t salen = sizeof (sa);
324   int rc;
325 
326   /* Read service name */
327   if ((len = fd_getline (fd, service, MAX_SERV_LEN)) < 0)
328     {
329       fd_report (fd, "-Error reading service name\r\n");
330       return;
331     }
332   service[len] = 0;
333 
334   debug (2, ("tcpmux: someone wants %s", service));
335 
336   if (!strcasecmp (service, "help"))
337     {
338       component_foreach (tcpmux_help, &fd);
339       return;
340     }
341 
342   srv_comp = progman_lookup_tcpmux (service, comp->tag);
343   if (!srv_comp)
344     {
345       fd_report (fd, "-Service not available\r\n");
346       return;
347     }
348 
349   rc = getpeername (fd, (struct sockaddr *) &sa, &salen);
350   if (rc)
351     logmsg (LOG_ERR, _("%s: cannot get peer name: %s"),
352 	    comp->tag, strerror (errno));
353 
354   if (comp->acl)
355     {
356       if (rc)
357 	{
358 	  fd_report (fd, "-Service not available\r\n");
359 	  return;
360 	}
361 
362       if (check_acl (comp->acl, (struct sockaddr *) &sa, salen, NULL))
363 	{
364 	  fd_report (fd, "-Service not available\r\n");
365 	  return;
366 	}
367     }
368   /* FIXME: What about max-instances, etc.? */
369 
370   if (srv_comp->flags & CF_TCPMUXPLUS)
371     fd_report (fd, "+Go\r\n");
372 
373   progman_run_comp (srv_comp, fd, &sa, salen);
374 }
375 
376 
377 struct inetd_builtin inetd_builtin_tab[] = {
378     /* Echo received data */
379     {"echo",    SOCK_STREAM, 0, 0, echo_stream},
380     {"echo",    SOCK_DGRAM,  1, 0, echo_dg},
381     /* Internet /dev/null */
382     {"discard", SOCK_STREAM, 0, 0, discard_stream},
383     {"discard", SOCK_DGRAM,  1, 0, discard_dg},
384     /* Return 32 bit time since 1900 */
385     {"time",    SOCK_STREAM, 1, 0, time_stream},
386     {"time",    SOCK_DGRAM,  1, 0, time_dg},
387     /* Return human-readable time */
388     {"daytime", SOCK_STREAM, 1, 0, daytime_stream},
389     {"daytime", SOCK_DGRAM,  1, 0, daytime_dg},
390     /* Character generator */
391     {"chargen", SOCK_STREAM, 0, 0, chargen_stream},
392     {"chargen", SOCK_DGRAM,  1, 0, chargen_dg},
393     /* Quote of the Day */
394     {"qotd",    SOCK_STREAM, 0, 0, qotd_stream},
395     {"qotd",    SOCK_DGRAM,  1, 0, qotd_dg},
396     /* TCPMUX */
397     {"tcpmux",  SOCK_STREAM, 0, 0, tcpmux},
398     {NULL, 0, 0, 0, NULL}
399 };
400 
401 struct inetd_builtin *
inetd_builtin_lookup(const char * service,int socktype)402 inetd_builtin_lookup (const char *service, int socktype)
403 {
404   struct inetd_builtin *bp;
405 
406   for (bp = inetd_builtin_tab; bp->service; bp++)
407     if (bp->socktype == socktype && strcmp (bp->service, service) == 0)
408       return bp;
409   return NULL;
410 }
411