[SCM] Samba Shared Repository - branch v3-3-test updated

Karolin Seeger kseeger at samba.org
Fri Oct 16 07:05:35 MDT 2009


The branch, v3-3-test has been updated
       via  6eacb25... cifs.upcall: do a brute-force search for KRB5 credcache
       via  6aa0f05... cifs.upcall: make using ip address conditional on new option
       via  8fed5de... cifs.upcall: switch to getopt_long
       via  177e543... cifs.upcall: fix IPv6 addrs sent to upcall to have colon delimiters
       via  ff1b2c8... cifs.upcall: use ip address passed by kernel to get server's hostname
       via  fe57399... cifs.upcall: clean up flag handling
       via  e919c3a... cifs.upcall: try getting a "cifs/" principal and fall back to "host/"
       via  0b516e8... cifs.upcall: declare a structure for holding decoded args
       via  56de963... cifs.upcall: formatting cleanup
       via  e9b932b... cifs.upcall: clean up logging and add debug messages
       via  223bee1... Attempt to fix the build -- jlayton, please check!
       via  9ecd9e7... cifs.upcall: use pid value from kernel to determine KRB5CCNAME to use
      from  96b600d... s3:winbind: Fix bug 6793 -- segfault in winbindd_pam_auth

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-3-test


- Log -----------------------------------------------------------------
commit 6eacb25d736d47e1b4572aec5a143b15fbed619e
Author: Jeff Layton <jlayton at redhat.com>
Date:   Wed Oct 14 11:06:23 2009 -0400

    cifs.upcall: do a brute-force search for KRB5 credcache
    
    A few weeks ago, I added some code to cifs.upcall to take the pid sent
    by the kernel and use that to get the value of the $KRB5CCNAME
    environment var for the process. That works fine on the initial mount,
    but could be problematic on reconnect.
    
    There's no guarantee on a reconnect that the process that initiates the
    upcall will have $KRB5CCNAME pointed at the correct credcache. Because
    of this, the current scheme isn't going to be reliable enough and we
    need to use something different.
    
    This patch replaces that scheme with one very similar to the one used by
    rpc.gssd in nfs-utils. It searches the credcache dir (currently
    hardcoded to /tmp) for a valid credcache for the given uid. If it finds
    one then it uses that as the credentials cache. If it finds more than
    one, it uses the one with the latest TGT expiration.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>
    
    Addresses bug #6810.

commit 6aa0f05509ec1b8578021051f83627f4ca296ef8
Author: Jeff Layton <jlayton at redhat.com>
Date:   Wed Oct 14 11:06:21 2009 -0400

    cifs.upcall: make using ip address conditional on new option
    
    Igor Mammedov pointed out that reverse resolving an IP address to get
    the hostname portion of a principal could open a possible attack
    vector. If an attacker were to gain control of DNS, then he could
    redirect the mount to a server of his choosing, and fix the reverse
    resolution to point to a hostname of his choosing (one where he has
    the key for the corresponding cifs/ or host/ principal).
    
    That said, we often trust DNS for other reasons and it can be useful
    to do so. Make the code that allows trusting DNS to be enabled by
    adding --trust-dns to the cifs.upcall invocation.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

commit 8fed5de25979654baf1c62b0346c725b9c6b6866
Author: Jeff Layton <jlayton at redhat.com>
Date:   Wed Oct 14 11:06:20 2009 -0400

    cifs.upcall: switch to getopt_long
    
    ...to allow long option names.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

commit 177e5437a75267fdfce8ba693f039a10344e5974
Author: Jeff Layton <jlayton at redhat.com>
Date:   Wed Oct 14 11:06:19 2009 -0400

    cifs.upcall: fix IPv6 addrs sent to upcall to have colon delimiters
    
    Current kernels don't send IPv6 addresses with the colon delimiters, add
    a routine to add them when they're not present.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

