979ee0
From 2347e7d3b9979533f471874919e1a39747bf4597 Mon Sep 17 00:00:00 2001
979ee0
From: Christian Heimes <cheimes@redhat.com>
979ee0
Date: Fri, 6 Jul 2018 21:47:32 +0200
979ee0
Subject: [PATCH] Fix race condition in get_locations_records()
979ee0
979ee0
The method IPASystemRecords.get_locations_records() has a race condition.
979ee0
The IPASystemRecords object creates a mapping of server names to server
979ee0
data. get_locations_records() uses server_find() again to get a list of
979ee0
servers, but then operates on the cached dict of server names.
979ee0
979ee0
In parallel replication case, the second server_find() call in
979ee0
get_locations_records() can return additional servers. Since the rest of
979ee0
the code operates on the cached data, the method then fails with a KeyError.
979ee0
979ee0
server_data is now an OrderedDict to keep same sorting as with
979ee0
server_find().
979ee0
979ee0
Fixes: https://pagure.io/freeipa/issue/7566
979ee0
Signed-off-by: Christian Heimes <cheimes@redhat.com>
979ee0
Reviewed-By: Tibor Dudlak <tdudlak@redhat.com>
979ee0
---
979ee0
 ipaserver/dns_data_management.py | 14 +++++---------
979ee0
 1 file changed, 5 insertions(+), 9 deletions(-)
979ee0
979ee0
diff --git a/ipaserver/dns_data_management.py b/ipaserver/dns_data_management.py
979ee0
index e5987b4bd7b43d3920e9da917258153e448206b7..c4f204c4941984d74e442c51ea206f11c05db2b9 100644
979ee0
--- a/ipaserver/dns_data_management.py
979ee0
+++ b/ipaserver/dns_data_management.py
979ee0
@@ -6,7 +6,7 @@ from __future__ import absolute_import
979ee0
 
979ee0
 import six
979ee0
 
979ee0
-from collections import defaultdict
979ee0
+from collections import defaultdict, OrderedDict
979ee0
 from dns import (
979ee0
     rdata,
979ee0
     rdataclass,
979ee0
@@ -68,7 +68,7 @@ class IPASystemRecords(object):
979ee0
     def __init__(self, api_instance, all_servers=False):
979ee0
         self.api_instance = api_instance
979ee0
         self.domain_abs = DNSName(self.api_instance.env.domain).make_absolute()
979ee0
-        self.servers_data = {}
979ee0
+        self.servers_data = OrderedDict()
979ee0
         self.__init_data(all_servers=all_servers)
979ee0
 
979ee0
     def reload_data(self):
979ee0
@@ -90,7 +90,7 @@ class IPASystemRecords(object):
979ee0
         return location + DNSName('_locations') + self.domain_abs
979ee0
 
979ee0
     def __init_data(self, all_servers=False):
979ee0
-        self.servers_data = {}
979ee0
+        self.servers_data.clear()
979ee0
 
979ee0
         kwargs = dict(no_members=False)
979ee0
         if not all_servers:
979ee0
@@ -325,7 +325,7 @@ class IPASystemRecords(object):
979ee0
 
979ee0
         zone_obj = zone.Zone(self.domain_abs, relativize=False)
979ee0
         if servers is None:
979ee0
-            servers = self.servers_data.keys()
979ee0
+            servers = list(self.servers_data)
979ee0
 
979ee0
         for server in servers:
979ee0
             self._add_base_dns_records_for_server(zone_obj, server,
979ee0
@@ -348,11 +348,7 @@ class IPASystemRecords(object):
979ee0
         """
979ee0
         zone_obj = zone.Zone(self.domain_abs, relativize=False)
979ee0
         if servers is None:
979ee0
-            servers_result = self.api_instance.Command.server_find(
979ee0
-                pkey_only=True,
979ee0
-                servrole=u"IPA master",  # only fully installed masters
979ee0
-            )['result']
979ee0
-            servers = [s['cn'][0] for s in servers_result]
979ee0
+            servers = list(self.servers_data)
979ee0
 
979ee0
         locations_result = self.api_instance.Command.location_find()['result']
979ee0
         locations = [l['idnsname'][0] for l in locations_result]
979ee0
-- 
979ee0
2.17.1
979ee0