Adds support for cifs.resolver upcall.
authorIgor Mammedov <niallain@gmail.com>
Wed, 19 Dec 2007 14:48:43 +0000 (17:48 +0300)
committerSimo Sorce <idra@samba.org>
Wed, 16 Jan 2008 14:51:06 +0000 (09:51 -0500)
Here is a patch for userspace cifs.spnego handler that adds support for cifs.resolver
upcall used in DFS code.
Any comments are appreciated.

#############################

Cifs upcall with key type cifs.resolver is used for resolving
server names in handling DFS refferals.

Signed-off-by: Igor Mammedov <niallain@gmail.com>
source/client/cifs.spnego.c

index caa22276c47b46eb30c1857977207f37ec3b00f0..d10d19da96ad48d05eca436b71c4f4e3c9bc0423 100644 (file)
@@ -3,11 +3,13 @@
 * Copyright (C) Igor Mammedov (niallain@gmail.com) 2007
 *
 * Used by /sbin/request-key for handling
-* cifs upcall for kerberos authorization of access to share.
+* cifs upcall for kerberos authorization of access to share and
+* cifs upcall for DFS srver name resolving (IPv4/IPv6 aware).
 * You should have keyutils installed and add following line to
 * /etc/request-key.conf file
 
 create cifs.spnego * * /usr/local/sbin/cifs.spnego [-v][-c] %k
+create cifs.resolver * * /usr/local/sbin/cifs.spnego [-v] %k
 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
@@ -27,7 +29,7 @@ create cifs.spnego * * /usr/local/sbin/cifs.spnego [-v][-c] %k
 
 #include "cifs_spnego.h"
 
-const char* CIFSSPNEGO_VERSION="1.0";
+const char *CIFSSPNEGO_VERSION = "1.1";
 static const char *prog = "cifs.spnego";
 typedef enum _secType {
        KRB5,
@@ -146,6 +148,58 @@ int decode_key_description(const char *desc, int *ver, secType_t * sec,
        return retval;
 }
 
+int cifs_resolver(const key_serial_t key, const char *key_descr)
+{
+       int c;
+       struct addrinfo *addr;
+       char ip[INET6_ADDRSTRLEN];
+       void *p;
+       const char *keyend = key_descr;
+       /* skip next 4 ';' delimiters to get to description */
+       for (c = 1; c <= 4; c++) {
+               keyend = index(keyend+1, ';');
+               if (!keyend) {
+                       syslog(LOG_WARNING, "invalid key description: %s",
+                                       key_descr);
+                       return 1;
+               }
+       }
+       keyend++;
+
+       /* resolve name to ip */
+       c = getaddrinfo(keyend, NULL, NULL, &addr);
+       if (c) {
+               syslog(LOG_WARNING, "unable to resolve hostname: %s [%s]",
+                               keyend, gai_strerror(c));
+               return 1;
+       }
+
+       /* conver ip to string form */
+       if (addr->ai_family == AF_INET) {
+               p = &(((struct sockaddr_in *)addr->ai_addr)->sin_addr);
+       } else {
+               p = &(((struct sockaddr_in6 *)addr->ai_addr)->sin6_addr);
+       }
+       if (!inet_ntop(addr->ai_family, p, ip, sizeof(ip))) {
+               syslog(LOG_WARNING, "%s: inet_ntop: %s",
+                               __FUNCTION__, strerror(errno));
+               freeaddrinfo(addr);
+               return 1;
+       }
+
+       /* setup key */
+       c = keyctl_instantiate(key, ip, strlen(ip)+1, 0);
+       if (c == -1) {
+               syslog(LOG_WARNING, "%s: keyctl_instantiate: %s",
+                               __FUNCTION__, strerror(errno));
+               freeaddrinfo(addr);
+               return 1;
+       }
+
+       freeaddrinfo(addr);
+       return 0;
+}
+
 int main(const int argc, char *const argv[])
 {
        struct cifs_spnego_msg *keydata = NULL;
@@ -199,6 +253,11 @@ int main(const int argc, char *const argv[])
                goto out;
        }
 
+       if (strncmp(buf, "cifs.resolver", sizeof("cifs.resolver")-1) == 0) {
+               rc = cifs_resolver(key, buf);
+               goto out;
+       }
+
        rc = decode_key_description(buf, &kernel_upcall_version, &sectype,
                                    &hostname, &uid);
        if ((rc & DKD_MUSTHAVE_SET) != DKD_MUSTHAVE_SET) {