[PATCH] Follow-up traffic_replay patches for machine account generation

Tim Beale timbeale at catalyst.net.nz
Tue Nov 6 20:16:47 UTC 2018


Attached are some follow-up patches that tidy-up issues around machine
account generation. The problem is we essentially have two different
use-cases that we want to create machine accounts for:
- Replaying network packets.
- Creating a large, realistic database.
These patches make the two different cases play nicely together.

CI pass: https://gitlab.com/catalyst-samba/samba/pipelines/35527497

Review appreciated. Thanks.

-------------- next part --------------
From 27d9ea27fed8a6e5c46149a121b8987d0513162d Mon Sep 17 00:00:00 2001
From: Tim Beale <timbeale at catalyst.net.nz>
Date: Tue, 6 Nov 2018 10:52:38 +1300
Subject: [PATCH 1/5] traffic_replay: Move machine account creation

I was assuming that generate_users_and_groups() only gets called in the
--generate-users-only case. However, it also gets called in the default
traffic replay case.

This patch reworks the code so that the number of machine accounts to
create gets passed in, and the 'create 25% more computers than users'
assumption only applies to the --generate-users-only case.

Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
---
 python/samba/emulate/traffic.py | 14 +++++++-------
 script/traffic_replay           |  6 +++++-
 2 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py
index af05163..8de329b 100644
--- a/python/samba/emulate/traffic.py
+++ b/python/samba/emulate/traffic.py
@@ -1798,22 +1798,22 @@ def clean_up_accounts(ldb, instance_id):
 
 def generate_users_and_groups(ldb, instance_id, password,
                               number_of_users, number_of_groups,
-                              group_memberships):
+                              group_memberships, machine_accounts=0):
     """Generate the required users and groups, allocating the users to
        those groups."""
     memberships_added = 0
-    groups_added  = 0
+    groups_added = 0
+    computers_added = 0
 
     create_ou(ldb, instance_id)
 
     LOGGER.info("Generating dummy user accounts")
     users_added = generate_users(ldb, instance_id, number_of_users, password)
 
-    # assume there will be some overhang with more computer accounts than users
-    computer_accounts = int(1.25 * number_of_users)
-    LOGGER.info("Generating dummy machine accounts")
-    computers_added = generate_machine_accounts(ldb, instance_id,
-                                                computer_accounts, password)
+    if machine_accounts > 0:
+        LOGGER.info("Generating dummy machine accounts")
+        computers_added = generate_machine_accounts(ldb, instance_id,
+                                                    machine_accounts, password)
 
     if number_of_groups > 0:
         LOGGER.info("Generating dummy groups")
diff --git a/script/traffic_replay b/script/traffic_replay
index 9642ea8..2cd84f7 100755
--- a/script/traffic_replay
+++ b/script/traffic_replay
@@ -324,12 +324,16 @@ def main():
         sys.exit(1)
 
     if opts.generate_users_only:
+        # generate computer accounts for added realism. Assume there will be
+        # some overhang with more computer accounts than users
+        computer_accounts = int(1.25 * number_of_users)
         traffic.generate_users_and_groups(ldb,
                                           opts.instance_id,
                                           opts.fixed_password,
                                           opts.number_of_users,
                                           opts.number_of_groups,
-                                          opts.group_memberships)
+                                          opts.group_memberships,
+                                          machine_accounts=computer_accounts)
         sys.exit()
 
     tempdir = tempfile.mkdtemp(prefix="samba_tg_")
-- 
2.7.4


From 597eeb2112d0331000e0d6f961ba41f723085f04 Mon Sep 17 00:00:00 2001
From: Tim Beale <timbeale at catalyst.net.nz>
Date: Tue, 6 Nov 2018 10:58:56 +1300
Subject: [PATCH 2/5] traffic_replay: Move 'traffic account' flag up a level

We create machine accounts for 2 different purposes:
1). For traffic generation, i.e. testing realistic network packets.
2). For generating a realistic large DB.

Unfortunately, we want to use different userAccountControl flags for
the 2 different cases. Commit 3338a3e257fa9f28 changed the flags used
for case #2, but this breaks case #1.

The problem is generate_users_and_groups() is called in both cases,
so we want the 'traffic account' flag passed into that function.
This ensures that the machine accounts get created with the appropriate
userAccountControl flags for the particular case you want to test.

Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
---
 python/samba/emulate/traffic.py | 11 +++++++----
 script/traffic_replay           |  6 ++++--
 2 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py
