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 /* This file holds the code that reads the configuration file and
21    calls the code in dataxfer to actually create all the ports in the
22    configuration file. */
23 
24 #include <stdlib.h>
25 #include <stdbool.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <stdio.h>
29 #include <syslog.h>
30 #include <stdarg.h>
31 #include <limits.h>
32 
33 #include "dataxfer.h"
34 #include "readconfig.h"
35 #include "utils.h"
36 #include "telnet.h"
37 #include "led.h"
38 
39 #ifdef HAVE_OPENIPMI
40 #include <OpenIPMI/ipmi_conn.h>
41 #include <OpenIPMI/ipmi_sol.h>
42 #endif
43 
44 #define PORT_BUFSIZE	64	/* Default data transfer buffer size */
45 
46 extern char *config_port;
47 
48 static int config_num = 0;
49 
50 static int lineno = 0;
51 
52 struct longstr_s
53 {
54     char *name;
55     char *str;
56     unsigned int length;
57     enum str_type type;
58     struct longstr_s *next;
59 };
60 
61 /* All the strings in the system. */
62 struct longstr_s *longstrs = NULL;
63 
isoctdigit(char c)64 static int isoctdigit(char c)
65 {
66     return ((c >= '0') && (c <= '7'));
67 }
68 
69 /* Assumes the value is pre-checked */
hexchar_to_val(char c)70 static int hexchar_to_val(char c)
71 {
72     if ((c >= '0') && (c <= '9'))
73 	return c - '0';
74     if (isupper(c))
75 	return c - 'A' + 10;
76     return c - 'a' + 10;
77 }
78 
79 /*
80  * Convert \004 and other ESC sequences in place, inspired from
81  * http://stackoverflow.com/questions/17015970/how-does-c-compiler-convert-escape-sequence-to-actual-bytes
82  */
83 static void
translateescapes(char * string,unsigned int * outlen,char ** err,char ** errpos)84 translateescapes(char *string, unsigned int *outlen,
85 		 char **err, char **errpos)
86 {
87     char *ip = string, *op = string;
88     unsigned int cleft = strlen(string);
89     unsigned int iplen;
90 
91     *err = NULL;
92     while (*ip) {
93 	cleft--;
94 	if (*ip != '\\') {
95 	    *op++ = *ip++;
96 	    continue;
97 	}
98 
99 	if (cleft == 0)
100 	    goto out_str_in_bslash;
101 
102 	iplen = 2;
103 	switch (ip[1]) {
104 	case '\\': *op = '\\'; break;
105 	case 'r': *op = '\r'; break;
106 	case 'n': *op = '\n'; break;
107 	case 't': *op = '\t'; break;
108 	case 'v': *op = '\v'; break;
109 	case 'a': *op = '\a'; break;
110 	case '0': case '1': case '2': case '3':
111 	case '4': case '5': case '6': case '7':
112 	    if (cleft < 3)
113 		goto out_str_in_bslash;
114 	    if (!isoctdigit(ip[2]) || !isoctdigit(ip[3])) {
115 		*err = "Invalid octal sequence";
116 		*errpos = ip - 1;
117 	    }
118 	    iplen = 4;
119 	    *op = (ip[1] -'0') * 64 + (ip[2] - '0') * 8 + (ip[3] - '0');
120 	    break;
121 	case 'x':
122 	    if (cleft < 3)
123 		goto out_str_in_bslash;
124 	    if (!isxdigit(ip[2]) || !isxdigit(ip[3])) {
125 		*err = "Invalid octal sequence";
126 		*errpos = ip - 1;
127 	    }
128 	    iplen = 4;
129 	    *op = 16 * hexchar_to_val(ip[2]) + hexchar_to_val(ip[3]);
130 	    break;
131 	default:
132 	    *err = "Unknown escape sequence";
133 	    *errpos = ip - 1;
134 	    return;
135 	}
136 
137 	ip += iplen;
138 	cleft -= iplen;
139 	op++;
140     }
141 
142     *outlen = op - string;
143     *op = '\0';
144     return;
145 
146  out_str_in_bslash:
147     *err = "end of string right after a \\";
148     *errpos = "";
149 }
150 
151 /* Parse the incoming string, it may be on multiple lines. */
152 static void
handle_longstr(const char * name,const char * line,enum str_type type)153 handle_longstr(const char *name, const char *line, enum str_type type)
154 {
155     struct longstr_s *longstr;
156 
157     /* If the user gave an empty string, we get a NULL. */
158     if (!line)
159 	line = "";
160 
161     longstr = malloc(sizeof(*longstr));
162     if (!longstr) {
163 	syslog(LOG_ERR, "Out of memory handling string on %d", lineno);
164 	return;
165     }
166     memset(longstr, 0, sizeof(*longstr));
167     longstr->type = type;
168 
169     longstr->name = strdup(name);
170     if (!longstr->name) {
171 	syslog(LOG_ERR, "Out of memory handling longstr on %d", lineno);
172 	goto out_err;
173     }
174 
175     longstr->str = strdup(line);
176     if (!longstr->str) {
177 	syslog(LOG_ERR, "Out of memory handling longstr on %d", lineno);
178 	goto out_err;
179     }
180 
181     longstr->length = strlen(line);
182 
183     if (longstr->type == CLOSEON) {
184 	char *err = NULL, *errpos = NULL;
185 
186 	translateescapes(longstr->str, &longstr->length,
187 			 &err, &errpos);
188 	if (err) {
189 	    syslog(LOG_ERR, "%s (starting at %s) on line %d", err, errpos,
190 		   lineno);
191 	    goto out_err;
192 	}
193     }
194 
195     longstr->next = longstrs;
196     longstrs = longstr;
197     return;
198 
199  out_err:
200     if (longstr->name)
201 	free(longstr->name);
202     if (longstr->str)
203 	free(longstr->str);
204     free(longstr);
205     return;
206 }
207 
208 char *
find_str(const char * name,enum str_type * type,unsigned int * len)209 find_str(const char *name, enum str_type *type, unsigned int *len)
210 {
211     struct longstr_s *longstr = longstrs;
212 
213     while (longstr) {
214 	if (strcmp(name, longstr->name) == 0) {
215 	    char *rv;
216 
217 	    /* Note that longstrs can contain \0, so be careful in handling */
218 	    if (type)
219 		*type = longstr->type;
220 	    if (len)
221 		*len = longstr->length;
222 	    rv = malloc(longstr->length + 1);
223 	    if (!rv)
224 		return NULL;
225 	    memcpy(rv, longstr->str, longstr->length + 1);
226 	    return rv;
227 	}
228 	longstr = longstr->next;
229     }
230     return NULL;
231 }
232 
233 void
free_longstrs(void)234 free_longstrs(void)
235 {
236 
237     while (longstrs) {
238 	struct longstr_s *longstr = longstrs;
239 
240 	longstrs = longstrs->next;
241 	free(longstr->name);
242 	free(longstr->str);
243 	free(longstr);
244     }
245 }
246 
247 struct tracefile_s
248 {
249     char *name;
250     char *str;
251     struct tracefile_s *next;
252 };
253 
254 #if HAVE_DECL_TIOCSRS485
255 struct rs485conf_s
256 {
257     char *name;
258     struct serial_rs485 conf;
259     struct rs485conf_s *next;
260 };
261 #endif
262 
263 /* All the tracefiles in the system. */
264 struct tracefile_s *tracefiles = NULL;
265 
266 static void
handle_tracefile(char * name,char * fname)267 handle_tracefile(char *name, char *fname)
268 {
269     struct tracefile_s *new_tracefile;
270 
271     new_tracefile = malloc(sizeof(*new_tracefile));
272     if (!new_tracefile) {
273 	syslog(LOG_ERR, "Out of memory handling tracefile on %d", lineno);
274 	return;
275     }
276 
277     new_tracefile->name = strdup(name);
278     if (!new_tracefile->name) {
279 	syslog(LOG_ERR, "Out of memory handling tracefile on %d", lineno);
280 	free(new_tracefile);
281 	return;
282     }
283 
284     new_tracefile->str = strdup(fname);
285     if (!new_tracefile->str) {
286 	syslog(LOG_ERR, "Out of memory handling tracefile on %d", lineno);
287 	free(new_tracefile->name);
288 	free(new_tracefile);
289 	return;
290     }
291 
292     new_tracefile->next = tracefiles;
293     tracefiles = new_tracefile;
294 }
295 
296 char *
find_tracefile(const char * name)297 find_tracefile(const char *name)
298 {
299     struct tracefile_s *tracefile = tracefiles;
300 
301     while (tracefile) {
302 	if (strcmp(name, tracefile->name) == 0)
303 	    return strdup(tracefile->str);
304 	tracefile = tracefile->next;
305     }
306     syslog(LOG_ERR, "Tracefile %s not found, it will be ignored", name);
307     return NULL;
308 }
309 
310 void
free_tracefiles(void)311 free_tracefiles(void)
312 {
313     while (tracefiles) {
314 	struct tracefile_s *tracefile = tracefiles;
315 
316 	tracefiles = tracefiles->next;
317 	free(tracefile->name);
318 	free(tracefile->str);
319 	free(tracefile);
320     }
321 }
322 
323 #if HAVE_DECL_TIOCSRS485
324 /* All the RS485 configs in the system. */
325 struct rs485conf_s *rs485confs = NULL;
326 
327 static void
handle_rs485conf(char * name,char * str)328 handle_rs485conf(char *name, char *str)
329 {
330     struct rs485conf_s *new_rs485conf;
331     uint8_t rts_on_send, rx_during_tx;
332 
333     new_rs485conf = malloc(sizeof(*new_rs485conf));
334     if (!new_rs485conf) {
335 	syslog(LOG_ERR, "Out of memory handling rs485 config on %d", lineno);
336 	return;
337     }
338     memset(new_rs485conf, 0, sizeof(*new_rs485conf));
339 
340     new_rs485conf->name = strdup(name);
341     if (!new_rs485conf->name) {
342 	syslog(LOG_ERR, "Out of memory handling rs485 config on %d", lineno);
343 	goto out_err;
344     }
345 
346     if (sscanf(str, "%10u:%10u:%1hhu:%1hhu",
347                &new_rs485conf->conf.delay_rts_before_send,
348                &new_rs485conf->conf.delay_rts_after_send,
349                &rts_on_send,
350                &rx_during_tx) != 4) {
351 	syslog(LOG_ERR, "Couldn't parse RS485 config on %d", lineno);
352 	goto out_err;
353     }
354 
355     /* check, if flags have values 0 or 1 */
356     if (rts_on_send > 1) {
357 	syslog(LOG_ERR, "RTS_ON_SEND parameter can be 0 or 1 on %d", lineno);
358 	goto out_err;
359     }
360 
361     if (rx_during_tx > 1) {
362 	syslog(LOG_ERR, "RX_DURING_TX parameter can be 0 or 1 on %d", lineno);
363 	goto out_err;
364     }
365 
366     new_rs485conf->conf.flags = SER_RS485_ENABLED;
367 
368     if (rts_on_send) {
369         new_rs485conf->conf.flags |= SER_RS485_RTS_ON_SEND;
370     } else {
371         new_rs485conf->conf.flags |= SER_RS485_RTS_AFTER_SEND;
372     }
373 
374     if (rx_during_tx) {
375         new_rs485conf->conf.flags |= SER_RS485_RX_DURING_TX;
376     }
377 
378     new_rs485conf->next = rs485confs;
379     rs485confs = new_rs485conf;
380     return;
381 
382  out_err:
383     if (new_rs485conf->name)
384 	free(new_rs485conf->name);
385     free(new_rs485conf);
386 }
387 
388 struct serial_rs485 *
find_rs485conf(const char * name)389 find_rs485conf(const char *name)
390 {
391     struct rs485conf_s *new_rs485conf = rs485confs;
392 
393     while (new_rs485conf) {
394         if (strcmp(name, new_rs485conf->name) == 0)
395             return &new_rs485conf->conf;
396         new_rs485conf = new_rs485conf->next;
397     }
398     syslog(LOG_ERR, "RS485 configuration %s not found, it will be ignored", name);
399     return NULL;
400 }
401 
402 void
free_rs485confs(void)403 free_rs485confs(void)
404 {
405     while (rs485confs) {
406 	struct rs485conf_s *rs485conf = rs485confs;
407 
408         rs485confs = rs485confs->next;
409         free(rs485conf->name);
410         free(rs485conf);
411     }
412 }
413 #else
free_rs485confs(void)414 void free_rs485confs(void) { }
415 #endif
416 
417 static int
startswith(char * str,const char * test,char ** strtok_data)418 startswith(char *str, const char *test, char **strtok_data)
419 {
420     int len = strlen(test);
421 
422     if ((strncmp(str, test, len) == 0) && (str[len] == ':')) {
423 	strtok_r(str, ":", strtok_data);
424 	return 1;
425     }
426     return 0;
427 }
428 
429 static int
syslog_eprint(struct absout * e,const char * str,...)430 syslog_eprint(struct absout *e, const char *str, ...)
431 {
432     va_list ap;
433     char buf[1024];
434 
435     va_start(ap, str);
436     vsnprintf(buf, sizeof(buf), str, ap);
437     va_end(ap);
438     syslog(LOG_ERR, "%s on line %d", buf, *((int *) e->data));
439     return 0;
440 }
441 
442 static struct absout syslog_eout = {
443     .out = syslog_eprint,
444     .data = &lineno
445 };
446 
447 struct enum_val
448 {
449     char *str;
450     int val;
451 };
452 
453 static int
lookup_enum(struct enum_val * enums,const char * str,int len)454 lookup_enum(struct enum_val *enums, const char *str, int len)
455 {
456     while (enums->str != NULL) {
457 	if (len == -1 && strcmp(enums->str, str) == 0)
458 	    return enums->val;
459 	if (strlen(enums->str) == len && strncmp(enums->str, str, len) == 0)
460 	    return enums->val;
461 	enums++;
462     }
463     return -1;
464 }
465 
466 static struct enum_val speed_enums[] = {
467     { "300",	300 },
468     { "600",	600 },
469     { "1200",	1200 },
470     { "2400",	2400 },
471     { "4800",	4800 },
472     { "9600",	9600 },
473     { "19200",	19200 },
474     { "38400",	38400 },
475     { "57600",	57600 },
476     { "115200",	115200 },
477     { "230400",	230400 },
478     { "460800",	460800 },
479     { "500000",	500000 },
480     { "576000",	576000 },
481     { "921600",	921600 },
482     { "1000000",1000000 },
483     { "1152000",1152000 },
484     { "1500000",1500000 },
485     { "2000000",2000000 },
486     { "2500000",2500000 },
487     { "3000000",3000000 },
488     { "3500000",3500000 },
489     { "4000000",4000000 },
490     { NULL },
491 };
492 
493 int
speedstr_to_speed(const char * speed)494 speedstr_to_speed(const char *speed)
495 {
496     return lookup_enum(speed_enums, speed, -1);
497 }
498 
499 struct enum_val parity_enums[] = {
500     { "NONE", PARITY_NONE },
501     { "EVEN", PARITY_EVEN },
502     { "ODD", PARITY_ODD },
503     { "none", PARITY_NONE },
504     { "even", PARITY_EVEN },
505     { "odd", PARITY_ODD },
506     { "MARK", PARITY_MARK },
507     { "SPACE", PARITY_SPACE },
508     { "mark", PARITY_MARK },
509     { "space", PARITY_SPACE },
510     { NULL }
511 };
512 
513 #ifdef HAVE_OPENIPMI
514 struct enum_val shared_serial_alert_enums[] = {
515     { "fail",		ipmi_sol_serial_alerts_fail },
516     { "deferred", 	ipmi_sol_serial_alerts_deferred },
517     { "succeed", 	ipmi_sol_serial_alerts_succeed },
518     { NULL }
519 };
520 #endif
521 
522 enum parity_vals
lookup_parity(const char * str)523 lookup_parity(const char *str)
524 {
525     return lookup_enum(parity_enums, str, -1);
526 }
527 
528 enum default_type { DEFAULT_INT, DEFAULT_BOOL, DEFAULT_ENUM, DEFAULT_STR };
529 
530 struct default_data
531 {
532     const char *name;
533     enum default_type type;
534     int min;
535     int max;
536     struct enum_val *enums;
537     union {
538 	int intval;
539 	char *strval;
540     } val;
541     union {
542 	int intval;
543 	const char *strval;
544     } def;
545     const char *altname;
546 };
547 
548 struct default_data defaults[] = {
549     /* serial device only */
550     { "stopbits",	DEFAULT_INT,	.min = 1, .max = 2, .def.intval = 1 },
551     { "databits",	DEFAULT_INT,	.min = 5, .max = 8, .def.intval = 8 },
552     { "parity",		DEFAULT_ENUM,	.enums = parity_enums,
553 					.def.intval = PARITY_NONE },
554     { "xonxoff",	DEFAULT_BOOL,	.def.intval = 0 },
555     { "rtscts",		DEFAULT_BOOL,	.def.intval = 0 },
556     { "local",		DEFAULT_BOOL,	.def.intval = 0 },
557     { "hangup_when_done", DEFAULT_BOOL,	.def.intval = 0 },
558     /* Serial port and SOL */
559     { "speed",		DEFAULT_ENUM,	.enums = speed_enums,
560 					.def.intval = 9600 },
561     { "nobreak",	DEFAULT_BOOL,	.def.intval = 0 },
562     /* All port types */
563     { "remctl",		DEFAULT_BOOL,	.def.intval = 0 },
564     { "telnet_brk_on_sync",DEFAULT_BOOL,.def.intval = 0 },
565     { "kickolduser",	DEFAULT_BOOL,	.def.intval = 0 },
566     { "chardelay",	DEFAULT_BOOL,	.def.intval = 1 },
567     { "chardelay-scale",DEFAULT_INT,	.min = 1, .max = 1000,
568 					.def.intval = 20 },
569     { "chardelay-min",	DEFAULT_INT,	.min = 1, .max = 100000,
570 					.def.intval = 1000 },
571     { "chardelay-max",	DEFAULT_INT,	.min = 1, .max = 1000000,
572 					.def.intval = 20000 },
573     { "dev-to-net-bufsize", DEFAULT_INT,.min = 1, .max = 65536,
574 					.def.intval = PORT_BUFSIZE,
575 					.altname = "dev-to-tcp-bufsize" },
576     { "net-to-dev-bufsize", DEFAULT_INT,.min = 1, .max = 65536,
577 					.def.intval = PORT_BUFSIZE,
578 					.altname = "tcp-to-dev-bufsize" },
579     { "max-connections", DEFAULT_INT,	.min=1, .max=65536,
580 					.def.intval = 1 },
581 #ifdef HAVE_OPENIPMI
582     /* SOL only */
583     { "authenticated",	DEFAULT_BOOL,	.def.intval = 1 },
584     { "encrypted",	DEFAULT_BOOL,	.def.intval = 1 },
585     { "ack-timeout",	DEFAULT_INT,	.min = 1, .max = INT_MAX,
586 					.def.intval = 1000000 },
587     { "ack-retries",	DEFAULT_INT,	.min = 1, .max = INT_MAX,
588 					.def.intval = 10 },
589     { "shared-serial-alert", DEFAULT_ENUM, .enums = shared_serial_alert_enums,
590 				   .def.intval = ipmi_sol_serial_alerts_fail },
591     { "deassert_CTS_DCD_DSR_on_connect", DEFAULT_BOOL, .def.intval = 0 },
592 #endif
593     { "remaddr",	DEFAULT_STR,	.def.strval = "" },
594     { NULL }
595 };
596 
597 
598 static void
setup_defaults(void)599 setup_defaults(void)
600 {
601     int i;
602 
603     for (i = 0; defaults[i].name; i++) {
604 	if (defaults[i].type == DEFAULT_STR) {
605 	    if (defaults[i].val.strval) {
606 		free(defaults[i].val.strval);
607 		defaults[i].val.strval = NULL;
608 	    }
609 	} else {
610 	    defaults[i].val.intval = defaults[i].def.intval;
611 	}
612     }
613 }
614 
cmp_default_name(struct default_data * def,const char * name)615 static int cmp_default_name(struct default_data *def, const char *name)
616 {
617     return (strcmp(def->name, name) == 0 ||
618 	    (def->altname && strcmp(def->altname, name) == 0));
619 }
620 
621 int
find_default_int(const char * name)622 find_default_int(const char *name)
623 {
624     int i;
625 
626     for (i = 0; defaults[i].name; i++) {
627 	if (cmp_default_name(&defaults[i], name) &&
628 			defaults[i].type != DEFAULT_STR)
629 	    return defaults[i].val.intval;
630     }
631     abort();
632 }
633 
634 char *
find_default_str(const char * name)635 find_default_str(const char *name)
636 {
637     int i;
638 
639     for (i = 0; defaults[i].name; i++) {
640 	if (cmp_default_name(&defaults[i], name) &&
641 			defaults[i].type == DEFAULT_STR) {
642 	    const char *s = defaults[i].val.strval;
643 	    if (!s)
644 		s = defaults[i].def.strval;
645 	    return strdup(s);
646 	}
647     }
648     abort();
649 }
650 
651 static void
handle_new_default(const char * name,const char * str)652 handle_new_default(const char *name, const char *str)
653 {
654     int i, val, len;
655     char *end, *sval;
656     const char *s;
657 
658     while (isspace(*str))
659 	str++;
660     s = str;
661     while (!isspace(*s) && *s != '\0')
662 	s++;
663     if (s == str) {
664 	syslog(LOG_ERR, "No default value on %d", lineno);
665 	return;
666     }
667     len = s - str;
668 
669     for (i = 0; defaults[i].name; i++) {
670 	if (!cmp_default_name(&defaults[i], name))
671 	    continue;
672 
673 	switch (defaults[i].type) {
674 	case DEFAULT_INT:
675 	    val = strtoul(str, &end, 10);
676 	    if (end != s) {
677 		syslog(LOG_ERR, "Invalid integer value on %d", lineno);
678 		return;
679 	    }
680 	    if (val < defaults[i].min || val > defaults[i].max) {
681 		syslog(LOG_ERR, "Integer value out of range on %d, "
682 		       "min is %d, max is %d",
683 		       lineno, defaults[i].min, defaults[i].max);
684 		return;
685 	    }
686 	    defaults[i].val.intval = val;
687 	    break;
688 
689 	case DEFAULT_BOOL:
690 	    val = strtoul(str, &end, 10);
691 	    if (end == s)
692 		defaults[i].val.intval = !!val;
693 	    else if (len == 4 && ((strncmp(str, "true", 4) == 0) ||
694 				  (strncmp(str, "TRUE", 4) == 0)))
695 		defaults[i].val.intval = 1;
696 	    else if (len == 5 && ((strncmp(str, "false", 5) == 0) ||
697 				  (strncmp(str, "FALSE", 5) == 0)))
698 		defaults[i].val.intval = 0;
699 	    else
700 		syslog(LOG_ERR, "Invalid integer value on %d", lineno);
701 	    break;
702 
703 	case DEFAULT_ENUM:
704 	    val = lookup_enum(defaults[i].enums, str, len);
705 	    if (val == -1) {
706 		syslog(LOG_ERR, "Invalid enumeration value on %d", lineno);
707 		return;
708 	    }
709 	    defaults[i].val.intval = val;
710 	    break;
711 
712 	case DEFAULT_STR:
713 	    sval = strdup(str);
714 	    if (!sval) {
715 		syslog(LOG_ERR, "Out of memory processing default string on"
716 		       " line %d", lineno);
717 		return;
718 	    }
719 	    if (defaults[i].val.strval)
720 		free(defaults[i].val.strval);
721 	    defaults[i].val.strval = sval;
722 	    break;
723 	}
724 	return;
725     }
726 
727     syslog(LOG_ERR, "unknown default name '%s' on %d", name, lineno);
728 }
729 
730 /*
731  * This rather complicated variable is used to scan the string for
732  * ":off", ":telnet", ":raw:", or ":rawlp:".  It's a basic state
733  * machine where if a character in the first string "c" matches the
734  * current character, you go to the state machine index in the
735  * corresponding location giving by the character in string "next".
736  * So ":raw:" would see the ":" in state zero and go to state 1.  Then
737  * the "r" in state 1 would go to state 7.  Then "a" in state 7 would
738  * go to state 8, "w" to state name.  The ":" has a zero, that means a
739  * match was found.
740  *
741  * This is nasty, but it allows there to be ":" characters in the
742  * portnum so that IPV6 addresses can be specified.
743  */
744 static struct {
745     char *c;
746     char *next;
747 } scanstate[] = {
748     { ":",   "\x01" },		/* 0x00 */
749     { "tro", "\x02\x07\x0b" },	/* 0x01 */
750     { "e",   "\x03" },		/* 0x02 */
751     { "l",   "\x04" },		/* 0x03 */
752     { "n",   "\x05" },		/* 0x04 */
753     { "e",   "\x06" },		/* 0x05 */
754     { "t",   "\x0d" },		/* 0x06 */
755     { "a",   "\x08" },		/* 0x07 */
756     { "w",   "\x09" },		/* 0x09 */
757     { ":l",  "\x00\x0a" },	/* 0x09 */
758     { "p",   "\x0d" },		/* 0x0a */
759     { "f",   "\x0c" },		/* 0x0b */
760     { "f",   "\x0d" },		/* 0x0c */
761     { ":",   "\x00" }		/* 0x0d */
762 };
763 
764 static char *
scan_for_state(char * str)765 scan_for_state(char *str)
766 {
767     int s = 0;
768     char *b = str;
769 
770     for (; *str; str++) {
771 	int i;
772 
773 	for (i = 0; scanstate[s].c[i]; i++) {
774 	    if (scanstate[s].c[i] == *str)
775 		break;
776 	}
777 
778 	if (scanstate[s].c[i]) {
779 	    s = scanstate[s].next[i];
780 	    if (s == 0)
781 		return b;
782 	} else {
783 	    s = 0;
784 	    b = str + 1;
785 	}
786     }
787 
788     return NULL;
789 }
790 
791 int
handle_config_line(char * inbuf,int len)792 handle_config_line(char *inbuf, int len)
793 {
794     char *portnum, *state, *timeout, *devname, *devcfg;
795     char *strtok_data = NULL;
796 
797     if (len == 0)
798 	/* Ignore empty lines */
799 	goto out;
800 
801     if (inbuf[0] == '#')
802 	/* Ignore comments. */
803 	goto out;
804 
805     if (inbuf[len - 1] == '\\')
806 	return len - 1; /* Continued line. */
807 
808     if (startswith(inbuf, "BANNER", &strtok_data)) {
809 	char *name = strtok_r(NULL, ":", &strtok_data);
810 	char *str = strtok_r(NULL, "\n", &strtok_data);
811 	if (name == NULL) {
812 	    syslog(LOG_ERR, "No banner name given on line %d", lineno);
813 	    goto out;
814 	}
815 	handle_longstr(name, str, BANNER);
816 	goto out;
817     }
818 
819     if (startswith(inbuf, "SIGNATURE", &strtok_data)) {
820 	char *name = strtok_r(NULL, ":", &strtok_data);
821 	char *str = strtok_r(NULL, "\n", &strtok_data);
822 	if (name == NULL) {
823 	    syslog(LOG_ERR, "No signature given on line %d", lineno);
824 	    goto out;
825 	}
826 	handle_longstr(name, str, SIGNATURE);
827 	goto out;
828     }
829 
830     if (startswith(inbuf, "OPENSTR", &strtok_data)) {
831 	char *name = strtok_r(NULL, ":", &strtok_data);
832 	char *str = strtok_r(NULL, "\n", &strtok_data);
833 	if (name == NULL) {
834 	    syslog(LOG_ERR, "No open string name given on line %d", lineno);
835 	    goto out;
836 	}
837 	handle_longstr(name, str, OPENSTR);
838 	goto out;
839     }
840 
841     if (startswith(inbuf, "CLOSESTR", &strtok_data)) {
842 	char *name = strtok_r(NULL, ":", &strtok_data);
843 	char *str = strtok_r(NULL, "\n", &strtok_data);
844 	if (name == NULL) {
845 	    syslog(LOG_ERR, "No close string name given on line %d", lineno);
846 	    goto out;
847 	}
848 	handle_longstr(name, str, CLOSESTR);
849 	goto out;
850     }
851 
852     if (startswith(inbuf, "CLOSEON", &strtok_data)) {
853 	char *name = strtok_r(NULL, ":", &strtok_data);
854 	char *str = strtok_r(NULL, "\n", &strtok_data);
855 	if (name == NULL) {
856 	    syslog(LOG_ERR, "No close on string name given on line %d", lineno);
857 	    goto out;
858 	}
859 	handle_longstr(name, str, CLOSEON);
860 	goto out;
861     }
862 
863     if (startswith(inbuf, "DEVICE", &strtok_data)) {
864 	char *name = strtok_r(NULL, ":", &strtok_data);
865 	char *str = strtok_r(NULL, "\n", &strtok_data);
866 	if (name == NULL) {
867 	    syslog(LOG_ERR, "No device name given on line %d", lineno);
868 	    goto out;
869 	}
870 	handle_longstr(name, str, DEVNAME);
871 	goto out;
872     }
873 
874     if (startswith(inbuf, "TRACEFILE", &strtok_data)) {
875 	char *name = strtok_r(NULL, ":", &strtok_data);
876 	char *str = strtok_r(NULL, "\n", &strtok_data);
877 	if (name == NULL) {
878 	    syslog(LOG_ERR, "No tracefile name given on line %d", lineno);
879 	    goto out;
880 	}
881 	if ((str == NULL) || (strlen(str) == 0)) {
882 	    syslog(LOG_ERR, "No tracefile given on line %d", lineno);
883 	    goto out;
884 	}
885 	handle_tracefile(name, str);
886 	goto out;
887     }
888 
889     if (startswith(inbuf, "CONTROLPORT", &strtok_data)) {
890 	if (config_port)
891 	    /*
892 	     * The control port has already been configured either on the
893 	     * command line or on a previous statement.  Only take the first.
894 	     */
895 	    goto out;
896 	config_port = strdup(strtok_r(NULL, "\n", &strtok_data));
897 	if (!config_port) {
898 	    syslog(LOG_ERR, "Could not allocate memory for CONTROLPORT");
899 	    goto out;
900 	}
901 	goto out;
902     }
903 
904 #if HAVE_DECL_TIOCSRS485
905     if (startswith(inbuf, "RS485CONF", &strtok_data)) {
906         char *name = strtok_r(NULL, ":", &strtok_data);
907         char *str = strtok_r(NULL, "\n", &strtok_data);
908         if (name == NULL) {
909             syslog(LOG_ERR, "No signature given on line %d", lineno);
910             goto out;
911         }
912         if ((str == NULL) || (strlen(str) == 0)) {
913             syslog(LOG_ERR, "No RS485 configuration given on line %d", lineno);
914             goto out;
915         }
916         handle_rs485conf(name, str);
917         goto out;
918     }
919 #endif
920 
921     if (startswith(inbuf, "DEFAULT", &strtok_data)) {
922 	char *name = strtok_r(NULL, ":", &strtok_data);
923 	char *str = strtok_r(NULL, "\n", &strtok_data);
924 	if (name == NULL) {
925 	    syslog(LOG_ERR, "No default name given on line %d", lineno);
926 	    goto out;
927 	}
928 	handle_new_default(name, str);
929 	goto out;
930     }
931 
932     if (startswith(inbuf, "ROTATOR", &strtok_data)) {
933 	char *name = strtok_r(NULL, ":", &strtok_data);
934 	char *str = strtok_r(NULL, "\n", &strtok_data);
935 	if (name == NULL) {
936 	    syslog(LOG_ERR, "No rotator name given on line %d", lineno);
937 	    goto out;
938 	}
939 	add_rotator(name, str, lineno);
940 	goto out;
941     }
942 
943     if (startswith(inbuf, "LED", &strtok_data)) {
944 	char *name = strtok_r(NULL, ":", &strtok_data);
945 	char *str = strtok_r(NULL, "\n", &strtok_data);
946 	if (name == NULL) {
947 	    syslog(LOG_ERR, "No LED name given on line %d", lineno);
948 	    goto out;
949 	}
950 	if ((str == NULL) || (strlen(str) == 0)) {
951 	    syslog(LOG_ERR, "No LED given on line %d", lineno);
952 	    goto out;
953 	}
954 	handle_led(name, str, lineno);
955 	goto out;
956     }
957 
958     /* Scan for the state. */
959     state = scan_for_state(inbuf);
960     if (!state) {
961 	syslog(LOG_ERR, "No state given on line %d", lineno);
962 	goto out;
963     }
964 
965     /* Everything before the state is the port number. */
966     portnum = inbuf;
967     *state = '\0';
968     state++;
969 
970     /* Terminate the state. */
971     inbuf = strchr(state, ':'); /* ":" must be there if scan_for_state works */
972     *inbuf = '\0';
973     inbuf++;
974 
975     timeout = strtok_r(inbuf, ":", &strtok_data);
976     if (timeout == NULL) {
977 	syslog(LOG_ERR, "No timeout given on line %d", lineno);
978 	goto out;
979     }
980 
981     devname = strtok_r(NULL, ":", &strtok_data);
982     if (devname == NULL) {
983 	syslog(LOG_ERR, "No device name given on line %d", lineno);
984 	goto out;
985     }
986 
987     devcfg = strtok_r(NULL, "", &strtok_data);
988     if (devcfg == NULL) {
989 	/* An empty device config is ok. */
990 	devcfg = "";
991     }
992 
993     portconfig(&syslog_eout, portnum, state, timeout, devname, devcfg,
994 	       config_num);
995 
996  out:
997     return 0;
998 }
999 
1000 void
readconfig_init(void)1001 readconfig_init(void)
1002 {
1003     setup_defaults();
1004     free_longstrs();
1005     free_tracefiles();
1006 #if HAVE_DECL_TIOCSRS485
1007     free_rs485confs();
1008 #endif
1009     free_leds();
1010 
1011     config_num++;
1012     free_rotators();
1013 }
1014 
1015 /* Read the specified configuration file and call the routine to
1016    create the ports. */
1017 int
readconfig(char * filename)1018 readconfig(char *filename)
1019 {
1020     FILE *instream = NULL;
1021     int linesize = 256;
1022     char *inbuf = malloc(linesize);
1023     int  rv = 0, pos = 0;
1024 
1025     if (!inbuf) {
1026 	syslog(LOG_ERR, "Unable to allocate input buffer");
1027 	return -1;
1028     }
1029 
1030     lineno = 0;
1031 
1032     instream = fopen(filename, "r");
1033     if (!instream) {
1034 	syslog(LOG_ERR, "Unable to open config file '%s': %m", filename);
1035 	rv = -1;
1036 	goto out_err;
1037     }
1038 
1039     while (fgets(inbuf + pos, linesize - pos, instream) != NULL) {
1040 	int len = strlen(inbuf);
1041 	lineno++;
1042 	if (len >= (linesize - 1) && inbuf[len - 1] != '\n') {
1043 	    char *new_inbuf;
1044 
1045 	    /* We filled up the buffer.  Expand the line. */
1046 	    pos = len;
1047 	    linesize += 256;
1048 	    new_inbuf = realloc(inbuf, linesize);
1049 	    if (!new_inbuf) {
1050 		syslog(LOG_ERR, "Unable to reallocate input buffer");
1051 		rv = -1;
1052 		goto out_err;
1053 	    }
1054 	    inbuf = new_inbuf;
1055 	    continue;
1056 	}
1057 
1058 	/* Remove the '\n' */
1059 	if (len > 0 && inbuf[len - 1] == '\n') {
1060 	    inbuf[len - 1] = '\0';
1061 	    len--;
1062 	}
1063 	pos = handle_config_line(inbuf, len);
1064     }
1065     if (pos > 0)
1066 	handle_config_line(inbuf, strlen(inbuf));
1067 
1068     /* Delete anything that wasn't in the new config file. */
1069     clear_old_port_config(config_num);
1070 
1071  out_err:
1072     if (instream)
1073 	fclose(instream);
1074     free(inbuf);
1075     return rv;
1076 }
1077 
1078