commit ff1b2c8725e21ed7fc944020a1c1cc12a80a9bec
Author: Jeff Layton <jlayton at redhat.com>
Date:   Wed Oct 14 11:06:18 2009 -0400

    cifs.upcall: use ip address passed by kernel to get server's hostname
    
    Instead of using the hostname given by the upcall to get the server's
    principal, take the IP address given in the upcall and reverse resolve
    it to a hostname.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

commit fe57399ac4ddbdc601871579478b996cfc85fcee
Author: Jeff Layton <jlayton at redhat.com>
Date:   Wed Oct 14 11:04:58 2009 -0400

    cifs.upcall: clean up flag handling
    
    Add a new stack var to hold the flags returned by the decoder routine
    so that we don't need to worry so much about preserving "rc".
    
    With this, we can drop privs before trying to find the location of
    the credcache.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

commit e919c3ac1229eae35614b92a9daebc71e770ca1b
Author: Jeff Layton <jlayton at redhat.com>
Date:   Wed Oct 14 11:04:56 2009 -0400

    cifs.upcall: try getting a "cifs/" principal and fall back to "host/"
    
    cifs.upcall takes a "-c" flag that tells the upcall to get a principal
    in the form of "cifs/hostname.example.com at REALM" instead of
    "host/hostname.example.com at REALM". This has turned out to be a source of
    great confusion for users.
    
    Instead of requiring this flag, have the upcall try to get a "cifs/"
    principal first. If that fails, fall back to getting a "host/"
    principal.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

commit 0b516e8e9e5b1c4b2ab32b27c37ec708d6afd5d2
Author: Jeff Layton <jlayton at redhat.com>
Date:   Wed Oct 14 11:04:55 2009 -0400

    cifs.upcall: declare a structure for holding decoded args
    
    The argument list for the decoder is becoming rather long. Declare an
    args structure and use that for holding the args. This also simplifies
    pointer handling a bit.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

commit 56de963329bed9a06d27d70dad1d6a21f5f9213a
Author: Jeff Layton <jlayton at redhat.com>
Date:   Wed Oct 14 11:04:54 2009 -0400

    cifs.upcall: formatting cleanup
    
    Clean up some unneeded curly braces, and fix some indentation.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

commit e9b932b242cac1061a19da9421b515cacf6c631b
Author: Jeff Layton <jlayton at redhat.com>
Date:   Wed Oct 14 11:04:53 2009 -0400

    cifs.upcall: clean up logging and add debug messages
    
    Change the log levels to be more appropriate to the messages being
    logged. Error messages should be LOG_ERR and not LOG_WARNING, for
    instance.
    
    Add some LOG_DEBUG messages that we can use to diagnose problems with
    krb5 upcalls. With these, someone can set up syslog to log daemon.debug
    and should be able to get more info when things aren't working.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

commit 223bee1fc5f655adb61db603a5423c8bf4a5f582
Author: Volker Lendecke <vl at samba.org>
Date:   Wed Oct 14 11:04:52 2009 -0400

    Attempt to fix the build -- jlayton, please check!

commit 9ecd9e7dbd6f5f6a07614084207b4891a93ca79b
Author: Jeff Layton <jlayton at redhat.com>
Date:   Wed Oct 14 11:04:50 2009 -0400

    cifs.upcall: use pid value from kernel to determine KRB5CCNAME to use
    
    If the kernel sends the upcall a pid of the requesting process, we can
    open that process' /proc/<pid>/environ file and scrape the KRB5CCNAME
    value out of it.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

-----------------------------------------------------------------------

Summary of changes:
 docs-xml/manpages-3/cifs.upcall.8.xml |   19 +-
 source/client/cifs.upcall.c           |  488 +++++++++++++++++++++++++--------
 2 files changed, 386 insertions(+), 121 deletions(-)


Changeset truncated at 500 lines:

diff --git a/docs-xml/manpages-3/cifs.upcall.8.xml b/docs-xml/manpages-3/cifs.upcall.8.xml
index 9782987..a60dd9d 100644
--- a/docs-xml/manpages-3/cifs.upcall.8.xml
+++ b/docs-xml/manpages-3/cifs.upcall.8.xml
@@ -19,8 +19,8 @@
 <refsynopsisdiv>
         <cmdsynopsis>
                 <command>cifs.upcall</command>