index 8de329b..af99e66 100644
--- a/python/samba/emulate/traffic.py
+++ b/python/samba/emulate/traffic.py
@@ -1747,7 +1747,8 @@ def generate_users(ldb, instance_id, number, password):
     return users
 
 
-def generate_machine_accounts(ldb, instance_id, number, password):
+def generate_machine_accounts(ldb, instance_id, number, password,
+                              traffic_account=True):
     """Add machine accounts to the server"""
     existing_objects = search_objectclass(ldb, objectclass='computer')
     added = 0
@@ -1756,7 +1757,7 @@ def generate_machine_accounts(ldb, instance_id, number, password):
         if name not in existing_objects:
             name = "STGM-%d-%d" % (instance_id, i)
             create_machine_account(ldb, instance_id, name, password,
-                                   traffic_account=False)
+                                   traffic_account)
             added += 1
             if added % 50 == 0:
                 LOGGER.info("Created %u/%u machine accounts" % (added, number))
@@ -1798,7 +1799,8 @@ def clean_up_accounts(ldb, instance_id):
 
 def generate_users_and_groups(ldb, instance_id, password,
                               number_of_users, number_of_groups,
-                              group_memberships, machine_accounts=0):
+                              group_memberships, machine_accounts=0,
+                              traffic_accounts=True):
     """Generate the required users and groups, allocating the users to
        those groups."""
     memberships_added = 0
@@ -1813,7 +1815,8 @@ def generate_users_and_groups(ldb, instance_id, password,
     if machine_accounts > 0:
         LOGGER.info("Generating dummy machine accounts")
         computers_added = generate_machine_accounts(ldb, instance_id,
-                                                    machine_accounts, password)
+                                                    machine_accounts, password,
+                                                    traffic_accounts)
 
     if number_of_groups > 0:
         LOGGER.info("Generating dummy groups")
diff --git a/script/traffic_replay b/script/traffic_replay
index 2cd84f7..e8ba131 100755
--- a/script/traffic_replay
+++ b/script/traffic_replay
@@ -333,7 +333,8 @@ def main():
                                           opts.number_of_users,
                                           opts.number_of_groups,
                                           opts.group_memberships,
-                                          machine_accounts=computer_accounts)
+                                          machine_accounts=computer_accounts,
+                                          traffic_accounts=False)
         sys.exit()
 
     tempdir = tempfile.mkdtemp(prefix="samba_tg_")
@@ -344,7 +345,8 @@ def main():
                                       opts.fixed_password,
                                       number_of_users,
                                       opts.number_of_groups,
