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