--- utils/gssd/gss_util.h | 2 ++ utils/gssd/gssd.c | 7 +++++-- utils/gssd/gssd.man | 25 ++++++++++++++++++++++++- utils/gssd/gssd_proc.c | 33 +++++++++++++++++++++++++++++---- 4 files changed, 60 insertions(+), 7 deletions(-) --- nfs-utils-1.2.3.orig/utils/gssd/gss_util.h +++ nfs-utils-1.2.3/utils/gssd/gss_util.h @@ -42,4 +42,6 @@ void pgsserr(char *msg, u_int32_t maj_st const gss_OID mech); int gssd_check_mechs(void); +extern int avoid_dns; + #endif /* _GSS_UTIL_H_ */ --- nfs-utils-1.2.3.orig/utils/gssd/gssd.c +++ nfs-utils-1.2.3/utils/gssd/gssd.c @@ -85,7 +85,7 @@ sig_hup(int signal) static void usage(char *progname) { - fprintf(stderr, "usage: %s [-f] [-M] [-n] [-v] [-r] [-p pipefsdir] [-k keytab] [-d ccachedir] [-t timeout] [-R preferred realm]\n", + fprintf(stderr, "usage: %s [-f] [-M] [-n] [-v] [-r] [-D] [-p pipefsdir] [-k keytab] [-d ccachedir] [-t timeout] [-R preferred realm]\n", progname); exit(1); } @@ -102,7 +102,7 @@ main(int argc, char *argv[]) char *progname; memset(ccachesearch, 0, sizeof(ccachesearch)); - while ((opt = getopt(argc, argv, "fvrmnMp:k:d:t:R:")) != -1) { + while ((opt = getopt(argc, argv, "DfvrmnMp:k:d:t:R:")) != -1) { switch (opt) { case 'f': fg = 1; @@ -143,6 +143,9 @@ main(int argc, char *argv[]) case 'R': preferred_realm = strdup(optarg); break; + case 'D': + avoid_dns = 0; + break; default: usage(argv[0]); break; --- nfs-utils-1.2.3.orig/utils/gssd/gssd.man +++ nfs-utils-1.2.3/utils/gssd/gssd.man @@ -6,7 +6,7 @@ .SH NAME rpc.gssd \- rpcsec_gss daemon .SH SYNOPSIS -.B "rpc.gssd [-f] [-n] [-k keytab] [-p pipefsdir] [-v] [-r] [-d ccachedir]" +.B "rpc.gssd [-f] [-n] [-D] [-k keytab] [-p pipefsdir] [-v] [-r] [-d ccachedir]" .SH DESCRIPTION The rpcsec_gss protocol gives a means of using the gss-api generic security api to provide security for protocols using rpc (in particular, nfs). Before @@ -87,6 +87,29 @@ Increases the verbosity of the output (c If the rpcsec_gss library supports setting debug level, increases the verbosity of the output (can be specified multiple times). .TP +.B \-D +The server name passed to GSSAPI for authentication is normally the +name exactly as requested. e.g. for NFS +it is the server name in the "servername:/path" mount request. Only if this +servername appears to be an IP address or an +unqualified name (no dots) will a reverse DNS lookup +will be performed to get the canoncial server name. + +If +.B \-D +is present, a reverse DNS lookup will +.I always +be used, even if the server name looks like a canonical name. So it +is needed if partially qualified, or non canonical names are regularly +used. + +Using +.B \-D +can introduce a security vulnerability, so it is recommended that +.B \-D +not be used, and that canonical names always be used when requesting +services. +.TP .B -R realm Kerberos tickets from this .I realm --- nfs-utils-1.2.3.orig/utils/gssd/gssd_proc.c +++ nfs-utils-1.2.3/utils/gssd/gssd_proc.c @@ -107,6 +107,9 @@ struct pollfd * pollarray; int pollsize; /* the size of pollaray (in pollfd's) */ +/* Avoid DNS reverse lookups on server names if possible */ +int avoid_dns = 1; + /* * convert a presentation address string to a sockaddr_storage struct. Returns * true on success or false on failure. @@ -165,12 +168,34 @@ addrstr_to_sockaddr(struct sockaddr *sa, * convert a sockaddr to a hostname */ static char * -sockaddr_to_hostname(const struct sockaddr *sa, const char *addr) +get_servername(const char *name, const struct sockaddr *sa, const char *addr) { socklen_t addrlen; int err; char *hostname; char hbuf[NI_MAXHOST]; + unsigned char buf[sizeof(struct in6_addr)]; + + if (avoid_dns) { + /* + * Determine if this is a server name, or an IP address. + * If it is an IP address, do the DNS lookup otherwise + * skip the DNS lookup. + */ + int is_fqdn = 1; + if (strchr(name, '.') == NULL) + is_fqdn = 0; /* local name */ + else if (inet_pton(AF_INET, name, buf) == 1) + is_fqdn = 0; /* IPv4 address */ + else if (inet_pton(AF_INET6, name, buf) == 1) + is_fqdn = 0; /* IPv6 addrss */ + + if (is_fqdn) { + return strdup(name); + } + /* Sorry, cannot avoid dns after all */ + } + switch (sa->sa_family) { case AF_INET: @@ -208,7 +233,7 @@ read_service_info(char *info_file_name, struct sockaddr *addr) { #define INFOBUFLEN 256 char buf[INFOBUFLEN + 1]; - static char dummy[128]; + static char server[128]; int nbytes; static char service[128]; static char address[128]; @@ -236,7 +261,7 @@ read_service_info(char *info_file_name, "service: %127s %15s version %15s\n" "address: %127s\n" "protocol: %15s\n", - dummy, + server, service, program, version, address, protoname); @@ -269,7 +294,7 @@ read_service_info(char *info_file_name, if (!addrstr_to_sockaddr(addr, address, port)) goto fail; - *servername = sockaddr_to_hostname(addr, address); + *servername = get_servername(server, addr, address); if (*servername == NULL) goto fail;