-                <arg choice="opt">-c</arg>
-                <arg choice="opt">-v</arg>
+                <arg choice="opt">--trust-dns|-t</arg>
+                <arg choice="opt">--version|-v</arg>
                 <arg choice="req">keyid</arg>
         </cmdsynopsis>
 </refsynopsisdiv>
@@ -48,12 +48,17 @@ to be run that way.</para>
 	<variablelist>
 		<varlistentry>
 		<term>-c</term>
-		<listitem><para>When handling a kerberos upcall, use a service principal that starts with "cifs/". The default is to use the "host/" service principal.
+		<listitem><para>This option is deprecated and is currently ignored.
+		</para></listitem>
+		</varlistentry>
+		<varlistentry>
+		<term>--trust-dns|-t</term>
+		<listitem><para>With krb5 upcalls, the name used as the host portion of the service principal defaults to the hostname portion of the UNC. This option allows the upcall program to reverse resolve the network address of the server in order to get the hostname.</para>
+		<para>This is less secure than not trusting DNS. When using this option, it's possible that an attacker could get control of DNS and trick the client into mounting a different server altogether. It's preferable to instead add server principals to the KDC for every possible hostname, but this option exists for cases where that isn't possible. The default is to not trust reverse hostname lookups in this fashion.
 		</para></listitem>
 		</varlistentry>
-
 		<varlistentry>
-		<term>-v</term>
+		<term>--version|-v</term>
 		<listitem><para>Print version number and exit.
 		</para></listitem>
 		</varlistentry>
@@ -85,8 +90,8 @@ to be run that way.</para>
 	<para>To make this program useful for CIFS, you'll need to set up entries for them in request-key.conf<manvolnum>5</manvolnum>. Here's an example of an entry for each key type:</para>
 <programlisting>
 #OPERATION  TYPE           D C PROGRAM ARG1 ARG2...
-#=========  =============  = = ==========================================
-create	    cifs.spnego    * * /usr/local/sbin/cifs.upcall -c %k
+#=========  =============  = = ================================
+create      cifs.spnego    * * /usr/local/sbin/cifs.upcall %k
 create      dns_resolver   * * /usr/local/sbin/cifs.upcall %k
 </programlisting>
 <para>
