]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - utils/gssd/gssd_proc.c
Avoid DNS reverse resolution for server names (take 3)
[nfs-utils.git] / utils / gssd / gssd_proc.c
index 698f86ff09589a2f70337396e2658ecb626ccee1..af1844c2d38490e1ccb5c21e2aa45cd34cca376e 100644 (file)
@@ -67,6 +67,7 @@
 #include <errno.h>
 #include <gssapi/gssapi.h>
 #include <netdb.h>
+#include <ctype.h>
 
 #include "gssd.h"
 #include "err_util.h"
@@ -107,6 +108,9 @@ struct pollfd * pollarray;
 
 unsigned long pollsize;  /* the size of pollaray (in pollfd's) */
 
+/* Avoid DNS reverse lookups on server names */
+int avoid_dns = 1;
+
 /*
  * convert a presentation address string to a sockaddr_storage struct. Returns
  * true on success or false on failure.
@@ -165,12 +169,31 @@ addrstr_to_sockaddr(struct sockaddr *sa, const char *node, const char *port)
  * 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)];
+       int                     servername = 0;
+
+       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.
+                */
+               servername = 0;
+               if (strchr(name, '.') && inet_pton(AF_INET, name, buf) == 1)
+                       servername = 1; /* IPv4 */
+               else if (strchr(name, ':') && inet_pton(AF_INET6, name, buf) == 1)
+                       servername = 1; /* or IPv6 */
+
+               if (servername) {
+                       return strdup(name);
+               }
+       }
 
        switch (sa->sa_family) {
        case AF_INET:
@@ -208,7 +231,7 @@ read_service_info(char *info_file_name, char **servicename, char **servername,
                  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 +259,7 @@ read_service_info(char *info_file_name, char **servicename, char **servername,
                   "service: %127s %15s version %15s\n"
                   "address: %127s\n"
                   "protocol: %15s\n",
-                  dummy,
+                  server,
                   service, program, version,
                   address,
                   protoname);
@@ -258,7 +281,7 @@ read_service_info(char *info_file_name, char **servicename, char **servername,
        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;
 
@@ -800,7 +823,8 @@ create_auth_rpc_client(struct clnt_info *clp,
                       CLIENT **clnt_return,
                       AUTH **auth_return,
                       uid_t uid,
-                      int authtype)
+                      int authtype,
+                      gss_cred_id_t cred)
 {
        CLIENT                  *rpc_clnt = NULL;
        struct rpc_gss_sec      sec;
@@ -826,7 +850,7 @@ create_auth_rpc_client(struct clnt_info *clp,
 
        sec.qop = GSS_C_QOP_DEFAULT;
        sec.svc = RPCSEC_GSS_SVC_NONE;
-       sec.cred = GSS_C_NO_CREDENTIAL;
+       sec.cred = cred;
        sec.req_flags = 0;
        if (authtype == AUTHTYPE_KRB5) {
                sec.mech = (gss_OID)&krb5oid;
@@ -951,6 +975,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
        char                    **dirname;
        int                     create_resp = -1;
        int                     err, downcall_err = -EACCES;
+       gss_cred_id_t           gss_cred;
        OM_uint32               maj_stat, min_stat, lifetime_rec;
 
        printerr(1, "handling krb5 upcall (%s)\n", clp->dirname);
@@ -985,15 +1010,20 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
        if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 &&
                                service == NULL)) {
                /* Tell krb5 gss which credentials cache to use */
-               for (dirname = ccachesearch; *dirname != NULL; dirname++) {
+               /* Try first to acquire credentials directly via GSSAPI */
+               err = gssd_acquire_user_cred(uid, &gss_cred);
+               if (!err)
+                       create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
+                                                            AUTHTYPE_KRB5, gss_cred);
+               /* if create_auth_rplc_client fails try the traditional method of
+                * trolling for credentials */
+               for (dirname = ccachesearch; create_resp != 0 && *dirname != NULL; dirname++) {
                        err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname);
                        if (err == -EKEYEXPIRED)
                                downcall_err = -EKEYEXPIRED;
                        else if (!err)
                                create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
-                                                            AUTHTYPE_KRB5);
-                       if (create_resp == 0)
-                               break;
+                                                            AUTHTYPE_KRB5, GSS_C_NO_CREDENTIAL);
                }
        }
        if (create_resp != 0) {
@@ -1019,7 +1049,8 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
                                        gssd_setup_krb5_machine_gss_ccache(*ccname);
                                        if ((create_auth_rpc_client(clp, &rpc_clnt,
                                                                    &auth, uid,
-                                                                   AUTHTYPE_KRB5)) == 0) {
+                                                                   AUTHTYPE_KRB5,
+                                                                   GSS_C_NO_CREDENTIAL)) == 0) {
                                                /* Success! */
                                                success++;
                                                break;
@@ -1066,7 +1097,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
                printerr(1, "WARNING: Failed to inquire context for lifetme "
                            "maj_stat %u\n", maj_stat);
 
-       if (serialize_context_for_kernel(pd.pd_ctx, &token, &krb5oid, NULL)) {
+       if (serialize_context_for_kernel(&pd.pd_ctx, &token, &krb5oid, NULL)) {
                printerr(0, "WARNING: Failed to serialize krb5 context for "
                            "user with uid %d for server %s\n",
                         uid, clp->servername);
@@ -1079,7 +1110,7 @@ out:
        if (token.value)
                free(token.value);
 #ifdef HAVE_AUTHGSS_FREE_PRIVATE_DATA
-       if (pd.pd_ctx_hndl.length != 0)
+       if (pd.pd_ctx_hndl.length != 0 || pd.pd_ctx != 0)
                authgss_free_private_data(&pd);
 #endif
        if (auth)