-                                      opts.group_memberships)
+                                      opts.group_memberships,
+                                      traffic_accounts=True)
 
     accounts = traffic.generate_replay_accounts(ldb,
                                                 opts.instance_id,
-- 
2.7.4


From 097909e3196cf8a2c05e66f66a37df8f52618555 Mon Sep 17 00:00:00 2001
From: Tim Beale <timbeale at catalyst.net.nz>
Date: Tue, 6 Nov 2018 09:35:41 +1300
Subject: [PATCH 3/5] traffic_replay: Make sure naming assumptions are in a
 single place

The traffic_replay group/user/machine account names follow a standard
format. This adds a function to generate the machine-name. It also makes
sure the existing user_name() function gets called in all applicable
places.

Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
---
 python/samba/emulate/traffic.py | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py
index af99e66..77a1862 100644
--- a/python/samba/emulate/traffic.py
+++ b/python/samba/emulate/traffic.py
@@ -1606,8 +1606,8 @@ def generate_replay_accounts(ldb, instance_id, number, password):
     generate_traffic_accounts(ldb, instance_id, number, password)
     accounts = []
     for i in range(1, number + 1):
-        netbios_name = "STGM-%d-%d" % (instance_id, i)
-        username     = "STGU-%d-%d" % (instance_id, i)
+        netbios_name = machine_name(instance_id, i)
+        username = user_name(instance_id, i)
 
         account = ConversationAccounts(netbios_name, password, username,
                                        password)
@@ -1629,7 +1629,7 @@ def generate_traffic_accounts(ldb, instance_id, number, password):
     added = 0
     for i in range(number, 0, -1):
         try:
-            netbios_name = "STGM-%d-%d" % (instance_id, i)
+            netbios_name = machine_name(instance_id, i)
             create_machine_account(ldb, instance_id, netbios_name, password)
             added += 1
             if added % 50 == 0:
@@ -1646,7 +1646,7 @@ def generate_traffic_accounts(ldb, instance_id, number, password):
     added = 0
     for i in range(number, 0, -1):
         try:
-            username = "STGU-%d-%d" % (instance_id, i)
+            username = user_name(instance_id, i)
             create_user_account(ldb, instance_id, username, password)
             added += 1
             if added % 50 == 0:
@@ -1747,15 +1747,19 @@ def generate_users(ldb, instance_id, number, password):
     return users
 
 
+def machine_name(instance_id, i):
+    """Generate a machine account name from instance id."""
+    return "STGM-%d-%d" % (instance_id, i)
+
+
 def generate_machine_accounts(ldb, instance_id, number, password,
                               traffic_account=True):
     """Add machine accounts to the server"""
     existing_objects = search_objectclass(ldb, objectclass='computer')
     added = 0
     for i in range(number, 0, -1):
-        name = "STGM-%d-%d$" % (instance_id, i)
-        if name not in existing_objects:
-            name = "STGM-%d-%d" % (instance_id, i)
+        name = machine_name(instance_id, i)
+        if name + "$" not in existing_objects:
             create_machine_account(ldb, instance_id, name, password,
                                    traffic_account)
             added += 1
-- 
2.7.4


From 8c8ac5f3f16cdd651c30183f5767e3a62f784019 Mon Sep 17 00:00:00 2001
From: Tim Beale <timbeale at catalyst.net.nz>
Date: Tue, 6 Nov 2018 11:14:41 +1300
Subject: [PATCH 4/5] traffic_replay: Make packet generation work on a
 pre-populated DB again

Generate separate machine accounts for populating a large DB vs
replaying network traffic.

We want to use different userAccountControl flags in each of the above
cases (i.e. commit 3338a3e257fa9f28). However, this means that once you
use the --generate-users-only option, you can't replay network packets
against the machine accounts.

We can avoid this problem by creating separate machine accounts for each
of 2 different cases, e.g. STGM-0-x machines for traffic-replay, and
PC-0-x machines for padding out the database.

Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
---
 python/samba/emulate/traffic.py | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py
index 77a1862..9ac8775 100644
--- a/python/samba/emulate/traffic.py
+++ b/python/samba/emulate/traffic.py
@@ -1747,9 +1747,19 @@ def generate_users(ldb, instance_id, number, password):
     return users
 
 
-def machine_name(instance_id, i):
+def machine_name(instance_id, i, traffic_account=True):
     """Generate a machine account name from instance id."""
-    return "STGM-%d-%d" % (instance_id, i)
+    if traffic_account:
+        # traffic accounts correspond to a given user, and use different
+        # userAccountControl flags to ensure packets get processed correctly
+        # by the DC
+        return "STGM-%d-%d" % (instance_id, i)
+    else:
+        # Otherwise we're just generating computer accounts to simulate a
+        # semi-realistic network. These use the default computer
+        # userAccountControl flags, so we use a different account name so that
+        # we don't try to use them when generating packets
+        return "PC-%d-%d" % (instance_id, i)
 
 
 def generate_machine_accounts(ldb, instance_id, number, password,
@@ -1758,7 +1768,7 @@ def generate_machine_accounts(ldb, instance_id, number, password,
     existing_objects = search_objectclass(ldb, objectclass='computer')
     added = 0
     for i in range(number, 0, -1):
-        name = machine_name(instance_id, i)
+        name = machine_name(instance_id, i, traffic_account)
         if name + "$" not in existing_objects:
             create_machine_account(ldb, instance_id, name, password,
                                    traffic_account)
-- 
2.7.4


From d3a365700063013d1243dd5a22762aef8cff7f46 Mon Sep 17 00:00:00 2001
From: Tim Beale <timbeale at catalyst.net.nz>
Date: Tue, 6 Nov 2018 11:27:42 +1300
Subject: [PATCH 5/5] traffic_replay: Rework machine accounts to remove
 redundant code

generate_users_and_groups() now generates the machine acounts as well as
the user accounts, so it seems there's no need to also have
generate_traffic_accounts(), which does the same job.

Instead, we can just pass through the number of machine acounts to
generate_users_and_groups() and delete the other function.

Also updated generate_users_and_groups() so that machine_accounts is
no longer optional (we want to create machine accounts in all cases).

Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
---
 python/samba/emulate/traffic.py | 60 ++++-------------------------------------
 script/traffic_replay           |  1 +
 2 files changed, 6 insertions(+), 55 deletions(-)

diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py
index 9ac8775..069c410 100644
--- a/python/samba/emulate/traffic.py
+++ b/python/samba/emulate/traffic.py
@@ -1603,7 +1603,6 @@ class ConversationAccounts(object):
 def generate_replay_accounts(ldb, instance_id, number, password):
     """Generate a series of unique machine and user account names."""
 
-    generate_traffic_accounts(ldb, instance_id, number, password)
     accounts = []
     for i in range(1, number + 1):
         netbios_name = machine_name(instance_id, i)
@@ -1615,54 +1614,6 @@ def generate_replay_accounts(ldb, instance_id, number, password):
     return accounts
 
 
-def generate_traffic_accounts(ldb, instance_id, number, password):
-    """Create the specified number of user and machine accounts.
-
-    As accounts are not explicitly deleted between runs. This function starts
-    with the last account and iterates backwards stopping either when it
-    finds an already existing account or it has generated all the required
-    accounts.
-    """
-    print(("Generating machine and conversation accounts, "
-           "as required for %d conversations" % number),
-          file=sys.stderr)
-    added = 0
-    for i in range(number, 0, -1):
-        try:
-            netbios_name = machine_name(instance_id, i)
-            create_machine_account(ldb, instance_id, netbios_name, password)
-            added += 1
-            if added % 50 == 0:
-                LOGGER.info("Created %u/%u machine accounts" % (added, number))
-        except LdbError as e:
-            (status, _) = e.args
-            if status == 68:
-                break
-            else:
-                raise
-    if added > 0:
-        LOGGER.info("Added %d new machine accounts" % added)
-
-    added = 0
-    for i in range(number, 0, -1):
-        try:
-            username = user_name(instance_id, i)
-            create_user_account(ldb, instance_id, username, password)
-            added += 1
-            if added % 50 == 0:
-                LOGGER.info("Created %u/%u users" % (added, number))
-
-        except LdbError as e:
-            (status, _) = e.args
-            if status == 68:
-                break
-            else:
-                raise
-
-    if added > 0:
-        LOGGER.info("Added %d new user accounts" % added)
-
-
 def create_machine_account(ldb, instance_id, netbios_name, machinepass,
                            traffic_account=True):
     """Create a machine account via ldap."""
@@ -1813,7 +1764,7 @@ def clean_up_accounts(ldb, instance_id):
 
 def generate_users_and_groups(ldb, instance_id, password,
                               number_of_users, number_of_groups,
-                              group_memberships, machine_accounts=0,
+                              group_memberships, machine_accounts,
                               traffic_accounts=True):
     """Generate the required users and groups, allocating the users to
        those groups."""
@@ -1826,11 +1777,10 @@ def generate_users_and_groups(ldb, instance_id, password,
     LOGGER.info("Generating dummy user accounts")
     users_added = generate_users(ldb, instance_id, number_of_users, password)
 
-    if machine_accounts > 0:
-        LOGGER.info("Generating dummy machine accounts")
-        computers_added = generate_machine_accounts(ldb, instance_id,
-                                                    machine_accounts, password,
-                                                    traffic_accounts)
+    LOGGER.info("Generating dummy machine accounts")
+    computers_added = generate_machine_accounts(ldb, instance_id,
+                                                machine_accounts, password,
+                                                traffic_accounts)
 
     if number_of_groups > 0:
         LOGGER.info("Generating dummy groups")
diff --git a/script/traffic_replay b/script/traffic_replay
index e8ba131..991c9a9 100755
--- a/script/traffic_replay
+++ b/script/traffic_replay
@@ -346,6 +346,7 @@ def main():
                                       number_of_users,
                                       opts.number_of_groups,
                                       opts.group_memberships,
+                                      machine_accounts=len(conversations),
                                       traffic_accounts=True)
 
     accounts = traffic.generate_replay_accounts(ldb,
-- 
2.7.4



More information about the samba-technical mailing list