diff --git a/source/client/cifs.upcall.c b/source/client/cifs.upcall.c
index 4110de3..71e60c6 100644
--- a/source/client/cifs.upcall.c
+++ b/source/client/cifs.upcall.c
@@ -1,6 +1,7 @@
 /*
 * CIFS user-space helper.
 * Copyright (C) Igor Mammedov (niallain at gmail.com) 2007
+* Copyright (C) Jeff Layton (jlayton at redhat.com) 2009
 *
 * Used by /sbin/request-key for handling
 * cifs upcall for kerberos authorization of access to share and
@@ -26,16 +27,166 @@ create dns_resolver * * /usr/local/sbin/cifs.upcall %k
 
 #include "includes.h"
 #include <keyutils.h>
+#include <getopt.h>
 
 #include "cifs_spnego.h"
 
-const char *CIFSSPNEGO_VERSION = "1.2";
+#define	CIFS_DEFAULT_KRB5_DIR		"/tmp"
+#define	CIFS_DEFAULT_KRB5_PREFIX	"krb5cc_"
+
+#define	MAX_CCNAME_LEN			PATH_MAX + 5
+
+const char *CIFSSPNEGO_VERSION = "1.3";
 static const char *prog = "cifs.upcall";
-typedef enum _secType {
+typedef enum _sectype {
 	NONE = 0,
 	KRB5,
 	MS_KRB5
-} secType_t;
+} sectype_t;
+
+static inline int
+k5_data_equal(krb5_data d1, krb5_data d2, unsigned int length)
+{
+	if (!length)
+		length = d1.length;
+
+	return (d1.length == length &&
+		d1.length == d2.length &&
+		memcmp(d1.data, d2.data, length) == 0);
+
+}
+
+/* does the ccache have a valid TGT? */
+static time_t
+get_tgt_time(const char *ccname) {
+	krb5_context context;
+	krb5_ccache ccache;
+	krb5_cc_cursor cur;
+	krb5_creds creds;
+	krb5_principal principal;
+	krb5_data tgt = { .data =	"krbtgt",
+			  .length =	6 };
+	time_t credtime = 0;
+
+	if (krb5_init_context(&context)) {
+		syslog(LOG_DEBUG, "%s: unable to init krb5 context", __func__);
+		return 0;
+	}
+
+	if (krb5_cc_resolve(context, ccname, &ccache)) {
+		syslog(LOG_DEBUG, "%s: unable to resolve krb5 cache", __func__);
+		goto err_cache;
+	}
+
+	if (krb5_cc_set_flags(context, ccache, 0)) {
+		syslog(LOG_DEBUG, "%s: unable to set flags", __func__);
+		goto err_cache;
+	}
+
+	if (krb5_cc_get_principal(context, ccache, &principal)) {
+		syslog(LOG_DEBUG, "%s: unable to get principal", __func__);
+		goto err_princ;
+	}
+
+	if (krb5_cc_start_seq_get(context, ccache, &cur)) {
+		syslog(LOG_DEBUG, "%s: unable to seq start", __func__);
+		goto err_ccstart;
+	}
+
+	while (!credtime && !krb5_cc_next_cred(context, ccache, &cur, &creds)) {
+		if (k5_data_equal(creds.server->realm, principal->realm, 0) &&
+		    k5_data_equal(creds.server->data[0], tgt, tgt.length) &&
+		    k5_data_equal(creds.server->data[1], principal->realm, 0) &&
+		    creds.times.endtime > time(NULL))
+			credtime = creds.times.endtime;
+                krb5_free_cred_contents(context, &creds);
+        }
+        krb5_cc_end_seq_get(context, ccache, &cur);
+
+err_ccstart:
+	krb5_free_principal(context, principal);
+err_princ:
+	krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
+	krb5_cc_close(context, ccache);
+err_cache:
+	krb5_free_context(context);
+	return credtime;
+}
+
+static int
+krb5cc_filter(const struct dirent *dirent)
+{
+	if (strstr(dirent->d_name, CIFS_DEFAULT_KRB5_PREFIX))
+		return 1;
+	else
+		return 0;
+}
+
+/* search for a credcache that looks like a likely candidate */
+static char *
+find_krb5_cc(const char *dirname, uid_t uid)
+{
+	struct dirent **namelist;
+	struct stat sbuf;
+	char ccname[MAX_CCNAME_LEN], *credpath, *best_cache = NULL;
+	int i, n;
+	time_t cred_time, best_time = 0;
+
+	n = scandir(dirname, &namelist, krb5cc_filter, NULL);
+	if (n < 0) {
+		syslog(LOG_DEBUG, "%s: scandir error on directory '%s': %s",
+				  __func__, dirname, strerror(errno));
+		return NULL;
+	}
+
+	for (i = 0; i < n; i++) {
+		snprintf(ccname, sizeof(ccname), "FILE:%s/%s", dirname,
+			 namelist[i]->d_name);
+		credpath = ccname + 5;
+		syslog(LOG_DEBUG, "%s: considering %s", __func__, credpath);
+
+		if (lstat(credpath, &sbuf)) {
+			syslog(LOG_DEBUG, "%s: stat error on '%s': %s",
+					  __func__, credpath, strerror(errno));
+			free(namelist[i]);
+			continue;
+		}
+		if (sbuf.st_uid != uid) {
+			syslog(LOG_DEBUG, "%s: %s is owned by %u, not %u",
+					__func__, credpath, sbuf.st_uid, uid);
+			free(namelist[i]);
+			continue;
+		}
+		if (!S_ISREG(sbuf.st_mode)) {
+			syslog(LOG_DEBUG, "%s: %s is not a regular file",
+					__func__, credpath);
+			free(namelist[i]);
+			continue;
+		}
+		if (!(cred_time = get_tgt_time(ccname))) {
+			syslog(LOG_DEBUG, "%s: %s is not a valid credcache.",
+					__func__, ccname);
+			free(namelist[i]);
+			continue;
+		}
+
+		if (cred_time <= best_time) {
+			syslog(LOG_DEBUG, "%s: %s expires sooner than current "
+					  "best.", __func__, ccname);
+			free(namelist[i]);
+			continue;
+		}
+
+		syslog(LOG_DEBUG, "%s: %s is valid ccache", __func__, ccname);
+		free(best_cache);
+		best_cache = SMB_STRNDUP(ccname, MAX_CCNAME_LEN);
+		best_time = cred_time;
+		free(namelist[i]);
+	}
+	free(namelist);
+
+	return best_cache;
+}
 
 /*
  * Prepares AP-REQ data for mechToken and gets session key
@@ -56,20 +207,28 @@ typedef enum _secType {
  * 	sess_key-	pointer for SessionKey data to be stored
  *
  * ret: 0 - success, others - failure
-*/
+ */
 static int
