nfs-utils: Enabling TCP wrappers
Subsystems (2)
cover nfs-utils: Enabling TCP wrappers
Recently I was asked to re-enable the TCP wrapper calls, that check the validity of client that communicate with mountd and statd.
It became very apparent this code had not been used in a while and was as a bit broken. So this patch set fixes the logic and tries to make the code scale better.
The commit blobs in the set are relative to the 'tcpwrap' branch in the git://linux-nfs.org/~steved/nfs-utils-exp.git
git tree.
Comments?
steved.
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH 1/3 nfs-utils: Enabling TCP wrappers
commit 0e594fd44041c5c0562ed1dfc19d2c6d5d3ede0f
Author: Steve Dickson <[email protected]> Date: Mon Dec 15 10:52:01 2008 -0500
When clients are define as IP addresses in /etc/hosts.deny, access is allow due to misinterpreting the return value of hosts_ctl(). This patch reworks that logic which closes that hole.
support/misc/tcpwrapper.c +45 -44
@@ -86,6 +86,9 @@ int hosts_ctl(char *daemon, char *name, char *addr, char *user)#define log_client (addr, proc, prog) \ logit(allow_severity, addr, proc, prog, "") +#define ALLOW 1 +#define DENY 0 + int good_client(daemon, addr) char *daemon;
@@ -95,47 +98,44 @@ struct sockaddr_in *addr;char **sp;char *tmpname; -/* Check the IP address first. */ -if (hosts_ctl (daemon,"" ,inet_ntoa (addr->sin_addr),"" )) -return 1 ; - -/* Check the hostname. */ - hp =gethostbyaddr ((const char *) &(addr->sin_addr), -sizeof (addr->sin_addr),AF_INET ); - -if (!hp) -return 0 ; - -/* must make sure the hostent is authorative. */ - tmpname =alloca (strlen (hp->h_name) +1 ); -strcpy (tmpname, hp->h_name); - hp =gethostbyname (tmpname); -if (hp) { -/* now make sure the "addr->sin_addr" is on the list */ +/* First check the address. */ +if (hosts_ctl (daemon,"" ,inet_ntoa (addr->sin_addr),"" ) ==DENY ) +return DENY ; + +/* Now do the hostname lookup */ + hp =gethostbyaddr ((const char *) &(addr->sin_addr), +sizeof (addr->sin_addr),AF_INET ); +if (!hp) +return DENY ;/* never heard of it. misconfigured DNS? */ + +/* Make sure the hostent is authorative. */ + tmpname =strdup (hp->h_name); +if (!tmpname) +return DENY ; + hp =gethostbyname (tmpname); +free (tmpname); +if (!hp) +return DENY ;/* never heard of it. misconfigured DNS? */ + +/* Now make sure the address is on the list */ for (sp = hp->h_addr_list ; *sp ; sp++) { -if (memcmp (*sp, &(addr->sin_addr), hp->h_length)==0 ) -break ; +if (memcmp (*sp, &(addr->sin_addr), hp->h_length) ==0 ) +break ; }if (!*sp) -/* it was a FAKE. */ -return 0 ; - } -else -/* never heard of it. misconfigured DNS? */ -return 0 ; - -/* Check the official name first. */ -if (hosts_ctl (daemon, hp->h_name,"" ,"" )) -return 1 ; - -/* Check aliases. */ -for (sp = hp->h_aliases; *sp ; sp++) { -if (hosts_ctl (daemon, *sp,"" ,"" )) -return 1 ; - } - -/* No match */ -return 0 ; +return DENY ;/* it was a FAKE. */ + +/* Check the official name and address. */ +if (hosts_ctl (daemon, hp->h_name,inet_ntoa (addr->sin_addr),"" ) ==DENY ) +return DENY ; + +/* Now check aliases. */ +for (sp = hp->h_aliases; *sp ; sp++) { +if (hosts_ctl (daemon, *sp,inet_ntoa (addr->sin_addr),"" ) ==DENY ) +return DENY ; + } + +return ALLOW ; }/* check_startup - additional startup code */
@@ -184,12 +184,13 @@ struct sockaddr_in *addr;u_long proc;u_long prog; { -if (!(from_local (addr) ||good_client (daemon, addr))) { -log_bad_host (addr, proc, prog); -return (FALSE); - } -if (verboselog) -log_client (addr, proc, prog); +if (!(from_local (addr) ||good_client (daemon, addr))) { +log_bad_host (addr, proc, prog); +return (FALSE); + } +if (verboselog) +log_client (addr, proc, prog); +return (TRUE); }
PATCH 2/3 nfs-utils: Enabling TCP wrappers
In reply to a message not in the archivecommit 6f970988b390633efbe3629fc2c19109f7cf96a3
Author: Steve Dickson <[email protected]> Date: Mon Dec 15 11:31:45 2008 -0500
Clients IP address and host names are check on every RPC request, to both mountd and statd when TCP wrappers are enabled. To help this process scale better the access rights are stored in a hash table, which are hashed per IP address, RPC program and procudure numbers.
support/misc/tcpwrapper.c +79 -0
@@ -44,6 +44,7 @@#include <pwd.h> #include <sys/types.h> #include <sys/signal.h> +#include <sys/queue.h> #ifdef SYSV40 #include <netinet/in.h> #include <rpc/rpcent.h>
@@ -89,6 +90,76 @@ int hosts_ctl(char *daemon, char *name, char *addr, char *user)#define ALLOW 1#define DENY 0 +typedef struct _haccess_t { +TAILQ_ENTRY (_haccess_t) list; +int access; +struct in_addr addr; +}haccess_t ; + +#define HASH_TABLE_SIZE 1021 +typedef struct _hash_head { + TAILQ_HEAD(host_list, _haccess_t) h_head; +}hash_head ; +hash_head haccess_tbl[HASH_TABLE_SIZE ]; +static haccess_t *haccess_lookup (struct sockaddr_in *addr,u_long ,u_long ); +static void haccess_add (struct sockaddr_in *addr,u_long ,u_long ,int ); + +inline unsigned int strtoint (char *str) +{ +unsigned int n =0 ; +int len =strlen (str); +int i; + +for (i=0 ; i < len; i++) + n+=((int )str[i])*i; + +return n; +} +inline int hashint (unsigned int num) +{ +return num %HASH_TABLE_SIZE ; +} +#define HASH (_addr, _proc, _prog) \ + hashint((strtoint((_addr))+(_proc)+(_prog))) + +void haccess_add (struct sockaddr_in *addr,u_long proc, +u_long prog,int access) +{ +hash_head *head; +haccess_t *hptr; +int hash; + + hptr = (haccess_t *)malloc (sizeof (haccess_t)); +if (hptr ==NULL ) +return ; + + hash =HASH (inet_ntoa (addr->sin_addr), proc, prog); + head = &(haccess_tbl[hash]); + + hptr->access = access; + hptr->addr.s_addr = addr->sin_addr.s_addr; + +if (TAILQ_EMPTY (&head->h_head)) +TAILQ_INSERT_HEAD (&head->h_head, hptr, list); +else +TAILQ_INSERT_TAIL (&head->h_head, hptr, list); +} +haccess_t *haccess_lookup (struct sockaddr_in *addr,u_long proc,u_long prog) +{ +hash_head *head; +haccess_t *hptr; +int hash; + + hash =HASH (inet_ntoa (addr->sin_addr), proc, prog); + head = &(haccess_tbl[hash]); + + TAILQ_FOREACH(hptr, &head->h_head, list) { +if (hptr->addr.s_addr == addr->sin_addr.s_addr) +return hptr; + } +return NULL ; +} + int good_client(daemon, addr) char *daemon;
@@ -184,13 +255,21 @@ struct sockaddr_in *addr;u_long proc;u_long prog; { +haccess_t *acc =NULL ; + + acc =haccess_lookup (addr, proc, prog); +if (acc) +return (acc->access); +if (!(from_local (addr) ||good_client (daemon, addr))) {log_bad_host (addr, proc, prog); +haccess_add (addr, proc, prog, FALSE);return (FALSE); }if (verboselog)log_client (addr, proc, prog); +haccess_add (addr, proc, prog, TRUE);return (TRUE); }
PATCH 3/3 nfs-utils: Enabling TCP wrappers
In reply to a message not in the archivecommit e1956712782b4bb7b4369420bfada972e5bc4398
Author: Steve Dickson <[email protected]> Date: Mon Dec 15 11:44:51 2008 -0500
To ensure the hash table of clients has valid access rights, check the modification times on both access files. If one of them have change, update the hash entry instead of creating a new entry.
support/misc/tcpwrapper.c +40 -3
@@ -45,6 +45,9 @@#include <sys/types.h> #include <sys/signal.h> #include <sys/queue.h> +#include <sys/stat.h> +#include <unistd.h> +#ifdef SYSV40 #include <netinet/in.h> #include <rpc/rpcent.h>
@@ -246,6 +249,33 @@ void check_startup(void) (void )signal (SIGINT , toggle_verboselog); } +/* check_files - check to see if either access files have changed */ + +int check_files () +{ +static time_t allow_mtime, deny_mtime; +struct stat astat, dstat; +int changed =0 ; + +if (stat ("/etc/hosts.allow" , &astat) <0 ) + astat.st_mtime =0 ; +if (stat ("/etc/hosts.deny" , &dstat) <0 ) + dstat.st_mtime =0 ; + +if (!astat.st_mtime || !dstat.st_mtime) +return changed; + +if (astat.st_mtime != allow_mtime) + changed =1 ; +else if (dstat.st_mtime != deny_mtime) + changed =1 ; + + allow_mtime = astat.st_mtime; + deny_mtime = dstat.st_mtime; + +return changed; +} +/* check_default - additional checks for NULL, DUMP, GETPORT and unknown */ int
@@ -256,20 +286,27 @@ u_long proc;u_long prog; {haccess_t *acc =NULL ; +int changed =check_files (); acc =haccess_lookup (addr, proc, prog); -if (acc) +if (acc && changed ==0 )return (acc->access);if (!(from_local (addr) ||good_client (daemon, addr))) {log_bad_host (addr, proc, prog); -haccess_add (addr, proc, prog, FALSE); +if (acc) + acc->access = FALSE; +else +haccess_add (addr, proc, prog, FALSE);return (FALSE); }if (verboselog)log_client (addr, proc, prog); -haccess_add (addr, proc, prog, TRUE); +if (acc) + acc->access = TRUE; +else +haccess_add (addr, proc, prog, TRUE);return (TRUE); }
Quoted 7 lines · Steve Dickson
Recently I was asked to re-enable the TCP wrapper calls, that check the validity of client that communicate with mountd and statd.
It became very apparent this code had not been used in a while and was as a bit broken. So this patch set fixes the logic and tries to make the code scale better.
Quoted 5 lines
The commit blobs in the set are relative to the 'tcpwrap' branch in the
git://linux-nfs.org/~steved/nfs-utils-exp.git
git tree.Comments?
A general comment: This code will need support for IPv6 addresses.
Until it has it, perhaps we should add some logic to configure.ac that prevents the use of tcpwrappers when --enable-ipv6 is in effect.
--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com
Quoted 12 lines · Chuck Lever
Quoted 11 lines · Steve Dickson
Recently I was asked to re-enable the TCP wrapper calls, that check the validity of client that communicate with mountd and statd.
It became very apparent this code had not been used in a while and was as a bit broken. So this patch set fixes the logic and tries to make the code scale better.
The commit blobs in the set are relative to the 'tcpwrap' branch in the
git://linux-nfs.org/~steved/nfs-utils-exp.git
git tree.
Quoted 6 lines
Quoted 1 line
Comments?
A general comment: This code will need support for IPv6 addresses.
Until it has it, perhaps we should add some logic to configure.ac that prevents the use of tcpwrappers when --enable-ipv6 is in effect.
Good point...
steved.
Quoted 5 lines · Chuck Lever
A general comment: This code will need support for IPv6 addresses.
Until it has it, perhaps we should add some logic to configure.ac that prevents the use of tcpwrappers when --enable-ipv6 is in effect.
The following patch does address this concern....
comments?
steved.
commit 5526bb225c745d169c070d392402fc1a569f1d15
Author: Steve Dickson <[email protected]> Date: Thu Dec 18 14:57:52 2008 -0500
Skip the host access check when IPv6 is enabled and its an IPv6 address.
utils/mountd/mount_dispatch.c +19 -0
@@ -12,6 +12,8 @@#include "tcpwrapper.h" #endif +#include <sys/syslog.h> +#include "mountd.h" #include "rpcmisc.h"
@@ -72,12 +74,29 @@ mount_dispatch(struct svc_req *rqstp, SVCXPRT *transp)union mountd_results result;#ifdef HAVE_TCP_WRAPPER +#ifdef IPV6_SUPPORTED +static int once =0 ; + +if (svc_getcaller (transp)->sin_family !=AF_INET ) { +if (!once) { +syslog (LOG_WARNING , +"No IPv6 support in Access Control Library (TCP Wrappers)" ); + once++; + } + goto skipcheck; + } +#endif /* remote host authorization check */ if (!check_default ("mountd" ,svc_getcaller (transp), rqstp->rq_proc,MOUNTPROG )) {svcerr_auth (transp,AUTH_FAILED );return ; } + +#ifdef IPV6_SUPPORTED +skipcheck: +#endif +#endif rpc_dispatch(rqstp, transp, dtable, number_of(dtable),
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 36 lines · Steve Dickson
Quoted 5 lines · Chuck Lever
A general comment: This code will need support for IPv6 addresses.
Until it has it, perhaps we should add some logic to configure.ac that prevents the use of tcpwrappers when --enable-ipv6 is in effect.
The following patch does address this concern....
comments?
steved.
commit
5526bb225c745d169c070d392402fc1a569f1d15Author: Steve Dickson <[email protected]> Date: Thu Dec 18 14:57:52 2008 -0500Skip the host access check when IPv6 is enabled and its an IPv6
address.Signed-off-by Steve Dickson <[email protected]>utils/mountd/mount_dispatch.c +2
-0@@ -12,6 +12,8 @@#include "tcpwrapper.h" #endif +#include <sys/syslog.h> +#include "mountd.h" #include "rpcmisc.h"
utils/mountd/mount_dispatch.c mount_dispatch(struct svc_req *rqstp, SVCXPRT · line 81
Quoted 8 lines
utils/mountd/mount_dispatch.c +4
-0@@ -72,12 +74,29 @@ mount_dispatch(struct svc_req *rqstp, SVCXPRT *transp)union mountd_results result; #ifdef HAVE_TCP_WRAPPER +#ifdef IPV6_SUPPORTED + static int once = 0; + + if (svc_getcaller(transp)->sin_family != AF_INET) {
It's not clear to me that svc_getcaller() will ever return a non-AF_INET address.
Should we use svc_getcaller_netbuf() here instead?
Quoted 23 lines
utils/mountd/mount_dispatch.c +13
-0+if (!once) { +syslog (LOG_WARNING , +"No IPv6 support in Access Control Library (TCP Wrappers)" ); + once++; + } + goto skipcheck; + } +#endif /* remote host authorization check */ if (!check_default ("mountd" ,svc_getcaller (transp), rqstp->rq_proc,MOUNTPROG )) {svcerr_auth (transp,AUTH_FAILED );return ; } + +#ifdef IPV6_SUPPORTED +skipcheck: +#endif +#endif rpc_dispatch(rqstp, transp, dtable,
number_of(dtable),
Signature · 2 lines
Chuck Lever chuck[dot]lever[at]oracle[dot]com
Quoted 13 lines · Chuck Lever
utils/mountd/mount_dispatch.c mount_dispatch(struct svc_req *rqstp, SVCXPRT · line 81
Quoted 9 lines
utils/mountd/mount_dispatch.c +4
-0@@ -72,12 +74,29 @@ mount_dispatch(struct svc_req *rqstp, SVCXPRT *transp)union mountd_results result; #ifdef HAVE_TCP_WRAPPER +#ifdef IPV6_SUPPORTED + static int once = 0; + + if (svc_getcaller(transp)->sin_family != AF_INET) {It's not clear to me that
svc_getcaller()will ever return a non-AF_INET address.
Quoted 1 line
Should we use
svc_getcaller_netbuf()here instead?
I would if I could but there is no svc_getcaller_netbuf() in the glibc version of RPC...
steved.
A message that is not in the archive (sent off-list or not yet received): [email protected]
Hi Steve-
Quoted 14 lines · Steve Dickson
Quoted 13 lines · Chuck Lever
utils/mountd/mount_dispatch.c mount_dispatch(struct svc_req *rqstp, SVCXPRT · line 81
Quoted 9 lines
utils/mountd/mount_dispatch.c +4
-0@@ -72,12 +74,29 @@ mount_dispatch(struct svc_req *rqstp, SVCXPRT *transp)union mountd_results result; #ifdef HAVE_TCP_WRAPPER +#ifdef IPV6_SUPPORTED + static int once = 0; + + if (svc_getcaller(transp)->sin_family != AF_INET) {It's not clear to me that
svc_getcaller()will ever return a non-AF_INET address.
Quoted 3 lines
Quoted 1 line
Should we use
svc_getcaller_netbuf()here instead?I would if I could but there is no
svc_getcaller_netbuf()in the glibc version of RPC...
If IPV6_SUPPORTED is set than libtirpc is required to be available. nfs-utils won't build with --enable-ipv6 if there's no libtirpc.
Signature · 2 lines
Chuck Lever chuck[dot]lever[at]oracle[dot]com
Quoted 17 lines · Chuck Lever
Hi Steve-
Quoted 14 lines · Steve Dickson
Quoted 13 lines · Chuck Lever
utils/mountd/mount_dispatch.c mount_dispatch(struct svc_req *rqstp, SVCXPRT · line 81
Quoted 9 lines
utils/mountd/mount_dispatch.c +4
-0@@ -72,12 +74,29 @@ mount_dispatch(struct svc_req *rqstp, SVCXPRT *transp)union mountd_results result; #ifdef HAVE_TCP_WRAPPER +#ifdef IPV6_SUPPORTED + static int once = 0; + + if (svc_getcaller(transp)->sin_family != AF_INET) {It's not clear to me that
svc_getcaller()will ever return a non-AF_INET address.
Quoted 6 lines
Quoted 3 lines
Quoted 1 line
Should we use
svc_getcaller_netbuf()here instead?I would if I could but there is no
svc_getcaller_netbuf()in the glibc version of RPC...If
IPV6_SUPPORTEDis set than libtirpc is required to be available. nfs-utils won't build with --enable-ipv6 if there's no libtirpc.
Ah... good point! So something like this should work:
sa = (struct sockaddr *)svc_getcaller_netbuf(transp)->buf;
if (sa->sa_family != AF_INET) {
if (!once) {
syslog(LOG_WARNING,
"No IPv6 support in Access Control Library (TCPWrappers)");
once++;
}
goto skipcheck;
}steved.
Quoted 13 lines · Chuck Lever
Review mount_dispatch(struct svc_req *rqstp, SVCXPRT · line 81
Quoted 9 lines
(quoted diff) +4
-0@@ -72,12 +74,29 @@ mount_dispatch(struct svc_req *rqstp, SVCXPRT *transp) union mountd_results result; #ifdef HAVE_TCP_WRAPPER +#ifdef IPV6_SUPPORTED + static int once = 0; + + if (svc_getcaller(transp)->sin_family != AF_INET) {It's not clear to me that
svc_getcaller()will ever return a non-AF_INET address.
Quoted 2 lines
Should we use
svc_getcaller_netbuf()here instead?
Here is the same patch using svc_getcaller_netbuf() instead of svc_getcaller():
comments?
steved.
commit 87aef16ecab0ee3b0744d24b0e257e9d108ff4c0
Author: Steve Dickson <[email protected]> Date: Fri Dec 19 11:58:02 2008 -0500
Skip the host access check when IPv6 is enabled and its an IPv6 address.
utils/mountd/mount_dispatch.c +22 -0
@@ -12,6 +12,8 @@#include "tcpwrapper.h" #endif +#include <sys/syslog.h> +#include "mountd.h" #include "rpcmisc.h"
@@ -72,12 +74,32 @@ mount_dispatch(struct svc_req *rqstp, SVCXPRT *transp)union mountd_results result;#ifdef HAVE_TCP_WRAPPER +#ifdef IPV6_SUPPORTED +struct sockaddr *sa; +static int once =0 ; + + sa = (struct sockaddr *)svc_getcaller_netbuf (transp)->buf; +if (sa->sa_family !=AF_INET ) { +if (!once) { +syslog (LOG_WARNING , +"No IPv6 support in Access Control Library (TCP Wrappers)" ); + once++; + } + goto skipcheck; + } +#endif +/* remote host authorization check */ if (!check_default ("mountd" ,svc_getcaller (transp), rqstp->rq_proc,MOUNTPROG )) {svcerr_auth (transp,AUTH_FAILED );return ; } + +#ifdef IPV6_SUPPORTED +skipcheck: +#endif +#endif rpc_dispatch(rqstp, transp, dtable, number_of(dtable),
utils/statd/statd.c +19 -0
@@ -88,6 +88,21 @@ extern void simulator (int, char **);static void sm_prog_1_wrapper (struct svc_req *rqstp, registerSVCXPRT *transp) { +#ifdef IPV6_SUPPORTED +struct sockaddr *sa; +static int once =0 ; + + sa = (struct sockaddr *)svc_getcaller_netbuf (transp)->buf; +if (sa->sa_family !=AF_INET ) { +if (!once) { +syslog (LOG_WARNING , +"No IPv6 support in Access Control Library (TCP Wrappers)" ); + once++; + } + goto skipcheck; + } +#endif +/* remote host authorization check */ if (!check_default ("statd" ,svc_getcaller (transp), rqstp->rq_proc,SM_PROG )) {
@@ -95,6 +110,10 @@ sm_prog_1_wrapper (struct svc_req *rqstp, register SVCXPRT *transp)return ; } +#ifdef IPV6_SUPPORTED +skipcheck: +#endif +sm_prog_1 (rqstp, transp); }
Quoted 11 lines · Steve Dickson
Recently I was asked to re-enable the TCP wrapper calls, that check the validity of client that communicate with mountd and statd.
It became very apparent this code had not been used in a while and was as a bit broken. So this patch set fixes the logic and tries to make the code scale better.
The commit blobs in the set are relative to the 'tcpwrap' branch in the
git://linux-nfs.org/~steved/nfs-utils-exp.git
git tree.
The three patches have been tested and committed.
Note, it was decided the IPv6 patch (the 4th patch) was not needed.
steved.