1/*
2 * Copyright (c) 1997-2014 Erez Zadok
3 * Copyright (c) 1990 Jan-Simon Pendry
4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1990 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 *
36 * File: am-utils/amd/conf.c
37 *
38 */
39
40/*
41 * Functions to handle the configuration file.
42 */
43
44#ifdef HAVE_CONFIG_H
45# include <config.h>
46#endif /* HAVE_CONFIG_H */
47#include <am_defs.h>
48#include <amd.h>
49
50
51/*
52 * MACROS:
53 */
54/* Turn on to show some info about maps being configured */
55/* #define DEBUG_CONF */
56
57/*
58 * TYPEDEFS:
59 */
60typedef int (*OptFuncPtr)(const char *);
61
62/*
63 * STRUCTURES:
64 */
65struct _func_map {
66  char *name;
67  OptFuncPtr func;
68};
69
70/*
71 * FORWARD DECLARATIONS:
72 */
73static int gopt_arch(const char *val);
74static int gopt_auto_attrcache(const char *val);
75static int gopt_auto_dir(const char *val);
76static int gopt_auto_nfs_version(const char *val);
77static int gopt_autofs_use_lofs(const char *val);
78static int gopt_browsable_dirs(const char *val);
79static int gopt_cache_duration(const char *val);
80static int gopt_cluster(const char *val);
81static int gopt_debug_mtab_file(const char *val);
82static int gopt_debug_options(const char *val);
83static int gopt_dismount_interval(const char *val);
84static int gopt_domain_strip(const char *val);
85static int gopt_exec_map_timeout(const char *val);
86static int gopt_forced_unmounts(const char *val);
87static int gopt_full_os(const char *val);
88static int gopt_fully_qualified_hosts(const char *val);
89static int gopt_hesiod_base(const char *val);
90static int gopt_karch(const char *val);
91static int gopt_ldap_base(const char *val);
92static int gopt_ldap_cache_maxmem(const char *val);
93static int gopt_ldap_cache_seconds(const char *val);
94static int gopt_ldap_hostports(const char *val);
95static int gopt_ldap_proto_version(const char *val);
96static int gopt_local_domain(const char *val);
97static int gopt_localhost_address(const char *val);
98static int gopt_log_file(const char *val);
99static int gopt_log_options(const char *val);
100static int gopt_map_defaults(const char *val);
101static int gopt_map_options(const char *val);
102static int gopt_map_reload_interval(const char *val);
103static int gopt_map_type(const char *val);
104static int gopt_mount_type(const char *val);
105static int gopt_pid_file(const char *val);
106static int gopt_portmap_program(const char *val);
107static int gopt_preferred_amq_port(const char *val);
108static int gopt_nfs_allow_any_interface(const char *val);
109static int gopt_nfs_allow_insecure_port(const char *val);
110static int gopt_nfs_proto(const char *val);
111static int gopt_nfs_retransmit_counter(const char *val);
112static int gopt_nfs_retransmit_counter_udp(const char *val);
113static int gopt_nfs_retransmit_counter_tcp(const char *val);
114static int gopt_nfs_retransmit_counter_toplvl(const char *val);
115static int gopt_nfs_retry_interval(const char *val);
116static int gopt_nfs_retry_interval_udp(const char *val);
117static int gopt_nfs_retry_interval_tcp(const char *val);
118static int gopt_nfs_retry_interval_toplvl(const char *val);
119static int gopt_nfs_vers(const char *val);
120static int gopt_nfs_vers_ping(const char *val);
121static int gopt_nis_domain(const char *val);
122static int gopt_normalize_hostnames(const char *val);
123static int gopt_normalize_slashes(const char *val);
124static int gopt_os(const char *val);
125static int gopt_osver(const char *val);
126static int gopt_plock(const char *val);
127static int gopt_print_pid(const char *val);
128static int gopt_print_version(const char *val);
129static int gopt_restart_mounts(const char *val);
130static int gopt_search_path(const char *val);
131static int gopt_selectors_in_defaults(const char *val);
132static int gopt_show_statfs_entries(const char *val);
133static int gopt_sun_map_syntax(const char *val);
134static int gopt_truncate_log(const char *val);
135static int gopt_unmount_on_exit(const char *val);
136static int gopt_use_tcpwrappers(const char *val);
137static int gopt_vendor(const char *val);
138static int process_global_option(const char *key, const char *val);
139static int process_one_regular_map(const cf_map_t *cfm);
140static int process_regular_option(const char *section, const char *key, const char *val, cf_map_t *cfm);
141static int ropt_browsable_dirs(const char *val, cf_map_t *cfm);
142static int ropt_map_name(const char *val, cf_map_t *cfm);
143static int ropt_map_defaults(const char *val, cf_map_t *cfm);
144static int ropt_map_options(const char *val, cf_map_t *cfm);
145static int ropt_map_type(const char *val, cf_map_t *cfm);
146static int ropt_mount_type(const char *val, cf_map_t *cfm);
147static int ropt_search_path(const char *val, cf_map_t *cfm);
148static int ropt_sun_map_syntax(const char *val, cf_map_t *cfm);
149static int ropt_tag(const char *val, cf_map_t *cfm);
150static void init_cf_map(cf_map_t *cfm);
151
152
153/*
154 * STATIC VARIABLES:
155 */
156static cf_map_t *head_map, *cur_map;
157
158static struct _func_map glob_functable[] = {
159  {"arch",			gopt_arch},
160  {"auto_attrcache",		gopt_auto_attrcache},
161  {"auto_dir",			gopt_auto_dir},
162  {"auto_nfs_version",		gopt_auto_nfs_version},
163  {"autofs_use_lofs",		gopt_autofs_use_lofs},
164  {"browsable_dirs",		gopt_browsable_dirs},
165  {"cache_duration",		gopt_cache_duration},
166  {"cluster",			gopt_cluster},
167  {"debug_mtab_file",           gopt_debug_mtab_file},
168  {"debug_options",		gopt_debug_options},
169  {"dismount_interval",		gopt_dismount_interval},
170  {"domain_strip",		gopt_domain_strip},
171  {"exec_map_timeout",		gopt_exec_map_timeout},
172  {"forced_unmounts",		gopt_forced_unmounts},
173  {"fully_qualified_hosts",	gopt_fully_qualified_hosts},
174  {"full_os",			gopt_full_os},
175  {"hesiod_base",		gopt_hesiod_base},
176  {"karch",			gopt_karch},
177  {"ldap_base",			gopt_ldap_base},
178  {"ldap_cache_maxmem",		gopt_ldap_cache_maxmem},
179  {"ldap_cache_seconds",	gopt_ldap_cache_seconds},
180  {"ldap_hostports",		gopt_ldap_hostports},
181  {"ldap_proto_version",	gopt_ldap_proto_version},
182  {"local_domain",		gopt_local_domain},
183  {"localhost_address",		gopt_localhost_address},
184  {"log_file",			gopt_log_file},
185  {"log_options",		gopt_log_options},
186  {"map_defaults",		gopt_map_defaults},
187  {"map_options",		gopt_map_options},
188  {"map_reload_interval",	gopt_map_reload_interval},
189  {"map_type",			gopt_map_type},
190  {"mount_type",		gopt_mount_type},
191  {"pid_file",			gopt_pid_file},
192  {"portmap_program",		gopt_portmap_program},
193  {"preferred_amq_port",	gopt_preferred_amq_port},
194  {"nfs_allow_any_interface",	gopt_nfs_allow_any_interface},
195  {"nfs_allow_insecure_port",	gopt_nfs_allow_insecure_port},
196  {"nfs_proto",			gopt_nfs_proto},
197  {"nfs_retransmit_counter",	gopt_nfs_retransmit_counter},
198  {"nfs_retransmit_counter_udp",	gopt_nfs_retransmit_counter_udp},
199  {"nfs_retransmit_counter_tcp",	gopt_nfs_retransmit_counter_tcp},
200  {"nfs_retransmit_counter_toplvl",	gopt_nfs_retransmit_counter_toplvl},
201  {"nfs_retry_interval",	gopt_nfs_retry_interval},
202  {"nfs_retry_interval_udp",	gopt_nfs_retry_interval_udp},
203  {"nfs_retry_interval_tcp",	gopt_nfs_retry_interval_tcp},
204  {"nfs_retry_interval_toplvl",	gopt_nfs_retry_interval_toplvl},
205  {"nfs_vers",			gopt_nfs_vers},
206  {"nfs_vers_ping",		gopt_nfs_vers_ping},
207  {"nis_domain",		gopt_nis_domain},
208  {"normalize_hostnames",	gopt_normalize_hostnames},
209  {"normalize_slashes",		gopt_normalize_slashes},
210  {"os",			gopt_os},
211  {"osver",			gopt_osver},
212  {"plock",			gopt_plock},
213  {"print_pid",			gopt_print_pid},
214  {"print_version",		gopt_print_version},
215  {"restart_mounts",		gopt_restart_mounts},
216  {"search_path",		gopt_search_path},
217  {"selectors_on_default",	gopt_selectors_in_defaults},
218  {"selectors_in_defaults",	gopt_selectors_in_defaults},
219  {"show_statfs_entries",	gopt_show_statfs_entries},
220  {"sun_map_syntax",		gopt_sun_map_syntax},
221  {"truncate_log",		gopt_truncate_log},
222  {"unmount_on_exit",		gopt_unmount_on_exit},
223  {"use_tcpwrappers",		gopt_use_tcpwrappers},
224  {"vendor",			gopt_vendor},
225  {NULL, NULL}
226};
227
228
229/*
230 * Initialize a map from [global] defaults.
231 */
232static void
233init_cf_map(cf_map_t *cfm)
234{
235  if (!cfm)
236    return;
237
238  /*
239   * Initialize a regular map's flags and other variables from the
240   * global ones, so that they are applied to all maps.  Of course, each map
241   * can then override the flags individually.
242   *
243   * NOTES:
244   * (1): Will only work for maps that appear after [global].
245   * (2): I'm assigning pointers directly from the global map.
246   */
247
248  /* initialize map_type from [global] */
249  cfm->cfm_type = gopt.map_type;
250
251  /* initialize map_defaults from [global] */
252  cfm->cfm_defaults = gopt.map_defaults;
253
254  /* initialize map_opts from [global] */
255  cfm->cfm_opts = gopt.map_options;
256
257  /* initialize search_path from [global] */
258  cfm->cfm_search_path = gopt.search_path;
259
260  /*
261   * Initialize flags that are common both to [global] and a local map
262   * (that is, they could be inherited from the global section).
263   */
264  cfm->cfm_flags = gopt.flags & (CFM_BROWSABLE_DIRS |
265				 CFM_BROWSABLE_DIRS_FULL |
266				 CFM_MOUNT_TYPE_AUTOFS |
267				 CFM_SELECTORS_IN_DEFAULTS |
268				 CFM_SUN_MAP_SYNTAX );
269}
270
271
272/*
273 * Process configuration file options (called from YACC parser).
274 * Return 0 if OK, 1 otherwise.
275 */
276int
277set_conf_kv(const char *section, const char *key, const char *val)
278{
279  int ret;
280
281#ifdef DEBUG_CONF
282  fprintf(stderr, "set_conf_kv: section=%s, key=%s, val=%s\n",
283	  section, key, val);
284#endif /* DEBUG_CONF */
285
286  /*
287   * If global section, process kv pairs one at a time.
288   */
289  if (STREQ(section, "global")) {
290    /*
291     * Check if a regular map was configured before "global",
292     * and warn about it.
293     */
294    if (cur_map && cur_map->cfm_dir) {
295      static short printed_this_error;
296      if (!printed_this_error) {
297	fprintf(stderr, "found regular map \"%s\" before global one.\n",
298		cur_map->cfm_dir);
299	printed_this_error = 1;
300      }
301    }
302
303    /* process the global option first */
304    ret = process_global_option(key, val);
305
306    /* return status from the processing of the global option */
307    return ret;
308  }
309
310  /*
311   * Otherwise we found a non-global option: store it after some testing.
312   */
313
314  /* initialize (static) global list head and current map pointer */
315  if (!head_map && !cur_map) {
316    cur_map = CALLOC(cf_map_t);
317    if (!cur_map) {
318      perror("calloc");
319      exit(1);
320    }
321    /* initialize first head map from global defaults */
322    init_cf_map(cur_map);
323    head_map = cur_map;
324  }
325
326  /* check if we found a new map, then allocate and initialize it */
327  if (cur_map->cfm_dir && !STREQ(cur_map->cfm_dir, section)) {
328    /* allocate new map struct */
329    cf_map_t *tmp_map = CALLOC(cf_map_t);
330    if (!tmp_map) {
331      perror("calloc");
332      exit(1);
333    }
334    /* initialize it from global defaults */
335    init_cf_map(tmp_map);
336    /* append it to end of linked list */
337    cur_map->cfm_next = tmp_map;
338    cur_map = tmp_map;
339  }
340
341  /* now process a single entry of a regular map */
342  return process_regular_option(section, key, val, cur_map);
343}
344
345
346/*
347 * Process global section of configuration file options.
348 * Return 0 upon success, 1 otherwise.
349 */
350static int
351process_global_option(const char *key, const char *val)
352{
353  struct _func_map *gfp;
354
355  /* ensure that val is valid */
356  if (!val || val[0] == '\0')
357    return 1;
358
359  /*
360   * search for global function.
361   */
362  for (gfp = glob_functable; gfp->name; gfp++)
363    if (FSTREQ(gfp->name, key))
364      return (gfp->func)(val);
365
366  fprintf(stderr, "conf: unknown global key: \"%s\"\n", key);
367  return 1;			/* failed to match any command */
368}
369
370
371static int
372gopt_arch(const char *val)
373{
374  gopt.arch = xstrdup(val);
375  return 0;
376}
377
378
379static int
380gopt_auto_attrcache(const char *val)
381{
382  gopt.auto_attrcache = atoi(val);
383  if (gopt.auto_attrcache < 0) {
384    fprintf(stderr, "conf: bad attrcache value: \"%s\"\n", val);
385    return 1;
386  }
387  return 0;
388}
389
390
391static int
392gopt_auto_dir(const char *val)
393{
394  gopt.auto_dir = xstrdup(val);
395  return 0;
396}
397
398static int
399gopt_auto_nfs_version(const char *val)
400{
401  if (strcmp(val, "2") == 0)
402    nfs_dispatcher = nfs_program_2;
403  else if (strcmp(val, "3") == 0)
404    nfs_dispatcher = nfs_program_3;
405  else {
406    fprintf(stderr, "conf: bad auto nfs version : \"%s\"\n", val);
407    return 1;
408  }
409  return 0;
410}
411
412static int
413gopt_autofs_use_lofs(const char *val)
414{
415  if (STREQ(val, "yes")) {
416    gopt.flags |= CFM_AUTOFS_USE_LOFS;
417    return 0;
418  } else if (STREQ(val, "no")) {
419    gopt.flags &= ~CFM_AUTOFS_USE_LOFS;
420    return 0;
421  }
422
423  fprintf(stderr, "conf: unknown value to autofs_use_lofs \"%s\"\n", val);
424  return 1;			/* unknown value */
425}
426
427
428static int
429gopt_browsable_dirs(const char *val)
430{
431  if (STREQ(val, "full")) {
432    gopt.flags |= CFM_BROWSABLE_DIRS_FULL;
433    return 0;
434  } else if (STREQ(val, "yes")) {
435    gopt.flags |= CFM_BROWSABLE_DIRS;
436    return 0;
437  } else if (STREQ(val, "no")) {
438    gopt.flags &= ~CFM_BROWSABLE_DIRS;
439    return 0;
440  }
441
442  fprintf(stderr, "conf: unknown value to browsable_dirs \"%s\"\n", val);
443  return 1;			/* unknown value */
444}
445
446
447static int
448gopt_cache_duration(const char *val)
449{
450  gopt.am_timeo = atoi(val);
451  if (gopt.am_timeo <= 0)
452    gopt.am_timeo = AM_TTL;
453  return 0;
454}
455
456
457static int
458gopt_cluster(const char *val)
459{
460  gopt.cluster = xstrdup(val);
461  return 0;
462}
463
464
465static int
466gopt_debug_mtab_file(const char *val)
467{
468  gopt.debug_mtab_file = xstrdup(val);
469  return 0;
470}
471
472
473static int
474gopt_debug_options(const char *val)
475{
476#ifdef DEBUG
477  usage += debug_option((char *)val);
478  return 0;
479#else /* not DEBUG */
480  fprintf(stderr, "%s: not compiled with DEBUG option -- sorry.\n",
481	  am_get_progname());
482  return 1;
483#endif /* not DEBUG */
484}
485
486
487static int
488gopt_dismount_interval(const char *val)
489{
490  gopt.am_timeo_w = atoi(val);
491  if (gopt.am_timeo_w <= 0)
492    gopt.am_timeo_w = AM_TTL_W;
493  return 0;
494}
495
496
497static int
498gopt_domain_strip(const char *val)
499{
500  if (STREQ(val, "yes")) {
501    gopt.flags |= CFM_DOMAIN_STRIP;
502    return 0;
503  } else if (STREQ(val, "no")) {
504    gopt.flags &= ~CFM_DOMAIN_STRIP;
505    return 0;
506  }
507
508  fprintf(stderr, "conf: unknown value to domain_strip \"%s\"\n", val);
509  return 1;                     /* unknown value */
510}
511
512
513static int
514gopt_exec_map_timeout(const char *val)
515{
516  gopt.exec_map_timeout = atoi(val);
517  if (gopt.exec_map_timeout <= 0)
518    gopt.exec_map_timeout = AMFS_EXEC_MAP_TIMEOUT; /* default exec map timeout */
519  return 0;
520}
521
522
523static int
524gopt_forced_unmounts(const char *val)
525{
526  if (STREQ(val, "yes")) {
527#if !defined(MNT2_GEN_OPT_DETACH) && !defined(MNT2_GEN_OPT_FORCE)
528    fprintf(stderr, "conf: forced_unmounts unsupported on this system.\n");
529    return 1;
530#else /* defined(MNT2_GEN_OPT_DETACH) || defined(MNT2_GEN_OPT_FORCE) */
531# ifdef __linux__
532    /*
533     * HACK ALERT: Linux has had MNT_FORCE since 2.2, but it hasn't gotten
534     * stable until 2.4.  And it had MNT_DETACH since 2.4, but it hasn't
535     * gotten stable since 2.6.  So alert users if they're trying to use a
536     * feature that may not work well on their older kernel.
537     */
538    {
539      struct utsname un;
540      if (uname(&un) >= 0) {
541#  ifdef MNT2_GEN_OPT_FORCE
542	if (strcmp(un.release, "2.4.0") < 0)
543	  fprintf(stderr, "warning: forced-unmounts (MNT_FORCE) may not work well before 2.4.0\n");
544#  endif /* MNT2_GEN_OPT_FORCE */
545#  ifdef MNT2_GEN_OPT_DETACH
546	if (strcmp(un.release, "2.6.0") < 0)
547	  fprintf(stderr, "warning: lazy-unmounts (MNT_DETACH) may not work well before 2.6.0\n");
548#  endif /* MNT2_GEN_OPT_DETACH */
549      }
550    }
551# endif /* __linux__ */
552    gopt.flags |= CFM_FORCED_UNMOUNTS;
553    return 0;
554#endif /* defined(MNT2_GEN_OPT_DETACH) || defined(MNT2_GEN_OPT_FORCE) */
555  } else if (STREQ(val, "no")) {
556    gopt.flags &= ~CFM_FORCED_UNMOUNTS;
557    return 0;
558  }
559
560  fprintf(stderr, "conf: unknown value to unmount_on_exit \"%s\"\n", val);
561  return 1;			/* unknown value */
562}
563
564
565static int
566gopt_full_os(const char *val)
567{
568  gopt.op_sys_full = xstrdup(val);
569  return 0;
570}
571
572
573static int
574gopt_fully_qualified_hosts(const char *val)
575{
576  if (STREQ(val, "yes")) {
577    gopt.flags |= CFM_FULLY_QUALIFIED_HOSTS;
578    return 0;
579  } else if (STREQ(val, "no")) {
580    gopt.flags &= ~CFM_FULLY_QUALIFIED_HOSTS;
581    return 0;
582  }
583
584  fprintf(stderr, "conf: unknown value to fully_qualified_hosts \"%s\"\n", val);
585  return 1;			/* unknown value */
586}
587
588
589static int
590gopt_hesiod_base(const char *val)
591{
592#ifdef HAVE_MAP_HESIOD
593  gopt.hesiod_base = xstrdup(val);
594  return 0;
595#else /* not HAVE_MAP_HESIOD */
596  fprintf(stderr, "conf: hesiod_base option ignored.  No Hesiod support available.\n");
597  return 1;
598#endif /* not HAVE_MAP_HESIOD */
599}
600
601
602static int
603gopt_karch(const char *val)
604{
605  gopt.karch = xstrdup(val);
606  return 0;
607}
608
609
610static int
611gopt_pid_file(const char *val)
612{
613  gopt.pid_file = xstrdup(val);
614  return 0;
615}
616
617
618static int
619gopt_local_domain(const char *val)
620{
621  gopt.sub_domain = xstrdup(val);
622  return 0;
623}
624
625
626static int
627gopt_localhost_address(const char *val)
628{
629  gopt.localhost_address = xstrdup(val);
630  return 0;
631}
632
633
634static int
635gopt_ldap_base(const char *val)
636{
637#ifdef HAVE_MAP_LDAP
638  gopt.ldap_base = xstrdup(val);
639  return 0;
640#else /* not HAVE_MAP_LDAP */
641  fprintf(stderr, "conf: ldap_base option ignored.  No LDAP support available.\n");
642  return 1;
643#endif /* not HAVE_MAP_LDAP */
644}
645
646
647static int
648gopt_ldap_cache_seconds(const char *val)
649{
650#ifdef HAVE_MAP_LDAP
651  char *end;
652
653  gopt.ldap_cache_seconds = strtol((char *)val, &end, 10);
654  if (end == val) {
655    fprintf(stderr, "conf: bad LDAP cache (seconds) option: %s\n",val);
656    return 1;
657  }
658  return 0;
659#else /* not HAVE_MAP_LDAP */
660  fprintf(stderr, "conf: ldap_cache_seconds option ignored.  No LDAP support available.\n");
661  return 1;
662#endif /* not HAVE_MAP_LDAP */
663}
664
665
666static int
667gopt_ldap_cache_maxmem(const char *val)
668{
669#ifdef HAVE_MAP_LDAP
670  char *end;
671
672  gopt.ldap_cache_maxmem = strtol((char *)val, &end, 10);
673  if (end == val) {
674    fprintf(stderr, "conf: bad LDAP cache (maxmem) option: %s\n",val);
675    return 1;
676  }
677  return 0;
678#else /* not HAVE_MAP_LDAP */
679  fprintf(stderr, "conf: ldap_cache_maxmem option ignored.  No LDAP support available.\n");
680  return 1;
681#endif /* not HAVE_MAP_LDAP */
682}
683
684
685static int
686gopt_ldap_hostports(const char *val)
687{
688#ifdef HAVE_MAP_LDAP
689  gopt.ldap_hostports = xstrdup(val);
690  return 0;
691#else /* not HAVE_MAP_LDAP */
692  fprintf(stderr, "conf: ldap_hostports option ignored.  No LDAP support available.\n");
693  return 1;
694#endif /* not HAVE_MAP_LDAP */
695
696}
697
698
699static int
700gopt_ldap_proto_version(const char *val)
701{
702#ifdef HAVE_MAP_LDAP
703  char *end;
704
705  gopt.ldap_proto_version = strtol((char *)val, &end, 10);
706  if (end == val) {
707    fprintf(stderr, "conf: bad ldap_proto_version option: %s\n",val);
708    return 1;
709  }
710
711  if (gopt.ldap_proto_version < 0 || gopt.ldap_proto_version > LDAP_VERSION_MAX) {
712    fprintf(stderr, "conf: bad ldap_proto_version option value: %s\n",val);
713    return 1;
714  }
715  switch (gopt.ldap_proto_version) {
716    /* XXX: what about LDAP_VERSION1? */
717  case LDAP_VERSION2:
718#ifdef LDAP_VERSION3
719  case LDAP_VERSION3:
720#endif /* LDAP_VERSION3 */
721#ifdef LDAP_VERSION4
722  case LDAP_VERSION4:
723#endif /* LDAP_VERSION4 */
724    break;
725  default:
726    fprintf(stderr, "conf: unsupported ldap_proto_version option value: %s\n",val);
727    return 1;
728  }
729  return 0;
730#else /* not HAVE_MAP_LDAP */
731  fprintf(stderr, "conf: ldap_proto_version option ignored.  No LDAP support available.\n");
732  return 1;
733#endif /* not HAVE_MAP_LDAP */
734}
735
736
737static int
738gopt_log_file(const char *val)
739{
740  gopt.logfile = xstrdup(val);
741  return 0;
742}
743
744
745static int
746gopt_log_options(const char *val)
747{
748  usage += switch_option((char *)val);
749  return 0;
750}
751
752
753static int
754gopt_map_defaults(const char *val)
755{
756  gopt.map_defaults = xstrdup(val);
757  return 0;
758}
759
760
761static int
762gopt_map_options(const char *val)
763{
764  gopt.map_options = xstrdup(val);
765  return 0;
766}
767
768
769static int
770gopt_map_reload_interval(const char *val)
771{
772  gopt.map_reload_interval = atoi(val);
773  if (gopt.map_reload_interval <= 0)
774    gopt.map_reload_interval = ONE_HOUR;
775  return 0;
776}
777
778
779static int
780gopt_map_type(const char *val)
781{
782  /* check if map type exist */
783  if (!mapc_type_exists(val)) {
784    fprintf(stderr, "conf: no such map type \"%s\"\n", val);
785    return 1;
786  }
787  gopt.map_type = xstrdup(val);
788  return 0;
789}
790
791
792static int
793gopt_mount_type(const char *val)
794{
795  if (STREQ(val, "autofs")) {
796#ifdef HAVE_FS_AUTOFS
797    gopt.flags |= CFM_MOUNT_TYPE_AUTOFS;
798    amd_use_autofs++;
799    return 0;
800#else /* not HAVE_FS_AUTOFS */
801    fprintf(stderr, "conf: no autofs support available\n");
802    return 1;
803#endif /* not HAVE_FS_AUTOFS */
804  } else if (STREQ(val, "nfs")) {
805    gopt.flags &= ~CFM_MOUNT_TYPE_AUTOFS;
806    return 0;
807  }
808
809  fprintf(stderr, "conf: unknown value to mount_type \"%s\"\n", val);
810  return 1;			/* unknown value */
811}
812
813
814static int
815gopt_portmap_program(const char *val)
816{
817  gopt.portmap_program = atol(val);
818  /*
819   * allow alternate program numbers to be no more than 10 offset from
820   * official amd program number (300019).
821   */
822  if (gopt.portmap_program < AMQ_PROGRAM ||
823      gopt.portmap_program > AMQ_PROGRAM + 10) {
824    gopt.portmap_program = AMQ_PROGRAM;
825    set_amd_program_number(gopt.portmap_program);
826    fprintf(stderr, "conf: illegal amd program number \"%s\"\n", val);
827    return 1;
828  }
829
830  set_amd_program_number(gopt.portmap_program);
831  return 0;			/* all is OK */
832}
833
834
835static int
836gopt_preferred_amq_port(const char *val)
837{
838  gopt.preferred_amq_port = atoi(val);
839
840  /*
841   * No need to check value: preferred_amq_port is an unsigned short and 0
842   * is a valid number, meaning "any port".
843   */
844  return 0;			/* all is OK */
845}
846
847
848static int
849gopt_nfs_allow_any_interface(const char *val)
850{
851  if (STREQ(val, "yes")) {
852    gopt.flags |= CFM_NFS_ANY_INTERFACE;
853    return 0;
854  } else if (STREQ(val, "no")) {
855    gopt.flags &= ~CFM_NFS_ANY_INTERFACE;
856    return 0;
857  }
858
859  fprintf(stderr, "conf: unknown value to nfs_allow_insecure_port \"%s\"\n", val);
860  return 1;			/* unknown value */
861}
862
863
864static int
865gopt_nfs_allow_insecure_port(const char *val)
866{
867  if (STREQ(val, "yes")) {
868    gopt.flags |= CFM_NFS_INSECURE_PORT;
869    return 0;
870  } else if (STREQ(val, "no")) {
871    gopt.flags &= ~CFM_NFS_INSECURE_PORT;
872    return 0;
873  }
874
875  fprintf(stderr, "conf: unknown value to nfs_allow_insecure_port \"%s\"\n", val);
876  return 1;			/* unknown value */
877}
878
879
880static int
881gopt_nfs_proto(const char *val)
882{
883  if (STREQ(val, "udp") || STREQ(val, "tcp")) {
884    gopt.nfs_proto = xstrdup(val);
885    return 0;
886  }
887  fprintf(stderr, "conf: illegal nfs_proto \"%s\"\n", val);
888  return 1;
889}
890
891
892static int
893gopt_nfs_retransmit_counter(const char *val)
894{
895  int i;
896
897  for (i=0; i<AMU_TYPE_MAX; ++i)
898    gopt.amfs_auto_retrans[i] = atoi(val);
899  return 0;
900}
901
902
903static int
904gopt_nfs_retransmit_counter_udp(const char *val)
905{
906  gopt.amfs_auto_retrans[AMU_TYPE_UDP] = atoi(val);
907  return 0;
908}
909
910
911static int
912gopt_nfs_retransmit_counter_tcp(const char *val)
913{
914  gopt.amfs_auto_retrans[AMU_TYPE_TCP] = atoi(val);
915  return 0;
916}
917
918
919static int
920gopt_nfs_retransmit_counter_toplvl(const char *val)
921{
922  gopt.amfs_auto_retrans[AMU_TYPE_TOPLVL] = atoi(val);
923  return 0;
924}
925
926
927static int
928gopt_nfs_retry_interval(const char *val)
929{
930  int i;
931
932  for (i=0; i<AMU_TYPE_MAX; ++i)
933    gopt.amfs_auto_timeo[i] = atoi(val);
934  return 0;
935}
936
937
938static int
939gopt_nfs_retry_interval_udp(const char *val)
940{
941  gopt.amfs_auto_timeo[AMU_TYPE_UDP] = atoi(val);
942  return 0;
943}
944
945
946static int
947gopt_nfs_retry_interval_tcp(const char *val)
948{
949  gopt.amfs_auto_timeo[AMU_TYPE_TCP] = atoi(val);
950  return 0;
951}
952
953
954static int
955gopt_nfs_retry_interval_toplvl(const char *val)
956{
957  gopt.amfs_auto_timeo[AMU_TYPE_TOPLVL] = atoi(val);
958  return 0;
959}
960
961
962static int
963gopt_nfs_vers(const char *val)
964{
965  int i = atoi(val);
966
967  if (i == 2 || i == 3 || i == 4) {
968    gopt.nfs_vers = i;
969    return 0;
970  }
971  fprintf(stderr, "conf: illegal nfs_vers \"%s\"\n", val);
972  return 1;
973}
974
975
976static int
977gopt_nfs_vers_ping(const char *val)
978{
979  int i = atoi(val);
980
981  if (i == 2 || i == 3 || i == 4) {
982    gopt.nfs_vers_ping = i;
983    return 0;
984  }
985  fprintf(stderr, "conf: illegal nfs_vers_ping \"%s\"\n", val);
986  return 1;
987}
988
989static int
990gopt_nis_domain(const char *val)
991{
992#ifdef HAVE_MAP_NIS
993  gopt.nis_domain = xstrdup(val);
994  return 0;
995#else /* not HAVE_MAP_NIS */
996  fprintf(stderr, "conf: nis_domain option ignored.  No NIS support available.\n");
997  return 1;
998#endif /* not HAVE_MAP_NIS */
999}
1000
1001
1002static int
1003gopt_normalize_hostnames(const char *val)
1004{
1005  if (STREQ(val, "yes")) {
1006    gopt.flags |= CFM_NORMALIZE_HOSTNAMES;
1007    return 0;
1008  } else if (STREQ(val, "no")) {
1009    gopt.flags &= ~CFM_NORMALIZE_HOSTNAMES;
1010    return 0;
1011  }
1012
1013  fprintf(stderr, "conf: unknown value to normalize_hostnames \"%s\"\n", val);
1014  return 1;			/* unknown value */
1015}
1016
1017
1018static int
1019gopt_normalize_slashes(const char *val)
1020{
1021  if (STREQ(val, "yes")) {
1022    gopt.flags |= CFM_NORMALIZE_SLASHES;
1023    return 0;
1024  } else if (STREQ(val, "no")) {
1025    gopt.flags &= ~CFM_NORMALIZE_SLASHES;
1026    return 0;
1027  }
1028
1029  fprintf(stderr, "conf: unknown value to normalize_slashes \"%s\"\n", val);
1030  return 1;			/* unknown value */
1031}
1032
1033
1034static int
1035gopt_os(const char *val)
1036{
1037  gopt.op_sys = xstrdup(val);
1038  return 0;
1039}
1040
1041
1042static int
1043gopt_osver(const char *val)
1044{
1045  gopt.op_sys_ver = xstrdup(val);
1046  return 0;
1047}
1048
1049
1050static int
1051gopt_plock(const char *val)
1052{
1053  if (STREQ(val, "yes")) {
1054    gopt.flags |= CFM_PROCESS_LOCK;
1055    return 0;
1056  } else if (STREQ(val, "no")) {
1057    gopt.flags &= ~CFM_PROCESS_LOCK;
1058    return 0;
1059  }
1060
1061  fprintf(stderr, "conf: unknown value to plock \"%s\"\n", val);
1062  return 1;			/* unknown value */
1063}
1064
1065
1066static int
1067gopt_print_pid(const char *val)
1068{
1069  if (STREQ(val, "yes")) {
1070    gopt.flags |= CFM_PRINT_PID;
1071    return 0;
1072  } else if (STREQ(val, "no")) {
1073    gopt.flags &= ~CFM_PRINT_PID;
1074    return 0;
1075  }
1076
1077  fprintf(stderr, "conf: unknown value to print_pid \"%s\"\n", val);
1078  return 1;			/* unknown value */
1079}
1080
1081
1082static int
1083gopt_print_version(const char *val)
1084{
1085  if (STREQ(val, "yes")) {
1086    char *vers = get_version_string();
1087    fputs(vers, stderr);
1088    XFREE(vers);
1089    return 0;
1090  } else if (STREQ(val, "no")) {
1091    return 0;
1092  }
1093
1094  fprintf(stderr, "conf: unknown value to print_version \"%s\"\n", val);
1095  return 1;			/* unknown value */
1096}
1097
1098
1099static int
1100gopt_restart_mounts(const char *val)
1101{
1102  if (STREQ(val, "yes")) {
1103    gopt.flags |= CFM_RESTART_EXISTING_MOUNTS;
1104    return 0;
1105  } else if (STREQ(val, "no")) {
1106    gopt.flags &= ~CFM_RESTART_EXISTING_MOUNTS;
1107    return 0;
1108  }
1109
1110  fprintf(stderr, "conf: unknown value to restart_mounts \"%s\"\n", val);
1111  return 1;			/* unknown value */
1112}
1113
1114
1115static int
1116gopt_search_path(const char *val)
1117{
1118  gopt.search_path = xstrdup(val);
1119  return 0;
1120}
1121
1122
1123static int
1124gopt_selectors_in_defaults(const char *val)
1125{
1126  if (STREQ(val, "yes")) {
1127    gopt.flags |= CFM_SELECTORS_IN_DEFAULTS;
1128    return 0;
1129  } else if (STREQ(val, "no")) {
1130    gopt.flags &= ~CFM_SELECTORS_IN_DEFAULTS;
1131    return 0;
1132  }
1133
1134  fprintf(stderr, "conf: unknown value to enable_default_selectors \"%s\"\n", val);
1135  return 1;			/* unknown value */
1136}
1137
1138
1139static int
1140gopt_show_statfs_entries(const char *val)
1141{
1142  if (STREQ(val, "yes")) {
1143    gopt.flags |= CFM_SHOW_STATFS_ENTRIES;
1144    return 0;
1145  } else if (STREQ(val, "no")) {
1146    gopt.flags &= ~CFM_SHOW_STATFS_ENTRIES;
1147    return 0;
1148  }
1149
1150  fprintf(stderr, "conf: unknown value to show_statfs_entries \"%s\"\n", val);
1151  return 1;			/* unknown value */
1152}
1153
1154
1155static int
1156gopt_sun_map_syntax(const char *val)
1157{
1158  if (STREQ(val, "yes")) {
1159    gopt.flags |= CFM_SUN_MAP_SYNTAX;
1160    return 0;
1161  } else if (STREQ(val, "no")) {
1162    gopt.flags &= ~CFM_SUN_MAP_SYNTAX;
1163    return 0;
1164  }
1165
1166  fprintf(stderr, "conf: unknown value to sun_map_syntax \"%s\"\n", val);
1167  return 1;			/* unknown value */
1168}
1169
1170
1171static int
1172gopt_truncate_log(const char *val)
1173{
1174  if (STREQ(val, "yes")) {
1175    gopt.flags |= CFM_TRUNCATE_LOG;
1176    return 0;
1177  } else if (STREQ(val, "no")) {
1178    gopt.flags &= ~CFM_TRUNCATE_LOG;
1179    return 0;
1180  }
1181
1182  fprintf(stderr, "conf: unknown value to truncate_log \"%s\"\n", val);
1183  return 1;			/* unknown value */
1184}
1185
1186
1187static int
1188gopt_unmount_on_exit(const char *val)
1189{
1190  if (STREQ(val, "yes")) {
1191    gopt.flags |= CFM_UNMOUNT_ON_EXIT;
1192    return 0;
1193  } else if (STREQ(val, "no")) {
1194    gopt.flags &= ~CFM_UNMOUNT_ON_EXIT;
1195    return 0;
1196  }
1197
1198  fprintf(stderr, "conf: unknown value to unmount_on_exit \"%s\"\n", val);
1199  return 1;			/* unknown value */
1200}
1201
1202
1203static int
1204gopt_use_tcpwrappers(const char *val)
1205{
1206#if defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP)
1207  if (STREQ(val, "yes")) {
1208    gopt.flags |= CFM_USE_TCPWRAPPERS;
1209    return 0;
1210  } else if (STREQ(val, "no")) {
1211    gopt.flags &= ~CFM_USE_TCPWRAPPERS;
1212    return 0;
1213  }
1214#else /* not defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP) */
1215    fprintf(stderr, "conf: no tcpd/libwrap support available\n");
1216    return 1;
1217#endif /* not defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP) */
1218
1219  fprintf(stderr, "conf: unknown value to use_tcpwrappers \"%s\"\n", val);
1220  return 1;			/* unknown value */
1221}
1222
1223
1224static int
1225gopt_vendor(const char *val)
1226{
1227  gopt.op_sys_vendor = xstrdup(val);
1228  return 0;
1229}
1230
1231
1232/*
1233 * Collect one entry for a regular map
1234 */
1235static int
1236process_regular_option(const char *section, const char *key, const char *val, cf_map_t *cfm)
1237{
1238  /* ensure that val is valid */
1239  if (!section || section[0] == '\0' ||
1240      !key || key[0] == '\0' ||
1241      !val || val[0] == '\0' ||
1242      !cfm) {
1243    fprintf(stderr, "conf: process_regular_option: null entries\n");
1244    return 1;
1245  }
1246
1247  /* check if initializing a new map */
1248  if (!cfm->cfm_dir)
1249    cfm->cfm_dir = xstrdup(section);
1250
1251  /* check for each possible field */
1252  if (STREQ(key, "browsable_dirs"))
1253    return ropt_browsable_dirs(val, cfm);
1254
1255  if (STREQ(key, "map_name"))
1256    return ropt_map_name(val, cfm);
1257
1258  if (STREQ(key, "map_defaults"))
1259    return ropt_map_defaults(val, cfm);
1260
1261  if (STREQ(key, "map_options"))
1262    return ropt_map_options(val, cfm);
1263
1264  if (STREQ(key, "map_type"))
1265    return ropt_map_type(val, cfm);
1266
1267  if (STREQ(key, "mount_type"))
1268    return ropt_mount_type(val, cfm);
1269
1270  if (STREQ(key, "search_path"))
1271    return ropt_search_path(val, cfm);
1272
1273  if (STREQ(key, "sun_map_syntax"))
1274    return ropt_sun_map_syntax(val, cfm);
1275
1276  if (STREQ(key, "tag"))
1277    return ropt_tag(val, cfm);
1278
1279  fprintf(stderr, "conf: unknown regular key \"%s\" for section \"%s\"\n",
1280	  key, section);
1281  return 1;			/* failed to match any command */
1282}
1283
1284
1285static int
1286ropt_browsable_dirs(const char *val, cf_map_t *cfm)
1287{
1288  if (STREQ(val, "full")) {
1289    cfm->cfm_flags |= CFM_BROWSABLE_DIRS_FULL;
1290    return 0;
1291  } else if (STREQ(val, "yes")) {
1292    cfm->cfm_flags |= CFM_BROWSABLE_DIRS;
1293    return 0;
1294  } else if (STREQ(val, "no")) {
1295    cfm->cfm_flags &= ~CFM_BROWSABLE_DIRS;
1296    return 0;
1297  }
1298
1299  fprintf(stderr, "conf: unknown value to browsable_dirs \"%s\"\n", val);
1300  return 1;			/* unknown value */
1301}
1302
1303
1304static int
1305ropt_map_name(const char *val, cf_map_t *cfm)
1306{
1307  cfm->cfm_name = xstrdup(val);
1308  return 0;
1309}
1310
1311
1312static int
1313ropt_map_defaults(const char *val, cf_map_t *cfm)
1314{
1315  cfm->cfm_defaults = xstrdup(val);
1316  return 0;
1317}
1318
1319
1320static int
1321ropt_map_options(const char *val, cf_map_t *cfm)
1322{
1323  cfm->cfm_opts = xstrdup(val);
1324  return 0;
1325}
1326
1327
1328static int
1329ropt_map_type(const char *val, cf_map_t *cfm)
1330{
1331  /* check if map type exist */
1332  if (!mapc_type_exists(val)) {
1333    fprintf(stderr, "conf: no such map type \"%s\"\n", val);
1334    return 1;
1335  }
1336  cfm->cfm_type = xstrdup(val);
1337  return 0;
1338}
1339
1340
1341static int
1342ropt_mount_type(const char *val, cf_map_t *cfm)
1343{
1344  if (STREQ(val, "autofs")) {
1345#ifdef HAVE_FS_AUTOFS
1346    cfm->cfm_flags |= CFM_MOUNT_TYPE_AUTOFS;
1347    amd_use_autofs++;
1348    return 0;
1349#else /* not HAVE_FS_AUTOFS */
1350    fprintf(stderr, "conf: no autofs support available\n");
1351    return 1;
1352#endif /* not HAVE_FS_AUTOFS */
1353  } else if (STREQ(val, "nfs")) {
1354    cfm->cfm_flags &= ~CFM_MOUNT_TYPE_AUTOFS;
1355    return 0;
1356  }
1357
1358  fprintf(stderr, "conf: unknown value to mount_type \"%s\"\n", val);
1359  return 1;			/* unknown value */
1360}
1361
1362
1363static int
1364ropt_search_path(const char *val, cf_map_t *cfm)
1365{
1366  cfm->cfm_search_path = xstrdup(val);
1367  return 0;
1368}
1369
1370
1371static int
1372ropt_sun_map_syntax(const char *val, cf_map_t *cfm)
1373{
1374  if (STREQ(val, "yes")) {
1375    cfm->cfm_flags |= CFM_SUN_MAP_SYNTAX;
1376    return 0;
1377
1378  } else if (STREQ(val, "no")) {
1379    cfm->cfm_flags &= ~CFM_SUN_MAP_SYNTAX;
1380    return 0;
1381  }
1382
1383  fprintf(stderr, "conf: unknown value to sun_map_syntax \"%s\"\n", val);
1384  return 1;			/* unknown value */
1385}
1386
1387
1388static int
1389ropt_tag(const char *val, cf_map_t *cfm)
1390{
1391  cfm->cfm_tag = xstrdup(val);
1392  return 0;
1393}
1394
1395
1396/*
1397 * Process one collected map.
1398 */
1399static int
1400process_one_regular_map(const cf_map_t *cfm)
1401{
1402  if (!cfm->cfm_name) {
1403    fprintf(stderr, "conf: map_name must be defined for map \"%s\"\n", cfm->cfm_dir);
1404    return 1;
1405  }
1406  /*
1407   * If map has no tag defined, process the map.
1408   * If no conf_tag was set in amd -T, process all untagged entries.
1409   * If a tag is defined, then process it only if it matches the map tag.
1410   */
1411  if (!cfm->cfm_tag ||
1412      (conf_tag && STREQ(cfm->cfm_tag, conf_tag))) {
1413#ifdef DEBUG_CONF
1414    fprintf(stderr, "processing map %s (flags=0x%x)...\n",
1415	    cfm->cfm_dir, cfm->cfm_flags);
1416#endif /* DEBUG_CONF */
1417    root_newmap(cfm->cfm_dir,
1418		cfm->cfm_opts ? cfm->cfm_opts : "",
1419		cfm->cfm_name,
1420		cfm);
1421  } else {
1422    fprintf(stderr, "skipping map %s...\n", cfm->cfm_dir);
1423  }
1424
1425  return 0;
1426}
1427
1428
1429/*
1430 * Process all regular maps in conf file (if any)
1431 */
1432int
1433process_all_regular_maps(void)
1434{
1435  cf_map_t *tmp_map = head_map;
1436
1437  /*
1438   * If the amd.conf file only has a [global] section (pretty useless
1439   * IMHO), there's nothing to process
1440   */
1441  if (!tmp_map)
1442    return 0;
1443
1444  while (tmp_map) {
1445    if (process_one_regular_map(tmp_map) != 0)
1446      return 1;
1447    tmp_map = tmp_map->cfm_next;
1448  }
1449  return 0;
1450}
1451
1452
1453/*
1454 * Find a cf_map_t for a given map name.
1455 * Return NULL if not found.
1456 */
1457cf_map_t *
1458find_cf_map(const char *name)
1459{
1460
1461  cf_map_t *tmp_map = head_map;
1462
1463  if (!tmp_map || !name)
1464    return NULL;
1465
1466  while (tmp_map) {
1467    if (STREQ(tmp_map->cfm_dir, name)) {
1468      return tmp_map;
1469    }
1470    tmp_map = tmp_map->cfm_next;
1471  }
1472  return NULL;
1473}
1474