-handle_krb5_mech(const char *oid, const char *principal,
-		     DATA_BLOB * secblob, DATA_BLOB * sess_key)
+handle_krb5_mech(const char *oid, const char *principal, DATA_BLOB *secblob,
+		 DATA_BLOB *sess_key, const char *ccname)
 {
 	int retval;
 	DATA_BLOB tkt, tkt_wrapped;
 
+	syslog(LOG_DEBUG, "%s: getting service ticket for %s", __func__,
+			  principal);
+
 	/* get a kerberos ticket for the service and extract the session key */
-	retval = cli_krb5_get_ticket(principal, 0,
-				     &tkt, sess_key, 0, NULL, NULL);
+	retval = cli_krb5_get_ticket(principal, 0, &tkt, sess_key, 0, ccname,
+				     NULL);
 
-	if (retval)
+	if (retval) {
+		syslog(LOG_DEBUG, "%s: failed to obtain service ticket (%d)",
+				  __func__, retval);
 		return retval;
+	}
+
+	syslog(LOG_DEBUG, "%s: obtained service ticket", __func__);
 
 	/* wrap that up in a nice GSS-API wrapping */
 	tkt_wrapped = spnego_gen_krb5_wrap(tkt, TOK_ID_KRB_AP_REQ);
@@ -82,18 +241,27 @@ handle_krb5_mech(const char *oid, const char *principal,
 	return retval;
 }
 
-#define DKD_HAVE_HOSTNAME	1
-#define DKD_HAVE_VERSION	2
-#define DKD_HAVE_SEC		4
-#define DKD_HAVE_IPV4		8
-#define DKD_HAVE_IPV6		16
-#define DKD_HAVE_UID		32
+#define DKD_HAVE_HOSTNAME	0x1
+#define DKD_HAVE_VERSION	0x2
+#define DKD_HAVE_SEC		0x4
+#define DKD_HAVE_IP		0x8
+#define DKD_HAVE_UID		0x10
+#define DKD_HAVE_PID		0x20
 #define DKD_MUSTHAVE_SET (DKD_HAVE_HOSTNAME|DKD_HAVE_VERSION|DKD_HAVE_SEC)
 
-static int
-decode_key_description(const char *desc, int *ver, secType_t * sec,
-			   char **hostname, uid_t * uid)
+struct decoded_args {
+	int		ver;
+	char		*hostname;
+	char		*ip;
+	uid_t		uid;
+	pid_t		pid;
+	sectype_t	sec;
+};
+
+static unsigned int
+decode_key_description(const char *desc, struct decoded_args *arg)
 {
+	int len;
 	int retval = 0;
 	char *pos;
 	const char *tkn = desc;
@@ -101,35 +269,52 @@ decode_key_description(const char *desc, int *ver, secType_t * sec,
 	do {
 		pos = index(tkn, ';');
 		if (strncmp(tkn, "host=", 5) == 0) {
-			int len;
 
-			if (pos == NULL) {
+			if (pos == NULL)
 				len = strlen(tkn);
-			} else {
+			else
 				len = pos - tkn;
-			}
+
 			len -= 4;
-			SAFE_FREE(*hostname);
-			*hostname = SMB_XMALLOC_ARRAY(char, len);
-			strlcpy(*hostname, tkn + 5, len);
+			SAFE_FREE(arg->hostname);
+			arg->hostname = SMB_XMALLOC_ARRAY(char, len);
+			strlcpy(arg->hostname, tkn + 5, len);
 			retval |= DKD_HAVE_HOSTNAME;
-		} else if (strncmp(tkn, "ipv4=", 5) == 0) {
-			/* BB: do we need it if we have hostname already? */
-		} else if (strncmp(tkn, "ipv6=", 5) == 0) {
-			/* BB: do we need it if we have hostname already? */
+		} else if (!strncmp(tkn, "ip4=", 4) ||
+			   !strncmp(tkn, "ip6=", 4)) {
+			if (pos == NULL)
+				len = strlen(tkn);
+			else
+				len = pos - tkn;
+
+			len -= 3;
+			SAFE_FREE(arg->ip);
+			arg->ip = SMB_XMALLOC_ARRAY(char, len);
+			strlcpy(arg->ip, tkn + 4, len);
+			retval |= DKD_HAVE_IP;
+		} else if (strncmp(tkn, "pid=", 4) == 0) {
+			errno = 0;
+			arg->pid = strtol(tkn + 4, NULL, 0);
+			if (errno != 0) {
+				syslog(LOG_ERR, "Invalid pid format: %s",
+				       strerror(errno));
+				return 1;
+			} else {
+				retval |= DKD_HAVE_PID;
+			}
 		} else if (strncmp(tkn, "sec=", 4) == 0) {
 			if (strncmp(tkn + 4, "krb5", 4) == 0) {
 				retval |= DKD_HAVE_SEC;
-				*sec = KRB5;
+				arg->sec = KRB5;
 			} else if (strncmp(tkn + 4, "mskrb5", 6) == 0) {
 				retval |= DKD_HAVE_SEC;
-				*sec = MS_KRB5;
+				arg->sec = MS_KRB5;
 			}
 		} else if (strncmp(tkn, "uid=", 4) == 0) {
 			errno = 0;
-			*uid = strtol(tkn + 4, NULL, 16);
+			arg->uid = strtol(tkn + 4, NULL, 16);
 			if (errno != 0) {
-				syslog(LOG_WARNING, "Invalid uid format: %s",
+				syslog(LOG_ERR, "Invalid uid format: %s",
 				       strerror(errno));
 				return 1;
 			} else {
@@ -137,10 +322,9 @@ decode_key_description(const char *desc, int *ver, secType_t * sec,
 			}
 		} else if (strncmp(tkn, "ver=", 4) == 0) {	/* if version */
 			errno = 0;
-			*ver = strtol(tkn + 4, NULL, 16);
+			arg->ver = strtol(tkn + 4, NULL, 16);
 			if (errno != 0) {
-				syslog(LOG_WARNING,
-				       "Invalid version format: %s",
+				syslog(LOG_ERR, "Invalid version format: %s",
 				       strerror(errno));
 				return 1;
 			} else {
@@ -166,7 +350,7 @@ cifs_resolver(const key_serial_t key, const char *key_descr)
 	for (c = 1; c <= 4; c++) {
 		keyend = index(keyend+1, ';');
 		if (!keyend) {
-			syslog(LOG_WARNING, "invalid key description: %s",
+			syslog(LOG_ERR, "invalid key description: %s",
 					key_descr);
 			return 1;
 		}
@@ -176,20 +360,19 @@ cifs_resolver(const key_serial_t key, const char *key_descr)
 	/* resolve name to ip */
 	c = getaddrinfo(keyend, NULL, NULL, &addr);
 	if (c) {
-		syslog(LOG_WARNING, "unable to resolve hostname: %s [%s]",
+		syslog(LOG_ERR, "unable to resolve hostname: %s [%s]",
 				keyend, gai_strerror(c));
 		return 1;
 	}
 
 	/* conver ip to string form */
-	if (addr->ai_family == AF_INET) {
+	if (addr->ai_family == AF_INET)
 		p = &(((struct sockaddr_in *)addr->ai_addr)->sin_addr);
-	} else {
+	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));
+		syslog(LOG_ERR, "%s: inet_ntop: %s", __func__, strerror(errno));
 		freeaddrinfo(addr);
 		return 1;
 	}
@@ -197,8 +380,8 @@ cifs_resolver(const key_serial_t key, const char *key_descr)
 	/* setup key */
 	c = keyctl_instantiate(key, ip, strlen(ip)+1, 0);
 	if (c == -1) {
-		syslog(LOG_WARNING, "%s: keyctl_instantiate: %s",
-				__FUNCTION__, strerror(errno));
+		syslog(LOG_ERR, "%s: keyctl_instantiate: %s", __func__,
+				strerror(errno));
 		freeaddrinfo(addr);
 		return 1;
 	}
@@ -207,44 +390,106 @@ cifs_resolver(const key_serial_t key, const char *key_descr)
 	return 0;
 }
 
+/*
+ * Older kernels sent IPv6 addresses without colons. Well, at least
+ * they're fixed-length strings. Convert these addresses to have colon
+ * delimiters to make getaddrinfo happy.
+ */
+static void
+convert_inet6_addr(const char *from, char *to)
+{
+	int i = 1;
+
+	while (*from) {
+		*to++ = *from++;
+		if (!(i++ % 4) && *from)
+			*to++ = ':';
+	}
+	*to = 0;
+}
+
+static int
+ip_to_fqdn(const char *addrstr, char *host, size_t hostlen)
+{
+	int rc;
+	struct addrinfo hints = { .ai_flags = AI_NUMERICHOST };
+	struct addrinfo *res;
+	const char *ipaddr = addrstr;
+	char converted[INET6_ADDRSTRLEN + 1];
+
+	if ((strlen(ipaddr) > INET_ADDRSTRLEN) && !strchr(ipaddr, ':')) {
+		convert_inet6_addr(ipaddr, converted);
+		ipaddr = converted;
+	}
+
+	rc = getaddrinfo(ipaddr, NULL, &hints, &res);
+	if (rc) {
+		syslog(LOG_DEBUG, "%s: failed to resolve %s to "
+			"ipaddr: %s", __func__, ipaddr,
+		rc == EAI_SYSTEM ? strerror(errno) : gai_strerror(rc));
+		return rc;
+	}
+
+	rc = getnameinfo(res->ai_addr, res->ai_addrlen, host, hostlen,
+			 NULL, 0, NI_NAMEREQD);
+	freeaddrinfo(res);
+	if (rc) {
+		syslog(LOG_DEBUG, "%s: failed to resolve %s to fqdn: %s",
+			__func__, ipaddr,
+			rc == EAI_SYSTEM ? strerror(errno) : gai_strerror(rc));
+		return rc;
+	}
+
+	syslog(LOG_DEBUG, "%s: resolved %s to %s", __func__, ipaddr, host);
+	return 0;
+}
+
 static void
 usage(void)
 {
-	syslog(LOG_WARNING, "Usage: %s [-c] [-v] key_serial", prog);
-	fprintf(stderr, "Usage: %s [-c] [-v] key_serial\n", prog);
+	syslog(LOG_INFO, "Usage: %s [-t] [-v] key_serial", prog);
+	fprintf(stderr, "Usage: %s [-t] [-v] key_serial\n", prog);
 }
 
+const struct option long_options[] = {
+	{ "trust-dns",	0, NULL, 't' },
+	{ "version",	0, NULL, 'v' },
+	{ NULL,		0, NULL, 0 }
+};


-- 
Samba Shared Repository


More information about the samba-cvs mailing list