From 75cfca58f7c31171c2d8c2d60a6824b20a423e51 Mon Sep 17 00:00:00 2001 From: Erez Zadok Date: Fri, 21 Apr 2006 01:11:50 +0000 Subject: [PATCH] * scripts/amd.conf-sample, scripts/amd.conf.5, doc/am-utils.texi, NEWS: document new nfs_allow_any_interface parameter. * include/am_compat.h (INADDR_LOOPBACK): define INADDR_LOOPBACK if not defined, since some systems don't have it. * libamu/wire.c (is_interface_local): new boolena function to determine if address represents any of the local interfaces. (getwire): more properly check if address equals INADDR_LOOPBACK, not if IFF_LOOPBACK is not (the latter isn't as correct). * include/am_utils.h: extern for new is_interface_local() function. * conf/transp/transp_{sockets,tli}.c: don't define INADDR_LOOPBACK here but in am_compat.h * amd/nfs_prot_svc.c (nfs_program_2): if nfs_allow_any_interface=yes, then allow NFS packets from any local interface (not just 127.0.0.1). * amd/conf.c (gopt_nfs_allow_any_interface): implement the new amd.conf parameter nfs_allow_any_interface. * amd/amd.h (CFM_NFS_ANY_INTERFACE): define new global flag when al interfaces are acceptable for local NFS packets. --- ChangeLog | 30 ++++++++++++++++++++++++++++++ NEWS | 7 +++++++ amd/amd.h | 1 + amd/conf.c | 18 ++++++++++++++++++ amd/nfs_prot_svc.c | 20 ++++++++++++++------ conf/transp/transp_sockets.c | 6 ------ conf/transp/transp_tli.c | 4 ---- doc/am-utils.texi | 34 ++++++++++++++++++++++++---------- include/am_compat.h | 4 ++++ include/am_utils.h | 1 + libamu/wire.c | 28 ++++++++++++++++++++++------ scripts/amd.conf-sample | 4 +++- scripts/amd.conf.5 | 20 ++++++++++++++------ 13 files changed, 138 insertions(+), 39 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1e991f1..699561c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,33 @@ +2006-04-20 Erez Zadok + + * scripts/amd.conf-sample, scripts/amd.conf.5, doc/am-utils.texi, + NEWS: document new nfs_allow_any_interface parameter. + + * include/am_compat.h (INADDR_LOOPBACK): define INADDR_LOOPBACK if + not defined, since some systems don't have it. + +2006-04-20 Nick Williams + + * libamu/wire.c (is_interface_local): new boolena function to + determine if address represents any of the local interfaces. + (getwire): more properly check if address equals INADDR_LOOPBACK, + not if IFF_LOOPBACK is not (the latter isn't as correct). + + * include/am_utils.h: extern for new is_interface_local() function. + + * conf/transp/transp_{sockets,tli}.c: don't define INADDR_LOOPBACK + here but in am_compat.h + + * amd/nfs_prot_svc.c (nfs_program_2): if + nfs_allow_any_interface=yes, then allow NFS packets from any local + interface (not just 127.0.0.1). + + * amd/conf.c (gopt_nfs_allow_any_interface): implement the new + amd.conf parameter nfs_allow_any_interface. + + * amd/amd.h (CFM_NFS_ANY_INTERFACE): define new global flag when + al interfaces are acceptable for local NFS packets. + 2006-04-18 Christos Zoulas * amd/opts.c: Add support for optionally specifying the hostname diff --git a/NEWS b/NEWS index eed764f..5e79dda 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,12 @@ *** Notes specific to am-utils version 6.2a2 +New amd.conf global parameter: nfs_allow_any_interface. By default it is +set to 'no' which means that Amd accepts local NFS packets only from +127.0.0.1. If set to 'yes' then Amd will accept local NFS packets from any +local interface; this is useful on hosts that may have multiple interfaces +where the system is forced to send all outgoing packets (even those bound to +the same host) via an address other than 127.0.0.1. + Add support for specifying the host to match in the mount selectors netgrp and netgrpd. Now one can use either netgrp() or netgrp(,). diff --git a/amd/amd.h b/amd/amd.h index 1f090cd..127e37e 100644 --- a/amd/amd.h +++ b/amd/amd.h @@ -80,6 +80,7 @@ #define CFM_FORCED_UNMOUNTS 0x00010000 /* forced unmounts? */ #define CFM_TRUNCATE_LOG 0x00020000 /* truncate log file? */ #define CFM_SUN_MAP_SYNTAX 0x00040000 /* Sun map syntax? */ +#define CFM_NFS_ANY_INTERFACE 0x00080000 /* all interfaces are acceptable */ /* defaults global flags: plock, tcpwrappers, and autofs/lofs */ #define CFM_DEFAULT_FLAGS (CFM_PROCESS_LOCK|CFM_USE_TCPWRAPPERS|CFM_AUTOFS_USE_LOFS|CFM_DOMAIN_STRIP|CFM_NORMALIZE_SLASHES) diff --git a/amd/conf.c b/amd/conf.c index 7b002a6..b5e3536 100644 --- a/amd/conf.c +++ b/amd/conf.c @@ -108,6 +108,7 @@ static int gopt_mount_type(const char *val); static int gopt_pid_file(const char *val); static int gopt_portmap_program(const char *val); static int gopt_preferred_amq_port(const char *val); +static int gopt_nfs_allow_any_interface(const char *val); static int gopt_nfs_allow_insecure_port(const char *val); static int gopt_nfs_proto(const char *val); static int gopt_nfs_retransmit_counter(const char *val); @@ -191,6 +192,7 @@ static struct _func_map glob_functable[] = { {"pid_file", gopt_pid_file}, {"portmap_program", gopt_portmap_program}, {"preferred_amq_port", gopt_preferred_amq_port}, + {"nfs_allow_any_interface", gopt_nfs_allow_any_interface}, {"nfs_allow_insecure_port", gopt_nfs_allow_insecure_port}, {"nfs_proto", gopt_nfs_proto}, {"nfs_retransmit_counter", gopt_nfs_retransmit_counter}, @@ -830,6 +832,22 @@ gopt_preferred_amq_port(const char *val) } +static int +gopt_nfs_allow_any_interface(const char *val) +{ + if (STREQ(val, "yes")) { + gopt.flags |= CFM_NFS_ANY_INTERFACE; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_NFS_ANY_INTERFACE; + return 0; + } + + fprintf(stderr, "conf: unknown value to nfs_allow_insecure_port \"%s\"\n", val); + return 1; /* unknown value */ +} + + static int gopt_nfs_allow_insecure_port(const char *val) { diff --git a/amd/nfs_prot_svc.c b/amd/nfs_prot_svc.c index 105aac5..0dd6992 100644 --- a/amd/nfs_prot_svc.c +++ b/amd/nfs_prot_svc.c @@ -133,12 +133,20 @@ nfs_program_2(struct svc_req *rqstp, SVCXPRT *transp) } # endif /* MNT2_NFS_OPT_RESVPORT */ /* if the address does not match, ignore the request */ - if (sinp && sinp->sin_addr.s_addr != myipaddr.s_addr) { - plog(XLOG_WARNING, "ignoring request from %s:%u, expected %s", - inet_dquad(dq, sizeof(dq), sinp->sin_addr.s_addr), - ntohs(sinp->sin_port), - inet_dquad(dq2, sizeof(dq2), myipaddr.s_addr)); - return; + if (sinp && (sinp->sin_addr.s_addr != myipaddr.s_addr)) { + if (gopt.flags & CFM_NFS_ANY_INTERFACE) { + if (!is_interface_local(sinp->sin_addr.s_addr)) { + plog(XLOG_WARNING, "ignoring request from %s:%u, not a local interface", + inet_dquad(dq, sizeof(dq), sinp->sin_addr.s_addr), + ntohs(sinp->sin_port)); + } + } else { + plog(XLOG_WARNING, "ignoring request from %s:%u, expected %s", + inet_dquad(dq, sizeof(dq), sinp->sin_addr.s_addr), + ntohs(sinp->sin_port), + inet_dquad(dq2, sizeof(dq2), myipaddr.s_addr)); + return; + } } #endif /* not HAVE_TRANPORT_TYPE_TLI */ diff --git a/conf/transp/transp_sockets.c b/conf/transp/transp_sockets.c index 53e1648..36ef2e3 100644 --- a/conf/transp/transp_sockets.c +++ b/conf/transp/transp_sockets.c @@ -50,12 +50,6 @@ #include -/* provide a definition for systems that don't have this */ -#ifndef INADDR_LOOPBACK -# define INADDR_LOOPBACK 0x7f000001 -#endif /* not INADDR_LOOPBACK */ - - /* * find the IP address that can be used to connect to the local host */ diff --git a/conf/transp/transp_tli.c b/conf/transp/transp_tli.c index 09d829f..0cf5f2b 100644 --- a/conf/transp/transp_tli.c +++ b/conf/transp/transp_tli.c @@ -51,10 +51,6 @@ struct netconfig *nfsncp; -/* provide a definition for systems that don't have this */ -#ifndef INADDR_LOOPBACK -# define INADDR_LOOPBACK 0x7f000001 -#endif /* not INADDR_LOOPBACK */ /* * find the IP address that can be used to connect to the local host diff --git a/doc/am-utils.texi b/doc/am-utils.texi index 398df95..e72fd88 100644 --- a/doc/am-utils.texi +++ b/doc/am-utils.texi @@ -4397,6 +4397,7 @@ The following parameters are applicable to the @samp{[global]} section only. * log_file Parameter:: * log_options Parameter:: * map_reload_interval Parameter:: +* nfs_allow_any_interface Parameter:: * nfs_allow_insecure_port Parameter:: * nfs_proto Parameter:: * nfs_retransmit_counter Parameter:: @@ -4823,7 +4824,7 @@ warnings @end table @c ---------------------------------------------------------------- -@node map_reload_interval Parameter, nfs_allow_insecure_port Parameter, log_options Parameter, Global Parameters +@node map_reload_interval Parameter, nfs_allow_any_interface Parameter, log_options Parameter, Global Parameters @comment node-name, next, previous, up @subsection @t{map_reload_interval} Parameter @cindex map_reload_interval Parameter @@ -4834,21 +4835,34 @@ wait before it checks to see if any maps have changed at their source those maps that have changed. @c ---------------------------------------------------------------- -@node nfs_allow_insecure_port Parameter, nfs_proto Parameter, map_reload_interval Parameter, Global Parameters +@node nfs_allow_any_interface Parameter, nfs_allow_insecure_port Parameter, map_reload_interval Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{nfs_allow_any_interface} Parameter +@cindex nfs_allow_any_interface Parameter + +(type=string, default=@samp{no}). Normally @i{Amd} accepts local NFS +packets only from 127.0.0.1. If this parameter is set to @samp{yes}, +then @i{amd} will accept local NFS packets from any local interface; +this is useful on hosts that may have multiple interfaces where the +system is forced to send all outgoing packets (even those bound to the +same host) via an address other than 127.0.0.1. + +@c ---------------------------------------------------------------- +@node nfs_allow_insecure_port Parameter, nfs_proto Parameter, nfs_allow_any_interface Parameter, Global Parameters @comment node-name, next, previous, up @subsection @t{nfs_allow_insecure_port} Parameter @cindex nfs_allow_insecure_port Parameter -(type=string, default=@samp{no}). Normally amd will refuse requests -coming from unprivileged ports (i.e. ports >= 1024 on Unix systems), +(type=string, default=@samp{no}). Normally @i{Amd} will refuse requests +coming from unprivileged ports (i.e., ports >= 1024 on Unix systems), so that only privileged users and the kernel can send NFS requests to -it. However, some kernels (certain versions of Darwin, MacOS X, and +it. However, some kernels (certain versions of Darwin, MacOS X, and Linux) have bugs that cause them to use unprivileged ports in certain -situations, which causes amd to stop dead in its tracks. This -parameter allows amd to operate normally even on such systems, at the -expense of a slight decrease in the security of its operations. If you -see messages like ``ignoring request from foo:1234, port not -reserved'' in your amd log, try enabling this parameter and give it +situations, which causes @i{Amd} to stop dead in its tracks. This +parameter allows @i{Amd} to operate normally even on such systems, at the +expense of a slight decrease in the security of its operations. If +you see messages like ``ignoring request from foo:1234, port not +reserved'' in your @i{Amd} log, try enabling this parameter and give it another go. @c ---------------------------------------------------------------- diff --git a/include/am_compat.h b/include/am_compat.h index 99401d1..dc3b71d 100644 --- a/include/am_compat.h +++ b/include/am_compat.h @@ -385,5 +385,9 @@ struct netconfig { #ifndef INADDR_NONE # define INADDR_NONE 0xffffffffU #endif /* INADDR_NONE */ +/* some OSs don't define INADDR_LOOPBACK */ +#ifndef INADDR_LOOPBACK +# define INADDR_LOOPBACK 0x7f000001 +#endif /* not INADDR_LOOPBACK */ #endif /* not _AM_COMPAT_H */ diff --git a/include/am_utils.h b/include/am_utils.h index 355c55c..3caadd5 100644 --- a/include/am_utils.h +++ b/include/am_utils.h @@ -298,6 +298,7 @@ extern char *hasmntstr(mntent_t *, char *); extern char *hasmnteq(mntent_t *, char *); extern char *haseq(char *); extern int is_network_member(const char *net); +extern int is_interface_local(u_long); extern int islocalnet(u_long); extern int make_rpc_packet(char *, int, u_long, struct rpc_msg *, voidp, XDRPROC_T_TYPE, AUTH *); extern int mkdirs(char *, int); diff --git a/libamu/wire.c b/libamu/wire.c index b760043..c1852cd 100644 --- a/libamu/wire.c +++ b/libamu/wire.c @@ -357,6 +357,24 @@ is_network_member(const char *net) } +/* + * Determine whether a IP address (netnum) is one of the local interfaces, + * returns TRUE/FALSE. + * Does not include the loopback interface: caller needs to check that. + */ +int +is_interface_local(u_long netnum) +{ + addrlist *al; + + for (al = localnets; al; al = al->ip_next) { + if (al->ip_addr == netnum) + return TRUE; + } + return FALSE; +} + + #ifdef HAVE_GETIFADDRS void getwire(char **name1, char **number1) @@ -384,10 +402,10 @@ getwire(char **name1, char **number1) continue; /* - * If the interface is a loopback, or its not running + * If the interface is the loopback, or it's not running, * then ignore it. */ - if ((ifap->ifa_flags & IFF_LOOPBACK) != 0) + if (S2IN(ifap->ifa_addr) == htonl(INADDR_LOOPBACK)) continue; if ((ifap->ifa_flags & IFF_RUNNING) == 0) continue; @@ -501,13 +519,11 @@ getwire(char **name1, char **number1) continue; /* - * If the interface is a loopback, or its not running + * If the interface is the loopback, or it's not running, * then ignore it. */ -#ifdef IFF_LOOPBACK - if ((ifr->ifr_flags & IFF_LOOPBACK) != 0) + if (address == htonl(INADDR_LOOPBACK)) continue; -#endif /* IFF_LOOPBACK */ /* * Fix for 0.0.0.0 loopback on SunOS 3.X which defines IFF_ROUTE * instead of IFF_LOOPBACK. diff --git a/scripts/amd.conf-sample b/scripts/amd.conf-sample index 76ff7c2..4d96578 100644 --- a/scripts/amd.conf-sample +++ b/scripts/amd.conf-sample @@ -97,7 +97,9 @@ nfs_proto = udp | tcp # perform Amq service checks via tcpwrappers (tcpd/libwrap) use_tcpwrappers = yes | no # allow NFS requests from insecure (>=1024) ports -nfs_allow_insecure_port = yes | no +nfs_allow_insecure_port = no | yes +# accept local NFS packets from any local interface, not just 127.0.0.1 +nfs_allow_any_interface = no | yes # address used for local NFS mount and RPC server (default to localhost) localhost_address = foo.example.com | 192.168.1.2 # number of seconds to timeout before map returns output diff --git a/scripts/amd.conf.5 b/scripts/amd.conf.5 index 76c38c7..2009d3b 100644 --- a/scripts/amd.conf.5 +++ b/scripts/amd.conf.5 @@ -443,17 +443,25 @@ The number of seconds that Amd will wait before it checks to see if any maps have changed at their source (NIS servers, LDAP servers, files, etc.). Amd will reload only those maps that have changed. +.TP +.BR nfs_allow_any_interface " (string, default=no)" +Normally Amd accepts local NFS packets only from 127.0.0.1. If this +parameter is set to "yes" then Amd will accept local NFS packets from any +local interface; this is useful on hosts that may have multiple interfaces +where the system is forced to send all outgoing packets (even those bound to +the same host) via an address other than 127.0.0.1. + .TP .BR nfs_allow_insecure_port " (string, default=no)" Normally Amd will refuse requests coming from unprivileged ports (i.e. ports >= 1024 on Unix systems), so that only privileged users and the kernel -can send NFS requests to it. However, some kernels (certain versions of +can send NFS requests to it. However, some kernels (certain versions of Darwin, MacOS X, and Linux) have bugs that cause them to use unprivileged -ports in certain situations, which causes Amd to stop dead in its -tracks. This parameter allows Amd to operate normally even on such systems, -at the expense of a slight decrease in the security of its operations. If -you see messages like "ignoring request from foo:1234, port not reserved" -in your Amd log, try enabling this parameter and give it another go. +ports in certain situations, which causes Amd to stop dead in its tracks. +This parameter allows Amd to operate normally even on such systems, at the +expense of a slight decrease in the security of its operations. If you see +messages like "ignoring request from foo:1234, port not reserved" in your +Amd log, try enabling this parameter and give it another go. .TP .BR nfs_proto " (string, default to trying version tcp then udp)" -- 2.34.1