1 /*
2  *  ser2net - A program for allowing telnet connection to serial ports
3  *  Copyright (C) 2001  Corey Minyard <minyard@acm.org>
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 
20 #include <sys/time.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <fcntl.h>
26 #include <netinet/in.h>
27 #include <errno.h>
28 #include <syslog.h>
29 
30 #include "ser2net.h"
31 #include "controller.h"
32 #include "selector.h"
33 #include "dataxfer.h"
34 #include "utils.h"
35 #include "telnet.h"
36 #include "locking.h"
37 
38 /** BASED ON sshd.c FROM openssh.com */
39 #ifdef HAVE_TCPD_H
40 #include <tcpd.h>
41 int allow_severity = LOG_INFO;
42 int deny_severity = LOG_WARNING;
43 static char *progname = "ser2net-control";
44 #endif /* HAVE_TCPD_H */
45 
46 /* This file holds the code that runs the control port. */
47 
48 DEFINE_LOCK_INIT(static, cntlr_lock)
49 static struct addrinfo *cntrl_ai;
50 static struct opensocks *acceptfds;/* File descriptors for the accept port. */
51 static unsigned int nr_acceptfds;
52 static waiter_t *accept_waiter;
53 
54 static int max_controller_ports = 4;	/* How many control connections
55 					   do we allow at a time. */
56 static int num_controller_ports = 0;	/* How many control connections
57 					   are currently active. */
58 
59 #define INBUF_SIZE 255	/* The size of the maximum input command. */
60 
61 char *prompt = "-> ";
62 
63 /* This data structure is kept for each control connection. */
64 typedef struct controller_info {
65     DEFINE_LOCK(, lock)
66     int in_shutdown;
67 
68     int            tcpfd;		/* When connected, the file
69                                            descriptor for the TCP
70                                            port used for I/O. */
71     struct sockaddr_storage remote;	/* The socket address of who
72 					   is connected to this port. */
73 
74     unsigned char inbuf[INBUF_SIZE + 1];/* Buffer to receive command on. */
75     int  inbuf_count;			/* The number of bytes currently
76 					   in the inbuf. */
77 
78     char *outbuf;			/* The output buffer, NULL if
79 					   no output. */
80     int  outbufsize;			/* Total size of the memory
81 					   allocated in outbuf. */
82     int  outbuf_pos;			/* The current position in the
83 					   output buffer. */
84     int  outbuf_count;			/* The number of bytes
85 					   (starting at outbuf_pos)
86 					   left to transmit. */
87 
88     void *monitor_port_id;		/* When port monitoring, this is
89 					   the id given when the monitoring
90 					   is started.  It is used to stop
91 					   monitoring. */
92 
93     struct controller_info *next;	/* Used to keep these items in
94 					   a linked list. */
95 
96     /* Data used by the telnet processing. */
97     telnet_data_t tn_data;
98 
99     void (*shutdown_complete)(void *);
100     void *shutdown_complete_cb_data;
101 } controller_info_t;
102 
103 static waiter_t *controller_shutdown_waiter;
104 
105 /* List of current control connections. */
106 controller_info_t *controllers = NULL;
107 
108 /* Used to initialize the telnet session. */
109 static unsigned char telnet_init_seq[] = {
110     TN_IAC, TN_WILL, TN_OPT_SUPPRESS_GO_AHEAD,
111     TN_IAC, TN_WILL, TN_OPT_ECHO,
112     TN_IAC, TN_DONT, TN_OPT_ECHO,
113 };
114 
115 static struct telnet_cmd telnet_cmds[] =
116 {
117     /*                        I will,  I do,  sent will, sent do */
118     { TN_OPT_SUPPRESS_GO_AHEAD,	   0,     1,          1,       0, },
119     { TN_OPT_ECHO,		   0,     1,          1,       1, },
120     { TN_OPT_BINARY_TRANSMISSION,  1,     1,          0,       1, },
121     { 255 }
122 };
123 
124 static void
shutdown_controller2(controller_info_t * cntlr)125 shutdown_controller2(controller_info_t *cntlr)
126 {
127     controller_info_t *prev;
128     controller_info_t *curr;
129     void (*shutdown_complete)(void *);
130     void *shutdown_complete_cb_data;
131 
132     FREE_LOCK(cntlr->lock);
133 
134     close(cntlr->tcpfd);
135     if (cntlr->outbuf != NULL) {
136 	free(cntlr->outbuf);
137     }
138     cntlr->outbuf = NULL;
139 
140     /* Remove it from the linked list. */
141     prev = NULL;
142     LOCK(cntlr_lock);
143     curr = controllers;
144     while (curr != NULL) {
145 	if (cntlr == curr) {
146 	    if (prev == NULL) {
147 		controllers = controllers->next;
148 	    } else {
149 		prev->next = curr->next;
150 	    }
151 	    num_controller_ports--;
152 	    break;
153 	}
154 
155 	prev = curr;
156 	curr = curr->next;
157     }
158     UNLOCK(cntlr_lock);
159 
160     shutdown_complete = cntlr->shutdown_complete;
161     shutdown_complete_cb_data = cntlr->shutdown_complete_cb_data;
162 
163     free(cntlr);
164 
165     if (shutdown_complete)
166 	shutdown_complete(shutdown_complete_cb_data);
167 }
168 
169 /* Shut down a control connection and remove it from the list of
170    controllers. */
171 static void
shutdown_controller(controller_info_t * cntlr)172 shutdown_controller(controller_info_t *cntlr)
173 {
174     if (cntlr->in_shutdown) {
175 	UNLOCK(cntlr->lock);
176 	return;
177     }
178 
179     if (cntlr->monitor_port_id != NULL) {
180 	data_monitor_stop(cntlr, cntlr->monitor_port_id);
181 	cntlr->monitor_port_id = NULL;
182     }
183 
184     cntlr->in_shutdown = 1;
185     UNLOCK(cntlr->lock);
186 
187     sel_clear_fd_handlers(ser2net_sel, cntlr->tcpfd);
188     /* The rest is handled in the done callback, which calls
189        shutdown_controller2. */
190 }
191 
192 /* Send some output to the control connection.  This allocates and
193    free a buffer in blocks of 1024 and increases the size of the
194    buffer as necessary. */
195 void
controller_output(struct controller_info * cntlr,const char * data,int count)196 controller_output(struct controller_info *cntlr,
197 		  const char             *data,
198 		  int                    count)
199 {
200     if (cntlr->outbuf != NULL) {
201 	/* Already outputting data, just add more onto it. */
202 	int  new_size = cntlr->outbuf_count + count;
203 
204 	if (new_size <= cntlr->outbufsize) {
205 	    /* It will fit into the current buffer, just move things
206 	       around and append it. */
207 	    if (cntlr->outbuf_pos > 0) {
208 		int i;
209 
210 		for (i = 0; i < cntlr->outbuf_count; i++) {
211 		    cntlr->outbuf[i] = cntlr->outbuf[cntlr->outbuf_pos + i];
212 		}
213 	    }
214 	    memcpy(&(cntlr->outbuf[cntlr->outbuf_count]), data, count);
215 	} else {
216 	    /* We need to allocate a larger buffer. */
217 	    char *newbuf;
218 
219 	    /* Allocate the next even multiple of 1024 bytes. */
220 	    new_size = ((new_size / 1024) * 1024) + 1024;
221 	    newbuf = malloc(new_size);
222 
223 	    if (newbuf == NULL) {
224 		/* Out of memory, just ignore the request */
225 		return;
226 	    }
227 
228 	    cntlr->outbufsize = new_size;
229 
230 	    /* Copy all the data into a new buffer. */
231 	    memcpy(newbuf,
232 		   &(cntlr->outbuf[cntlr->outbuf_pos]),
233 		   cntlr->outbuf_count);
234 	    memcpy(newbuf + cntlr->outbuf_count, data, count);
235 	    free(cntlr->outbuf);
236 	    cntlr->outbuf = newbuf;
237 	}
238 	cntlr->outbuf_pos = 0;
239 	cntlr->outbuf_count += count;
240     } else {
241 	/* We are starting a new buffer, just get it. */
242 	char *newbuf;
243 	int  new_size = ((count / 1024) * 1024) + 1024;
244 
245 	newbuf = malloc(new_size);
246 	if (newbuf == NULL) {
247 	    /* Out of memory, just ignore thre request */
248 	    return;
249 	}
250 
251 	cntlr->outbufsize = new_size;
252 
253 	memcpy(newbuf, data, count);
254 	cntlr->outbuf = newbuf;
255 	cntlr->outbuf_pos = 0;
256 	cntlr->outbuf_count = count;
257 	sel_set_fd_read_handler(ser2net_sel, cntlr->tcpfd,
258 				SEL_FD_HANDLER_DISABLED);
259 	sel_set_fd_write_handler(ser2net_sel, cntlr->tcpfd,
260 				 SEL_FD_HANDLER_ENABLED);
261     }
262 }
263 
264 int
controller_voutputf(struct controller_info * cntlr,const char * str,va_list ap)265 controller_voutputf(struct controller_info *cntlr, const char *str, va_list ap)
266 {
267     char buffer[1024];
268     int rv;
269 
270     rv = vsnprintf(buffer, sizeof(buffer), str, ap);
271     controller_output(cntlr, buffer, rv);
272     return rv;
273 }
274 
275 int
controller_outputf(struct controller_info * cntlr,const char * str,...)276 controller_outputf(struct controller_info *cntlr, const char *str, ...)
277 {
278     va_list ap;
279     int rv;
280 
281     va_start(ap, str);
282     rv = controller_voutputf(cntlr, str, ap);
283     va_end(ap);
284     return rv;
285 }
286 
controller_outs(struct controller_info * cntlr,char * s)287 void controller_outs(struct controller_info *cntlr, char *s)
288 {
289     controller_output (cntlr, s, strlen(s));
290 }
291 
292 
293 /* Write some data directly to the controllers output port. */
294 void
controller_write(struct controller_info * cntlr,const char * data,int count)295 controller_write(struct controller_info *cntlr, const char *data, int count)
296 {
297     write_ignore_fail(cntlr->tcpfd, data, count);
298 }
299 
300 static void
telnet_output_ready(void * cb_data)301 telnet_output_ready(void *cb_data)
302 {
303     struct controller_info *cntlr = cb_data;
304 
305     sel_set_fd_read_handler(ser2net_sel, cntlr->tcpfd,
306 			    SEL_FD_HANDLER_DISABLED);
307     sel_set_fd_write_handler(ser2net_sel, cntlr->tcpfd,
308 			     SEL_FD_HANDLER_ENABLED);
309 }
310 
311 /* Called when a telnet command is received. */
312 void
telnet_cmd_handler(void * cb_data,unsigned char cmd)313 telnet_cmd_handler(void *cb_data, unsigned char cmd)
314 {
315     /* These are ignored for now. */
316 }
317 
318 static char *help_str =
319 "exit - leave the program.\r\n"
320 "help - display this help.\r\n"
321 "version - display the version of this program.\r\n"
322 "monitor <type> <tcp port> - display all the input for a given port on\r\n"
323 "       the calling control port.  Only one direction may be monitored\r\n"
324 "       at a time.  The type field may be 'tcp' or 'term' and specifies\r\n"
325 "       whether to monitor data from the TCP port or from the serial port\r\n"
326 "       Note that data monitoring is best effort, if the controller port\r\n"
327 "       cannot keep up the data will be silently dropped.  A controller\r\n"
328 "       may only monitor one thing and a port may only be monitored by\r\n"
329 "       one controller.\r\n"
330 "monitor stop - stop the current monitor.\r\n"
331 "disconnect <tcp port> - disconnect the tcp connection on the port.\r\n"
332 "showport [<tcp port>] - Show information about a port. If no port is\r\n"
333 "       given, all ports are displayed.\r\n"
334 "showshortport [<tcp port>] - Show information about a port in a one-line\r\n"
335 "       format. If no port is given, all ports are displayed.\r\n"
336 "setporttimeout <tcp port> <timeout> - Set the amount of time in seconds\r\n"
337 "       before the port connection will be shut down if no activity\r\n"
338 "       has been seen on the port.\r\n"
339 "setportconfig <tcp port> <config> - Set the port configuration as in\r\n"
340 "       the device configuration in the ser2net.conf file.  Valid options\r\n"
341 "       are: 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, \r\n"
342 "       EVEN, ODD, NONE, 1STOPBIT, 2STOPBITS, 7DATABITS, 8DATABITS, \r\n"
343 "       LOCAL (ignore modem control), [-]RTSCTS, [-]XONXOFF.\r\n"
344 "       Note that these will not change until the port is disconnected\r\n"
345 "       and connected again.\r\n"
346 "setportcontrol <tcp port> <controls>\r\n"
347 "       Dynamically modify the characteristics of the port.  These are\r\n"
348 "       immedaite and won't live between connections.  Valid controls are\r\n"
349 "       DTRHI, DTRLO, RTSHI, and RTSLO.\r\n"
350 "setportenable <tcp port> <enable state> - Sets the port operation state.\r\n"
351 "       Valid states are:\r\n"
352 "         off - The port is shut down\r\n"
353 "         raw - The port is up and all I/O is transferred\r\n"
354 "         rawlp - The port is up and the input is transferred to dev\r\n"
355 "         telnet - The port is up and the telnet negotiation protocol\r\n"
356 "                  runs on the port.\r\n";
357 
358 /* Process a line of input.  This scans for commands, reads any
359    parameters, then calls the actual code to handle the command. */
360 int
process_input_line(controller_info_t * cntlr)361 process_input_line(controller_info_t *cntlr)
362 {
363     char *strtok_data;
364     char *tok;
365     char *str;
366 
367     tok = strtok_r((char *) cntlr->inbuf, " \t", &strtok_data);
368     if (tok == NULL) {
369 	/* Empty line, just ignore it. */
370     } else if (strcmp(tok, "exit") == 0) {
371 	shutdown_controller(cntlr);
372 	return 1; /* We don't want a prompt any more. */
373     } else if (strcmp(tok, "quit") == 0) {
374 	shutdown_controller(cntlr);
375 	return 1; /* We don't want a prompt any more. */
376     } else if (strcmp(tok, "help") == 0) {
377 	controller_outs(cntlr, help_str);
378     } else if (strcmp(tok, "version") == 0) {
379 	str = "ser2net version ";
380 	controller_outs(cntlr, str);
381 	str = VERSION;
382 	controller_outs(cntlr, str);
383 	controller_outs(cntlr, "\r\n");
384     } else if (strcmp(tok, "showport") == 0) {
385 	tok = strtok_r(NULL, " \t", &strtok_data);
386 	start_maint_op();
387 	showports(cntlr, tok);
388 	end_maint_op();
389     } else if (strcmp(tok, "showshortport") == 0) {
390 	tok = strtok_r(NULL, " \t", &strtok_data);
391 	start_maint_op();
392 	showshortports(cntlr, tok);
393 	end_maint_op();
394     } else if (strcmp(tok, "monitor") == 0) {
395 	tok = strtok_r(NULL, " \t", &strtok_data);
396 	if (tok == NULL) {
397 	    char *err = "No monitor type given\r\n";
398 	    controller_outs(cntlr, err);
399 	    goto out;
400 	}
401 	if (strcmp(tok, "stop") == 0) {
402 	    if (cntlr->monitor_port_id != NULL) {
403 		start_maint_op();
404 		data_monitor_stop(cntlr, cntlr->monitor_port_id);
405 		end_maint_op();
406 		cntlr->monitor_port_id = NULL;
407 	    }
408 	} else {
409 	    if (cntlr->monitor_port_id != NULL) {
410 		char *err = "Already monitoring a port\r\n";
411 		controller_outs(cntlr, err);
412 		goto out;
413 	    }
414 
415 	    str = strtok_r(NULL, " \t", &strtok_data);
416 	    if (str == NULL) {
417 		char *err = "No tcp port given\r\n";
418 		controller_outs(cntlr, err);
419 		goto out;
420 	    }
421 	    start_maint_op();
422 	    cntlr->monitor_port_id = data_monitor_start(cntlr, tok, str);
423 	    end_maint_op();
424 	}
425     } else if (strcmp(tok, "disconnect") == 0) {
426 	tok = strtok_r(NULL, " \t", &strtok_data);
427 	if (tok == NULL) {
428 	    char *err = "No port given\r\n";
429 	    controller_outs(cntlr, err);
430 	    goto out;
431 	}
432 	start_maint_op();
433 	disconnect_port(cntlr, tok);
434 	end_maint_op();
435     } else if (strcmp(tok, "setporttimeout") == 0) {
436 	tok = strtok_r(NULL, " \t", &strtok_data);
437 	if (tok == NULL) {
438 	    char *err = "No port given\r\n";
439 	    controller_outs(cntlr, err);
440 	    goto out;
441 	}
442 	str = strtok_r(NULL, " \t", &strtok_data);
443 	if (str == NULL) {
444 	    char *err = "No timeout given\r\n";
445 	    controller_outs(cntlr, err);
446 	    goto out;
447 	}
448 	start_maint_op();
449 	setporttimeout(cntlr, tok, str);
450 	end_maint_op();
451     } else if (strcmp(tok, "setportenable") == 0) {
452 	tok = strtok_r(NULL, " \t", &strtok_data);
453 	if (tok == NULL) {
454 	    char *err = "No port given\r\n";
455 	    controller_outs(cntlr, err);
456 	    goto out;
457 	}
458 	str = strtok_r(NULL, " \t", &strtok_data);
459 	if (str == NULL) {
460 	    char *err = "No timeout given\r\n";
461 	    controller_outs(cntlr, err);
462 	    goto out;
463 	}
464 	start_maint_op();
465 	setportenable(cntlr, tok, str);
466 	end_maint_op();
467     } else if (strcmp(tok, "setportconfig") == 0) {
468 	tok = strtok_r(NULL, " \t", &strtok_data);
469 	if (tok == NULL) {
470 	    char *err = "No port given\r\n";
471 	    controller_outs(cntlr, err);
472 	    goto out;
473 	}
474 
475 	str = strtok_r(NULL, "", &strtok_data);
476 	if (str == NULL) {
477 	    char *err = "No device config\r\n";
478 	    controller_outs(cntlr, err);
479 	    goto out;
480 	}
481 	start_maint_op();
482 	setportdevcfg(cntlr, tok, str);
483 	end_maint_op();
484     } else if (strcmp(tok, "setportcontrol") == 0) {
485 	tok = strtok_r(NULL, " \t", &strtok_data);
486 	if (tok == NULL) {
487 	    char *err = "No port given\r\n";
488 	    controller_outs(cntlr, err);
489 	    goto out;
490 	}
491 
492 	str = strtok_r(NULL, "", &strtok_data);
493 	if (str == NULL) {
494 	    char *err = "No device controls\r\n";
495 	    controller_outs(cntlr, err);
496 	    goto out;
497 	}
498 	start_maint_op();
499 	setportcontrol(cntlr, tok, str);
500 	end_maint_op();
501     } else {
502 	char *err = "Unknown command: ";
503 	controller_outs(cntlr, err);
504 	controller_outs(cntlr, tok);
505 	controller_outs(cntlr, "\r\n");
506     }
507 
508 out:
509     controller_outs(cntlr, prompt);
510     return 0;
511 }
512 
513 /* Removes one or more characters starting at pos and going backwards.
514    So, for instance, if inbuf holds "abcde", pos points to d, and
515    count is 2, the new inbuf will be "abe".  This is used for
516    backspacing and for removing telnet command characters. */
517 static int
remove_chars(controller_info_t * cntlr,int pos,int count)518 remove_chars(controller_info_t *cntlr, int pos, int count) {
519     int j;
520 
521     for (j = pos-count + 1; j < (cntlr->inbuf_count - count); j++) {
522 	cntlr->inbuf[j] = cntlr->inbuf[j + count];
523     }
524     cntlr->inbuf_count -= count;
525     pos -= count;
526 
527     return pos;
528 }
529 
530 /* Data is ready to read on the TCP port. */
531 static void
handle_tcp_fd_read(int fd,void * data)532 handle_tcp_fd_read(int fd, void *data)
533 {
534     controller_info_t *cntlr = (controller_info_t *) data;
535     int read_count;
536     int read_start;
537     int i;
538 
539     LOCK(cntlr->lock);
540     if (cntlr->in_shutdown)
541 	goto out_unlock;
542 
543     if (cntlr->inbuf_count == INBUF_SIZE) {
544         char *err = "Input line too long\r\n";
545 	controller_outs(cntlr, err);
546 	cntlr->inbuf_count = 0;
547 	goto out_unlock;
548     }
549 
550     read_count = read(fd,
551 		      &(cntlr->inbuf[cntlr->inbuf_count]),
552 		      INBUF_SIZE - cntlr->inbuf_count);
553 
554     if (read_count < 0) {
555 	if (errno == EINTR) {
556 	    /* EINTR means we were interrupted, just retry by returning. */
557 	    goto out_unlock;
558 	}
559 
560 	if (errno == EAGAIN) {
561 	    /* EAGAIN, is due to O_NONBLOCK, just ignore it. */
562 	    goto out_unlock;
563 	}
564 
565 	/* Got an error on the read, shut down the port. */
566 	syslog(LOG_ERR, "read error for controller port: %m");
567 	shutdown_controller(cntlr); /* Releases the lock */
568 	goto out;
569     } else if (read_count == 0) {
570 	/* The other end closed the port, shut it down. */
571 	shutdown_controller(cntlr); /* Releases the lock */
572 	goto out;
573     }
574     read_start = cntlr->inbuf_count;
575     read_count = process_telnet_data
576 	(cntlr->inbuf + read_start, read_count, &cntlr->tn_data);
577     if (cntlr->tn_data.error) {
578 	shutdown_controller(cntlr); /* Releases the lock */
579 	goto out;
580     }
581     cntlr->inbuf_count += read_count;
582 
583     for (i = read_start; i < cntlr->inbuf_count; i++) {
584 	if (cntlr->inbuf[i] == 0x0) {
585 	    /* Ignore nulls. */
586 	    i = remove_chars(cntlr, i, 1);
587 	} else if (cntlr->inbuf[i] == '\n') {
588 	    /* Ignore newlines. */
589 	    i = remove_chars(cntlr, i, 1);
590 	} else if ((cntlr->inbuf[i] == '\b') || (cntlr->inbuf[i] == 0x7f)) {
591 	    /* Got a backspace. */
592 
593 	    if (i == 0) {
594 		/* We ignore backspaces at the beginning of the line. */
595 		i = remove_chars(cntlr, i, 1);
596 	    } else {
597 		i = remove_chars(cntlr, i, 2);
598 		controller_outs(cntlr, "\b \b");
599 	    }
600 	} else if (cntlr->inbuf[i] == '\r') {
601 	    /* We got a newline, process the command. */
602 	    int j;
603 
604 	    controller_outs(cntlr, "\r\n");
605 
606 	    cntlr->inbuf[i] ='\0';
607 	    if (process_input_line(cntlr))
608 		goto out; /* Controller was shut down. */
609 
610 	    /* Now copy any leftover data to the beginning of the buffer. */
611 	    /* Don't use memcpy or strcpy because the memory might
612                overlap */
613 	    i++;
614 	    cntlr->inbuf_count -= i;
615 	    for (j = 0; j < cntlr->inbuf_count; i++, j++) {
616 		cntlr->inbuf[j] = cntlr->inbuf[i];
617 	    }
618 	    i = -1;
619 	} else {
620 	    /* It's a normal character, just echo it. */
621 	    controller_output(cntlr, (char *) &(cntlr->inbuf[i]), 1);
622 	}
623     }
624  out_unlock:
625     UNLOCK(cntlr->lock);
626  out:
627     return;
628 }
629 
630 /* The TCP port has room to write some data.  This is only activated
631    if a write fails to complete, it is deactivated as soon as writing
632    is available again. */
633 static void
handle_tcp_fd_write(int fd,void * data)634 handle_tcp_fd_write(int fd, void *data)
635 {
636     controller_info_t *cntlr = (controller_info_t *) data;
637     telnet_data_t *td;
638     int write_count;
639 
640     LOCK(cntlr->lock);
641     if (cntlr->in_shutdown)
642 	goto out;
643 
644     td = &cntlr->tn_data;
645     if (buffer_cursize(&td->out_telnet_cmd) > 0) {
646 	int buferr, reterr;
647 
648 	reterr = buffer_write(cntlr->tcpfd, &td->out_telnet_cmd, &buferr);
649 	if (reterr == -1) {
650 	    if (buferr == EPIPE) {
651 		goto out_fail;
652 	    } else {
653 		/* Some other bad error. */
654 		syslog(LOG_ERR, "The tcp write for controller had error: %m");
655 		goto out_fail;
656 	    }
657 	}
658 	if (buffer_cursize(&td->out_telnet_cmd) > 0)
659 	    /* Still telnet data left, don't send regular data */
660 	    goto out;
661     }
662 
663     write_count = write(cntlr->tcpfd,
664 			&(cntlr->outbuf[cntlr->outbuf_pos]),
665 			cntlr->outbuf_count);
666     if (write_count == -1) {
667 	if (errno == EAGAIN) {
668 	    /* This again was due to O_NONBLOCK, just ignore it. */
669 	} else if (errno == EPIPE) {
670 	    goto out_fail;
671 	} else {
672 	    /* Some other bad error. */
673 	    syslog(LOG_ERR, "The tcp write for controller had error: %m");
674 	    goto out_fail;
675 	}
676     } else {
677 	cntlr->outbuf_count -= write_count;
678 	if (cntlr->outbuf_count != 0) {
679 	    /* We didn't write all the data, continue writing. */
680 	    cntlr->outbuf_pos += write_count;
681 	} else {
682 	    /* We are done writing, turn the reader back on. */
683 	    free(cntlr->outbuf);
684 	    cntlr->outbuf = NULL;
685 	    sel_set_fd_read_handler(ser2net_sel, cntlr->tcpfd,
686 				    SEL_FD_HANDLER_ENABLED);
687 	    sel_set_fd_write_handler(ser2net_sel, cntlr->tcpfd,
688 				     SEL_FD_HANDLER_DISABLED);
689 	}
690     }
691  out:
692     UNLOCK(cntlr->lock);
693     return;
694 
695  out_fail:
696     shutdown_controller(cntlr); /* Releases the lock */
697 }
698 
699 /* Handle an exception from the TCP port. */
700 static void
handle_tcp_fd_except(int fd,void * data)701 handle_tcp_fd_except(int fd, void *data)
702 {
703     controller_info_t *cntlr = (controller_info_t *) data;
704 
705     LOCK(cntlr->lock);
706     if (cntlr->in_shutdown) {
707 	UNLOCK(cntlr->lock);
708 	return;
709     }
710     syslog(LOG_ERR, "Select exception for controller port");
711     shutdown_controller(cntlr); /* Releases the lock */
712 }
713 
714 static void
controller_fd_cleared(int fd,void * cb_data)715 controller_fd_cleared(int fd, void *cb_data)
716 {
717     controller_info_t *cntlr = cb_data;
718 
719     shutdown_controller2(cntlr);
720 }
721 
722 /* A connection request has come in for the control port. */
723 static void
handle_accept_port_read(int fd,void * data)724 handle_accept_port_read(int fd, void *data)
725 {
726     controller_info_t *cntlr;
727     socklen_t         len;
728     char              *err = NULL;
729     int               optval;
730 
731     LOCK(cntlr_lock);
732     if (num_controller_ports >= max_controller_ports) {
733 	err = "Too many controller ports\r\n";
734 	goto errout2;
735     } else {
736 	cntlr = malloc(sizeof(*cntlr));
737 	if (cntlr == NULL) {
738 	    err = "Could not allocate controller port\r\n";
739 	    goto errout2;
740 	}
741 	memset(cntlr, 0, sizeof(*cntlr));
742     }
743 
744     /* From here on, errors must go to errout. */
745 
746     INIT_LOCK(cntlr->lock);
747 
748     len = sizeof(cntlr->remote);
749     cntlr->tcpfd = accept(fd, (struct sockaddr *) &(cntlr->remote), &len);
750     if (cntlr->tcpfd == -1) {
751 	if (errno != EAGAIN && errno != EWOULDBLOCK)
752 	    syslog(LOG_ERR, "Could not accept on controller port: %m");
753 	goto errout;
754     }
755 
756 #ifdef HAVE_TCPD_H
757     {
758 	struct request_info req;
759 
760 	request_init(&req, RQ_DAEMON, progname, RQ_FILE, cntlr->tcpfd, NULL);
761 	fromhost(&req);
762 
763 	if (!hosts_access(&req)) {
764 	    char *err = "Access denied\r\n";
765 	    write(cntlr->tcpfd, err, strlen(err));
766 	    close(cntlr->tcpfd);
767 	    goto errout;
768 	}
769     }
770 #endif /* HAVE_TCPD_H */
771 
772     if (fcntl(cntlr->tcpfd, F_SETFL, O_NONBLOCK) == -1) {
773 	close(cntlr->tcpfd);
774 	syslog(LOG_ERR, "Could not fcntl the tcp port: %m");
775 	goto errout;
776     }
777 
778     optval = 1;
779     if (setsockopt(cntlr->tcpfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&optval,
780 		   sizeof(optval)) == -1) {
781 	close(cntlr->tcpfd);
782 	syslog(LOG_ERR, "Could not enable SO_KEEPALIVE on the tcp port: %m");
783 	goto errout;
784     }
785 
786     cntlr->inbuf_count = 0;
787     cntlr->outbuf = NULL;
788     cntlr->monitor_port_id = NULL;
789 
790     sel_set_fd_handlers(ser2net_sel,
791 			cntlr->tcpfd,
792 			cntlr,
793 			handle_tcp_fd_read,
794 			handle_tcp_fd_write,
795 			handle_tcp_fd_except,
796 			controller_fd_cleared);
797 
798     cntlr->next = controllers;
799     controllers = cntlr;
800 
801     /* Send the telnet negotiation string.  We do this by
802        putting the data in the dev to tcp buffer and turning
803        the tcp write selector on. */
804 
805     telnet_init(&cntlr->tn_data, cntlr, telnet_output_ready,
806 		telnet_cmd_handler,
807 		telnet_cmds,
808 		telnet_init_seq, sizeof(telnet_init_seq));
809     controller_outs(cntlr, prompt);
810 
811     num_controller_ports++;
812 
813     UNLOCK(cntlr_lock);
814     return;
815 
816 errout:
817     UNLOCK(cntlr_lock);
818     free(cntlr);
819     return;
820 
821 errout2:
822     UNLOCK(cntlr_lock);
823     {
824 	/* We have a problem so refuse this one. */
825 	struct sockaddr_storage dummy_sockaddr;
826 	socklen_t len = sizeof(dummy_sockaddr);
827 	int new_fd = accept(fd, (struct sockaddr *) &dummy_sockaddr, &len);
828 
829 	if (new_fd != -1) {
830 	    write_ignore_fail(new_fd, err, strlen(err));
831 	    close(new_fd);
832 	}
833     }
834 }
835 
836 static void
controller_accept_fd_cleared(int fd,void * cb_data)837 controller_accept_fd_cleared(int fd, void *cb_data)
838 {
839     wake_waiter(accept_waiter);
840 }
841 
842 /* Set up the controller port to accept connections. */
843 int
controller_init(char * controller_port)844 controller_init(char *controller_port)
845 {
846     int rv;
847     bool is_port_set;
848 
849     if (!controller_shutdown_waiter) {
850 	controller_shutdown_waiter = alloc_waiter();
851 	if (!controller_shutdown_waiter)
852 	    return ENOMEM;
853     }
854 
855     rv = scan_network_port(controller_port, &cntrl_ai, NULL, &is_port_set);
856     if (rv) {
857 	if (rv == EINVAL)
858 	    return CONTROLLER_INVALID_TCP_SPEC;
859 	else if (rv == ENOMEM)
860 	    return CONTROLLER_OUT_OF_MEMORY;
861 	else
862 	    return -1;
863     }
864     if (!is_port_set)
865 	return CONTROLLER_INVALID_TCP_SPEC;
866 
867     if (!accept_waiter) {
868 	accept_waiter = alloc_waiter();
869 	if (!accept_waiter) {
870 	    syslog(LOG_ERR, "Unable to allocate controller accept waiter");
871 	    return CONTROLLER_CANT_OPEN_PORT;
872 	}
873     }
874 
875     acceptfds = open_socket(cntrl_ai, handle_accept_port_read, NULL, NULL,
876 			    &nr_acceptfds, controller_accept_fd_cleared);
877     if (acceptfds == NULL) {
878 	freeaddrinfo(cntrl_ai);
879 	syslog(LOG_ERR, "Unable to create TCP socket: %m");
880 	return CONTROLLER_CANT_OPEN_PORT;
881     }
882 
883     return 0;
884 }
885 
886 void
controller_shutdown(void)887 controller_shutdown(void)
888 {
889     unsigned int i;
890 
891     if (acceptfds == NULL)
892 	return;
893     for (i = 0; i < nr_acceptfds; i++) {
894 	sel_clear_fd_handlers(ser2net_sel, acceptfds[i].fd);
895 	wait_for_waiter(accept_waiter);
896 	close(acceptfds[i].fd);
897     }
898     free(acceptfds);
899     freeaddrinfo(cntrl_ai);
900     acceptfds = NULL;
901 }
902 
903 static void
shutdown_controller_done(void * cb_data)904 shutdown_controller_done(void *cb_data)
905 {
906     waiter_t *waiter = cb_data;
907 
908     wake_waiter(waiter);
909 }
910 
911 void
free_controllers(void)912 free_controllers(void)
913 {
914     controller_shutdown();
915     while (controllers) {
916 	controllers->shutdown_complete = shutdown_controller_done;
917 	controllers->shutdown_complete_cb_data = controller_shutdown_waiter;
918 	LOCK(controllers->lock);
919 	shutdown_controller(controllers); /* Releases the lock. */
920 	wait_for_waiter(controller_shutdown_waiter);
921     }
922     if (controller_shutdown_waiter)
923 	free_waiter(controller_shutdown_waiter);
924     if (accept_waiter)
925 	free_waiter(accept_waiter);
926 }
927