Interdiff:
---
 lib/cmdlib.py                            |    4 +--
 lib/constants.py                         |    3 +-
 lib/masterd/instance.py                  |   47 ++++++++++++++++++++++++++++++
 test/ganeti.masterd.instance_unittest.py |   32 +++++++++++++++++++-
 4 files changed, 81 insertions(+), 5 deletions(-)

diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index a621451..51514d7 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -8873,9 +8873,7 @@ class LUPrepareExport(NoHooksLU):
                                              cert_pem)
 
       return {
-        "handshake": (utils.Sha1Hmac(self._cds, constants.RIE_HANDSHAKE,
-                                     salt=salt),
-                      salt),
+        "handshake": masterd.instance.ComputeRemoteExportHandshake(self._cds),
         "x509_key_name": (name, utils.Sha1Hmac(self._cds, name, salt=salt),
                           salt),
         "x509_ca": utils.SignX509Certificate(cert, self._cds, salt),
diff --git a/lib/constants.py b/lib/constants.py
index cf6a656..93f1045 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -333,7 +333,8 @@ LOCKS_APPEND = 'append'
 INSTANCE_CREATE = "create"
 INSTANCE_IMPORT = "import"
 
-# Remote import/export handshake message
+# Remote import/export handshake message and version
+RIE_VERSION = 0
 RIE_HANDSHAKE = "Hi, I'm Ganeti"
 
 # Remote import/export certificate validity in seconds
diff --git a/lib/masterd/instance.py b/lib/masterd/instance.py
index 7e95b0d..f48e01b 100644
--- a/lib/masterd/instance.py
+++ b/lib/masterd/instance.py
@@ -1105,3 +1105,50 @@ class ExportInstanceHelper:
     assert len(self._removed_snaps) == len(self._instance.disks)
     for idx in range(len(self._instance.disks)):
       self._RemoveSnapshot(idx)
+
+
+def _GetImportExportHandshakeMessage(version):
+  """Returns the handshake message for a RIE protocol version.
+
+  @type version: number
+
+  """
+  return "%s:%s" % (version, constants.RIE_HANDSHAKE)
+
+
+def ComputeRemoteExportHandshake(cds):
+  """Computes the remote import/export handshake.
+
+  @type cds: string
+  @param cds: Cluster domain secret
+
+  """
+  salt = utils.GenerateSecret(8)
+  msg = _GetImportExportHandshakeMessage(constants.RIE_VERSION)
+  return (constants.RIE_VERSION, utils.Sha1Hmac(cds, msg, salt=salt), salt)
+
+
+def CheckRemoteExportHandshake(cds, handshake):
+  """Checks the handshake of a remote import/export.
+
+  @type cds: string
+  @param cds: Cluster domain secret
+  @type handshake: sequence
+  @param handshake: Handshake sent by remote peer
+
+  """
+  try:
+    (version, hmac_digest, hmac_salt) = handshake
+  except (TypeError, ValueError), err:
+    return "Invalid data: %s" % err
+
+  if not utils.VerifySha1Hmac(cds, _GetImportExportHandshakeMessage(version),
+                              hmac_digest, salt=hmac_salt):
+    return "Hash didn't match, clusters don't share the same domain secret"
+
+  if version != constants.RIE_VERSION:
+    return ("Clusters don't have the same remote import/export protocol"
+            " (local=%s, remote=%s)" %
+            (constants.RIE_VERSION, version))
+
+  return None
diff --git a/test/ganeti.masterd.instance_unittest.py 
b/test/ganeti.masterd.instance_unittest.py
index 05b0183..0c74def 100755
--- a/test/ganeti.masterd.instance_unittest.py
+++ b/test/ganeti.masterd.instance_unittest.py
@@ -25,11 +25,13 @@ import os
 import sys
 import unittest
 
+from ganeti import constants
 from ganeti import utils
 from ganeti import masterd
 
 from ganeti.masterd.instance import \
-  ImportExportTimeouts, _TimeoutExpired, _DiskImportExportBase
+  ImportExportTimeouts, _TimeoutExpired, _DiskImportExportBase, \
+  ComputeRemoteExportHandshake, CheckRemoteExportHandshake
 
 import testutils
 
@@ -56,5 +58,33 @@ class TestMisc(unittest.TestCase):
                       None, None, None, None, None, None, None)
 
 
+class TestRieHandshake(unittest.TestCase):
+  def test(self):
+    cds = "cd-secret"
+    hs = ComputeRemoteExportHandshake(cds)
+    self.assertEqual(len(hs), 3)
+    self.assertEqual(hs[0], constants.RIE_VERSION)
+
+    self.assertEqual(CheckRemoteExportHandshake(cds, hs), None)
+
+  def testCheckErrors(self):
+    self.assert_(CheckRemoteExportHandshake(None, None))
+    self.assert_(CheckRemoteExportHandshake("", ""))
+    self.assert_(CheckRemoteExportHandshake("", ("xyz", "foo")))
+
+  def testCheckWrongHash(self):
+    cds = "cd-secret999"
+    self.assert_(CheckRemoteExportHandshake(cds, (0, "fakehash", "xyz")))
+
+  def testCheckWrongVersion(self):
+    version = 14887
+    self.assertNotEqual(version, constants.RIE_VERSION)
+    cds = "c28ac99"
+    salt = "a19cf8cc06"
+    msg = "%s:%s" % (version, constants.RIE_HANDSHAKE)
+    hs = (version, utils.Sha1Hmac(cds, msg, salt=salt), salt)
+    self.assert_(CheckRemoteExportHandshake(cds, hs))
+
+
 if __name__ == "__main__":
   testutils.GanetiTestProgram()
-- 
1.7.0.4

Reply via email to