1 /*
2 Copyright 1987, 1998  The Open Group
3 
4 Permission to use, copy, modify, distribute, and sell this software and its
5 documentation for any purpose is hereby granted without fee, provided that
6 the above copyright notice appear in all copies and that both that
7 copyright notice and this permission notice appear in supporting
8 documentation.
9 
10 The above copyright notice and this permission notice shall be included in
11 all copies or substantial portions of the Software.
12 
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
16 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
17 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 
20 Except as contained in this notice, the name of The Open Group shall not be
21 used in advertising or otherwise to promote the sale, use or other dealings
22 in this Software without prior written authorization from The Open Group.
23  * Copyright 1990, 1991 Network Computing Devices;
24  * Portions Copyright 1987 by Digital Equipment Corporation
25  *
26  * Permission to use, copy, modify, distribute, and sell this software and its
27  * documentation for any purpose is hereby granted without fee, provided that
28  * the above copyright notice appear in all copies and that both that
29  * copyright notice and this permission notice appear in supporting
30  * documentation, and that the names of Network Computing Devices,
31  * or Digital not be used in advertising or
32  * publicity pertaining to distribution of the software without specific,
33  * written prior permission.  Network Computing Devices, or Digital
34  * make no representations about the
35  * suitability of this software for any purpose.  It is provided "as is"
36  * without express or implied warranty.
37  *
38  * NETWORK COMPUTING DEVICES, AND DIGITAL DISCLAIM ALL WARRANTIES WITH
39  * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
40  * AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES, OR DIGITAL BE
41  * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
42  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
43  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
44  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
45  *
46  */
47 
48 #include	"config.h"
49 
50 #include	<stdio.h>
51 #include	<stdlib.h>
52 #include	<ctype.h>
53 #include	<X11/Xtrans/Xtrans.h>
54 #include	<X11/Xos.h>
55 #include	"misc.h"
56 #include	"configstr.h"
57 #include	"osdep.h"
58 #include	"globals.h"
59 #include	"access.h"
60 #include	"difsutils.h"
61 #include	"difs.h"
62 #include        <X11/fonts/libxfont2.h>
63 
64 /* libXfont/src/bitmap/snfstr.h */
65 extern void SnfSetFormat(int bit, int byte, int glyph, int scan);
66 
67 static const char * const default_config_files[] = {
68 #ifdef DEFAULT_CONFIG_FILE
69     DEFAULT_CONFIG_FILE,
70 #else
71     "/usr/lib/X11/fs/config",
72 #endif
73     NULL
74 };
75 
76 static char *font_catalogue = NULL;
77 
78 static char *config_set_int(ConfigOptionPtr parm, char *val);
79 static char *config_set_bool(ConfigOptionPtr parm, char *val);
80 static char *config_set_catalogue(ConfigOptionPtr parm, char *val);
81 static char *config_set_glyph_caching_mode(ConfigOptionPtr parm, char *val);
82 static char *config_set_list(ConfigOptionPtr parm, char *val);
83 static char *config_set_file(ConfigOptionPtr parm, char *val);
84 static char *config_set_resolutions(ConfigOptionPtr parm, char *val);
85 static char *config_set_ignored_transports(ConfigOptionPtr parm, char *val);
86 static char *config_set_snf_format(ConfigOptionPtr parm, char *val);
87 
88 /* these need to be in lower case and alphabetical order so a
89  * binary search lookup can be used
90  */
91 static ConfigOptionRec config_options[] = {
92     {"alternate-servers", config_set_list},
93     {"catalogue", config_set_catalogue},
94     {"client-limit", config_set_int},
95     {"clone-self", config_set_bool},
96     {"default-point-size", config_set_int},
97     {"default-resolutions", config_set_resolutions},
98     {"deferglyphs", config_set_glyph_caching_mode},
99     {"error-file", config_set_file},
100     {"no-listen", config_set_ignored_transports},
101     {"port", config_set_int},
102     {"server-number", config_set_int},
103     {"snf-format", config_set_snf_format},
104     {"trusted-clients", config_set_list},
105     {"use-syslog", config_set_bool},
106     {NULL, NULL},
107 };
108 
109 /* max size in bytes of config file */
110 #define	CONFIG_MAX_FILESIZE	32767
111 
112 #define	CONFIG_ERR_MEMORY \
113     "CONFIG: insufficient memory to load configuration file \"%s\"\n"
114 #define	CONFIG_ERR_OPEN "CONFIG: can't open configuration file \"%s\"\n"
115 #define	CONFIG_ERR_READ "CONFIG: error reading configuration file \"%s\"\n"
116 #define	CONFIG_ERR_VALUE "CONFIG: bad value \"%s\" for parameter \"%s\"\n"
117 #define	CONFIG_ERR_UNKNOWN "CONFIG: unknown parameter \"%s\"\n"
118 #define	CONFIG_ERR_NOEQUALS "CONFIG: missing '=' after parameter \"%s\"\n"
119 #define	CONFIG_ERR_RANGE "CONFIG: value out of range for parameter \"%s\"\n"
120 #define	CONFIG_ERR_SYNTAX "CONFIG: syntax error near parameter \"%s\"\n"
121 #define	CONFIG_ERR_NOVALUE "CONFIG: missing value for parameter \"%s\"\n"
122 #define	CONFIG_ERR_EXTRAVALUE "CONFIG: extra value for parameter \"%s\"\n"
123 
124 #define	iseol(c)	((c) == '\n' || (c) == '\r' || (c) == '\f')
125 #define	skip_whitespace(c)	while(isspace(*(c)) || *(c) == ',') (c)++;
126 #define	skip_val(c)	while(!isspace(*(c)) && *(c) != ',' && *(c) != '\0')\
127 						(c) ++;
128 #define	skip_list_val(c)	while(!isspace(*(c)) && *(c) != '\0')\
129 						(c) ++;
130 #define	blank_comment(c)	while (!iseol(*(c)) && *(c) != '\0')	\
131 						*(c)++= ' ';
132 
133 static char *
next_assign(char * c)134 next_assign(char *c)
135 {
136     int         nesting = 0;
137 
138     while (*c != '\0') {
139 	if (*c == '(')
140 	    nesting++;
141 	else if (*c == ')')
142 	    nesting--;
143 	else if (*c == '=' && nesting == 0)
144 	    return c;
145 	c++;
146     }
147     return (char *) 0;
148 }
149 
150 static void
strip_comments(char * data)151 strip_comments(char *data)
152 {
153     char       *c;
154 
155     c = data;
156     while ((c = strchr(c, '#')) != NULL) {
157 	if (c == data || *(c - 1) != '\\') {
158 	    blank_comment(c);
159 	} else {
160 	    c++;
161 	}
162     }
163 }
164 
165 static ConfigOptionPtr
match_param_name(char * name)166 match_param_name(char *name)
167 {
168     int         pos,
169                 rc,
170                 low,
171                 high;
172 
173     low = 0;
174     high = sizeof(config_options) / sizeof(ConfigOptionRec) - 2;
175     pos = high >> 1;
176 
177     while (low <= high) {
178 	rc = strcmp(name, config_options[pos].parm_name);
179 	if (rc == 0) {
180 	    return &config_options[pos];
181 	} else if (rc < 0) {
182 	    high = pos - 1;
183 	} else {
184 	    low = pos + 1;
185 	}
186 	pos = ((high + low) >> 1);
187     }
188     return NULL;
189 }
190 
191 static int
parse_config(char * data)192 parse_config(char *data)
193 {
194     char       *c,
195                *val = NULL,
196                *next_eq,
197                *consumed,
198                *p;
199     char        param_name[64];
200     Bool        equals_missing;
201     ConfigOptionPtr param;
202 
203     c = data;
204     skip_whitespace(c);
205 
206     while (*c != '\0') {
207 	equals_missing = FALSE;
208 
209 	/* get parm name in lower case */
210 	p = c;
211 	while (isalnum(*c) || *c == '-') {
212 	    if (isupper(*c))
213 		*c = tolower(*c);
214 	    c++;
215 	}
216 	memmove( param_name, p, min(sizeof(param_name), (int) (c - p)));
217 	param_name[(int) (c - p)] = '\0';
218 
219 	/* check for junk */
220 	if (!isspace(*c) && *c != '=') {
221 	    ErrorF(CONFIG_ERR_SYNTAX, param_name);
222 	    /* eat garbage */
223 	    while (!isspace(*c) && *c != '=' && *c != '\0')
224 		c++;
225 	}
226 	skip_whitespace(c);
227 	if (*c != '=') {
228 	    ErrorF(CONFIG_ERR_NOEQUALS, param_name);
229 	    equals_missing = TRUE;
230 	} else {
231 	    c++;
232 	}
233 
234 	skip_whitespace(c);
235 
236 	/* find next assignment to guess where the value ends */
237 	if ((next_eq = next_assign(c)) != NULL) {
238 	    /* back up over whitespace */
239 	    for (val = next_eq - 1; val >= c &&
240 		    (isspace(*val) || *val == ',');
241 		    val--);
242 
243 	    /* back over parm name */
244 	    for (; val >= c && (isalnum(*val) || *val == '-'); val--);
245 
246 	    if (val <= c) {
247 		/* no value, ignore */
248 		ErrorF(CONFIG_ERR_NOVALUE, param_name);
249 		continue;
250 	    }
251 	    *val = '\0';
252 	} else if (*c == '\0') {
253 	    /* no value, ignore */
254 	    ErrorF(CONFIG_ERR_NOVALUE, param_name);
255 	    continue;
256 	}
257 	/* match parm name */
258 	if (equals_missing) {
259 	    equals_missing = FALSE;
260 	} else if ((param = match_param_name(param_name)) == NULL) {
261 	    ErrorF(CONFIG_ERR_UNKNOWN, param_name);
262 	} else {
263 	    consumed = (param->set_func) (param, c);
264 
265 	    skip_whitespace(consumed);
266 	    if (*consumed != '\0') {
267 		ErrorF(CONFIG_ERR_EXTRAVALUE,
268 		       param_name);
269 	    }
270 	}
271 
272 	if (next_eq != NULL)
273 	    c = val + 1;
274 	else			/* last setting */
275 	    break;
276     }
277     return FSSuccess;
278 }
279 
280 /*
281  * handles anything that should be set once the file is parsed
282  */
283 void
SetConfigValues(void)284 SetConfigValues(void)
285 {
286     int         err,
287                 num;
288 
289     if (font_catalogue == NULL) {
290 	FatalError("font catalogue is missing/empty\n");
291     }
292 
293     err = SetFontCatalogue(font_catalogue, &num);
294     if (err != FSSuccess) {
295 	FatalError("element #%d (starting at 0) of font path is bad or has a bad font:\n\"%s\"\n",
296 		   num, font_catalogue);
297     }
298     InitErrors();
299     fsfree((char *) font_catalogue);
300     font_catalogue = NULL;
301 }
302 
303 
304 /* If argument is NULL, uses first file found from default_config_files */
305 int
ReadConfigFile(const char * filename)306 ReadConfigFile(const char *filename)
307 {
308     FILE       *fp = NULL;
309     int         ret;
310     int         len;
311     int         i;
312     char       *data;
313 
314     data = (char *) fsalloc(CONFIG_MAX_FILESIZE);
315     if (!data) {
316 	ErrorF(CONFIG_ERR_MEMORY, filename);
317 	return FSBadAlloc;
318     }
319     if (filename != NULL) {
320 	fp = fopen(filename, "r");
321 	if (fp == NULL) {
322 	    ErrorF(CONFIG_ERR_OPEN, filename);
323 	}
324     } else {
325 	for (i = 0; default_config_files[i] != NULL; i++) {
326 	    filename = default_config_files[i];
327 	    if ((fp = fopen(filename, "r")) != NULL) {
328 		if (configfilename == NULL) {
329 		    configfilename = strdup(filename); /* save for clones */
330 		}
331 		break;
332 	    }
333 	}
334 	if (fp == NULL) {
335 	    for (i = 0; default_config_files[i] != NULL; i++) {
336 		ErrorF(CONFIG_ERR_OPEN, default_config_files[i]);
337 	    }
338 	}
339     }
340     if (fp == NULL) {
341 	fsfree(data);
342 	return FSBadName;
343     }
344     ret = fread(data, sizeof(char), CONFIG_MAX_FILESIZE, fp);
345     if (ret <= 0) {
346 	fsfree(data);
347 	(void) fclose(fp);
348 	ErrorF(CONFIG_ERR_READ, filename);
349 	return FSBadName;
350     }
351     len = ftell(fp);
352     len = min(len, CONFIG_MAX_FILESIZE);
353     data[len] = '\0';		/* NULL terminate the data */
354 
355     (void) fclose(fp);
356 
357     strip_comments(data);
358     ret = parse_config(data);
359 
360     fsfree(data);
361 
362     return ret;
363 }
364 
365 struct nameVal {
366     const char *name;
367     int         val;
368 };
369 
370 static char *
config_parse_nameVal(ConfigOptionPtr parm,char * c,int * ret,int * pval,struct nameVal * name_val)371 config_parse_nameVal (
372     ConfigOptionPtr parm,
373     char       *c,
374     int        *ret,
375     int		*pval,
376     struct nameVal   *name_val)
377 {
378     char       *start,
379                 t;
380     int         i,
381                 len;
382 
383     start = c;
384     skip_val(c);
385     t = *c;
386     *c = '\0';
387     len = c - start;
388 
389     for (i = 0; name_val[i].name; i++) {
390 	if (!strncmpnocase(start, name_val[i].name, len)) {
391 	    *pval = name_val[i].val;
392 	    *ret = 0;
393 	    *c = t;
394 	    return c;
395 	}
396     }
397     ErrorF(CONFIG_ERR_VALUE, start, parm->parm_name);
398     *c = t;
399     *ret = -1;
400     return c;
401 }
402 
403 static char *
config_parse_bool(ConfigOptionPtr parm,char * c,int * ret,Bool * pval)404 config_parse_bool (
405     ConfigOptionPtr parm,
406     char	*c,
407     int		*ret,
408     Bool	*pval)
409 {
410     static struct nameVal bool_val[] = {
411     	    { "yes",   TRUE },
412     	    { "on",    TRUE },
413     	    { "1",     TRUE },
414     	    { "true",  TRUE },
415     	    { "no",    FALSE },
416     	    { "off",   FALSE },
417     	    { "0",     FALSE },
418     	    { "false", FALSE },
419     	    { (char *) 0, 0 },
420     };
421     return config_parse_nameVal (parm, c, ret, pval, bool_val);
422 }
423 
424 static char *
config_parse_int(ConfigOptionPtr parm,char * c,int * ret,int * pval)425 config_parse_int(
426     ConfigOptionPtr parm,
427     char       *c,
428     int        *ret,
429     int        *pval)
430 {
431     char       *start,
432                 t;
433 
434     start = c;
435     while (*c != '\0' && !isspace(*c) && *c != ',') {
436 	if (!isdigit(*c)) {	/* error */
437 	    skip_val(c);
438 	    t = *c;
439 	    *c = '\0';
440 	    ErrorF(CONFIG_ERR_VALUE, start, parm->parm_name);
441 	    *ret = -1;
442 	    *c = t;
443 	    return c;
444 	}
445 	c++;
446     }
447     t = *c;
448     *c = '\0';
449     *ret = 0;
450     *pval = atoi(start);
451     *c = t;
452     return c;
453 }
454 
455 
456 /* config option sets */
457 /* these have to know how to do the real work and tweak the proper things */
458 static char *
config_set_int(ConfigOptionPtr parm,char * val)459 config_set_int(
460     ConfigOptionPtr parm,
461     char       *val)
462 {
463     int         ival,
464                 ret;
465 
466     val = config_parse_int(parm, val, &ret, &ival);
467     if (ret == -1)
468 	return val;
469 
470     /* now do individual attribute checks */
471     if (!strcmp(parm->parm_name, "port") && !portFromCmdline) {
472 	ListenPort = ival;
473     } else if (!strcmp(parm->parm_name, "client-limit")) {
474 	AccessSetConnectionLimit(ival);
475     } else if (!strcmp(parm->parm_name, "default-point-size")) {
476 	SetDefaultPointSize(ival);
477     }
478     return val;
479 }
480 
481 static char *
config_set_bool(ConfigOptionPtr parm,char * val)482 config_set_bool(
483     ConfigOptionPtr parm,
484     char       *val)
485 {
486     int
487                 ret;
488     Bool        bval;
489 
490     val = config_parse_bool(parm, val, &ret, &bval);
491     if (ret == -1)
492 	return val;
493 
494     /* now do individual attribute checks */
495     if (!strcmp(parm->parm_name, "use-syslog")) {
496 	UseSyslog = bval;
497     } else if (!strcmp(parm->parm_name, "clone-self")) {
498 	CloneSelf = bval;
499     }
500     return val;
501 }
502 
503 static char *
config_set_file(ConfigOptionPtr parm,char * val)504 config_set_file(
505     ConfigOptionPtr parm,
506     char       *val)
507 {
508     char       *start = val,
509                 t;
510 
511     skip_val(val);
512     t = *val;
513     *val = '\0';
514     if (!strcmp(parm->parm_name, "error-file")) {
515 	memmove( ErrorFile, start, val - start + 1);
516     }
517     *val = t;
518     return val;
519 }
520 
521 static char *
config_set_catalogue(ConfigOptionPtr parm,char * val)522 config_set_catalogue(
523     ConfigOptionPtr parm,
524     char       *val)
525 {
526     char       *b;
527 
528     if (!strcmp(parm->parm_name, "catalogue")) {
529 	/* stash it for later */
530 	fsfree((char *) font_catalogue);	/* dump any previous one */
531 	b = font_catalogue = (char *) fsalloc(strlen(val) + 1);
532 	if (!font_catalogue)
533 	    FatalError("insufficent memory for font catalogue\n");
534 	while (*val) {		/* remove all the gunk */
535 	    if (!isspace(*val)) {
536 		*b++ = *val;
537 	    }
538 	    val++;
539 	}
540 	*b = '\0';
541     }
542     return val;
543 }
544 
545 static char *
config_set_list(ConfigOptionPtr parm,char * val)546 config_set_list(
547     ConfigOptionPtr parm,
548     char       *val)
549 {
550     char       *start = val,
551                 t;
552 
553     skip_list_val(val);
554     t = *val;
555     *val = '\0';
556     if (!strcmp(parm->parm_name, "alternate-servers")) {
557 	SetAlternateServers(start);
558     }
559     *val = t;
560     return val;
561 }
562 
563 static char *
config_set_ignored_transports(ConfigOptionPtr parm,char * val)564 config_set_ignored_transports(
565     ConfigOptionPtr parm,
566     char       *val)
567 {
568     char       *start = val,
569                 t;
570 
571     skip_list_val(val);
572     t = *val;
573     *val = '\0';
574     _FontTransNoListen(start);
575     *val = t;
576     return val;
577 }
578 
579 static char *
config_set_glyph_caching_mode(ConfigOptionPtr parm,char * val)580 config_set_glyph_caching_mode(
581     ConfigOptionPtr parm,
582     char       *val)
583 {
584     char       *start = val,
585                 t;
586 
587     skip_list_val(val);
588     t = *val;
589     *val = '\0';
590     if (!strcmp(parm->parm_name, "deferglyphs")) {
591 	xfont2_parse_glyph_caching_mode(start);
592     }
593     *val = t;
594     return val;
595 }
596 
597 static char *
config_set_resolutions(ConfigOptionPtr parm,char * val)598 config_set_resolutions(
599     ConfigOptionPtr parm,
600     char       *val)
601 {
602     char       *start = val,
603                 t;
604     int         err;
605 
606     skip_list_val(val);
607     t = *val;
608     *val = '\0';
609     if (!strcmp(parm->parm_name, "default-resolutions")) {
610 	err = SetDefaultResolutions(start);
611 	if (err != FSSuccess) {
612 	    FatalError("bogus resolution list \"%s\"\n", start);
613 	}
614     }
615     *val = t;
616     return val;
617 }
618 
619 
620 static char *
config_parse_endian(ConfigOptionPtr parm,char * c,int * ret,int * pval)621 config_parse_endian(
622     ConfigOptionPtr parm,
623     char       *c,
624     int        *ret,
625     int		*pval)
626 {
627     static struct nameVal endian_val[] = {
628 	{ "lsb",      LSBFirst },
629 	{ "little",   LSBFirst },
630 	{ "lsbfirst", LSBFirst },
631 	{ "msb",      MSBFirst },
632 	{ "big",      MSBFirst },
633 	{ "msbfirst", MSBFirst },
634 	{ (char *) 0, 0 },
635     };
636     return config_parse_nameVal (parm, c, ret, pval, endian_val);
637 }
638 
639 /* ARGSUSED */
640 static char *
config_set_snf_format(ConfigOptionPtr parm,char * val)641 config_set_snf_format (
642     ConfigOptionPtr parm,
643     char	    *val)
644 {
645     int	    bit, byte, glyph, scan;
646     int	    ret;
647 
648     val = config_parse_endian (parm, val, &ret, &bit);
649     if (ret == -1)
650 	return val;
651     skip_whitespace (val);
652     val = config_parse_endian (parm, val, &ret, &byte);
653     if (ret == -1)
654 	return val;
655     skip_whitespace (val);
656     val = config_parse_int (parm, val, &ret, &glyph);
657     if (ret == -1)
658 	return val;
659     skip_whitespace (val);
660     val = config_parse_int (parm, val, &ret, &scan);
661     if (ret == -1)
662 	return val;
663 #ifdef XFONT_SNFFORMAT
664     SnfSetFormat (bit, byte, glyph, scan);
665 #endif
666     return val;
667 }
668