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