diff --git a/cmd/adsysd/integration_tests/adsysctl_policy_test.go b/cmd/adsysd/integration_tests/adsysctl_policy_test.go index 6530c50b3..f92871a1d 100644 --- a/cmd/adsysd/integration_tests/adsysctl_policy_test.go +++ b/cmd/adsysd/integration_tests/adsysctl_policy_test.go @@ -965,6 +965,15 @@ func TestPolicyUpdate(t *testing.T) { t.Setenv("ADSYS_WBCLIENT_BEHAVIOR", tc.winbindMockBehavior) + // Create fake certmonger and cepces binaries for the certificate manager + binDir := t.TempDir() + for _, executable := range []string{"getcert", "cepces-submit"} { + // #nosec G306. We want this asset to be executable. + err := os.WriteFile(filepath.Join(binDir, executable), []byte("#!/bin/sh\necho $@\n"), 0755) + require.NoError(t, err, "Setup: could not create %q binary", executable) + } + t.Setenv("PATH", binDir+":"+os.Getenv("PATH")) + // Some tests will need some initial state assets for _, k := range tc.clearDirs { err := os.RemoveAll(filepath.Join(adsysDir, k)) diff --git a/internal/policies/certificate/cert-autoenroll b/internal/policies/certificate/cert-autoenroll index 44c0b68d8..53eb10954 100755 --- a/internal/policies/certificate/cert-autoenroll +++ b/internal/policies/certificate/cert-autoenroll @@ -13,7 +13,7 @@ from samba.dcerpc import preg from vendor_samba.gp.gpclass import GPOStorage from vendor_samba.gp import gp_cert_auto_enroll_ext as cae -from vendor_samba.gp.util.logging import logger_init +from vendor_samba.gp.util.logging import logger_init, log class adsys_cert_auto_enroll(cae.gp_cert_auto_enroll_ext): def enroll(self, guid, entries, trust_dir, private_dir, global_trust_dir): @@ -78,6 +78,10 @@ def main(): # Set up logging logger_init('cert-autoenroll', lp.log_level()) + if not cepces_submit() or not certmonger(): + log.warning('certmonger and/or cepces not found, skipping certificate enrollment') + return + ext = adsys_cert_auto_enroll(lp, c, username, store) guid = f'adsys-cert-autoenroll-{args.object_name}' if args.action == 'enroll': @@ -126,6 +130,13 @@ def gpo_entries(entries_json): raise ValueError(f'GPO data must be a JSON array of objects') from exc return entries +def cepces_submit(): + certmonger_dirs = [os.environ.get('PATH'), '/usr/lib/certmonger', + '/usr/libexec/certmonger'] + return shutil.which('cepces-submit', path=':'.join(certmonger_dirs)) + +def certmonger(): + return shutil.which('getcert') if __name__ == "__main__": sys.exit(main()) diff --git a/internal/policies/certificate/cert-autoenroll_test.go b/internal/policies/certificate/cert-autoenroll_test.go index 39375cb7f..4fd691bc9 100644 --- a/internal/policies/certificate/cert-autoenroll_test.go +++ b/internal/policies/certificate/cert-autoenroll_test.go @@ -80,6 +80,9 @@ func TestCertAutoenrollScript(t *testing.T) { readOnlyPath bool autoenrollError bool + missingCertmonger bool + missingCepces bool + wantErr bool }{ "Enroll with simple configuration": {args: []string{"enroll", "keypress", "example.com"}}, @@ -89,6 +92,10 @@ func TestCertAutoenrollScript(t *testing.T) { "Unenroll": {args: []string{"unenroll", "keypress", "example.com"}}, + // Missing binary cases + "Enroll with certmonger not installed": {args: []string{"enroll", "keypress", "example.com"}, missingCertmonger: true}, + "Enroll with cepces not installed": {args: []string{"enroll", "keypress", "example.com"}, missingCepces: true}, + // Error cases "Error on missing arguments": {args: []string{"enroll"}, wantErr: true}, "Error on invalid flags": {args: []string{"enroll", "keypress", "example.com", "--invalid_flag"}, wantErr: true}, @@ -109,6 +116,17 @@ func TestCertAutoenrollScript(t *testing.T) { stateDir := t.TempDir() sambaCacheDir := filepath.Join(stateDir, "samba") globalTrustDir := filepath.Join(stateDir, "ca-certificates") + binDir := t.TempDir() + if !tc.missingCertmonger { + // #nosec G306. We want this asset to be executable. + err := os.WriteFile(filepath.Join(binDir, "getcert"), []byte("#!/bin/sh\necho $@\n"), 0755) + require.NoError(t, err, "Setup: could not create getcert binary") + } + if !tc.missingCepces { + // #nosec G306. We want this asset to be executable. + err := os.WriteFile(filepath.Join(binDir, "cepces-submit"), []byte("#!/bin/sh\necho $@\n"), 0755) + require.NoError(t, err, "Setup: could not create cepces binary") + } // Create a dummy cache file to ensure we don't fail when removing a non-empty directory testutils.CreatePath(t, filepath.Join(sambaCacheDir, "cert_gpo_state_HOST.tdb")) @@ -121,7 +139,10 @@ func TestCertAutoenrollScript(t *testing.T) { // #nosec G204: we control the command line name and only change it for tests cmd := exec.Command(certAutoenrollCmd, args...) - cmd.Env = append(os.Environ(), "PYTHONPATH="+pythonPath) + cmd.Env = append(os.Environ(), + "PYTHONPATH="+pythonPath, + "PATH="+binDir+":"+os.Getenv("PATH"), + ) if tc.autoenrollError { cmd.Env = append(os.Environ(), "ADSYS_WANT_AUTOENROLL_ERROR=1") } diff --git a/internal/policies/certificate/testdata/TestCertAutoenrollScript/golden/enroll_with_cepces_not_installed b/internal/policies/certificate/testdata/TestCertAutoenrollScript/golden/enroll_with_cepces_not_installed new file mode 100644 index 000000000..fefe24e79 --- /dev/null +++ b/internal/policies/certificate/testdata/TestCertAutoenrollScript/golden/enroll_with_cepces_not_installed @@ -0,0 +1,6 @@ +Loading smb.conf +[global] +realm = example.com + +Loading state file: #STATEDIR#/samba/cert_gpo_state_keypress.tdb +WARNING: certmonger and/or cepces not found, skipping certificate enrollment diff --git a/internal/policies/certificate/testdata/TestCertAutoenrollScript/golden/enroll_with_certmonger_not_installed b/internal/policies/certificate/testdata/TestCertAutoenrollScript/golden/enroll_with_certmonger_not_installed new file mode 100644 index 000000000..fefe24e79 --- /dev/null +++ b/internal/policies/certificate/testdata/TestCertAutoenrollScript/golden/enroll_with_certmonger_not_installed @@ -0,0 +1,6 @@ +Loading smb.conf +[global] +realm = example.com + +Loading state file: #STATEDIR#/samba/cert_gpo_state_keypress.tdb +WARNING: certmonger and/or cepces not found, skipping certificate enrollment diff --git a/internal/testutils/admock/vendor_samba/gp/util/logging.py b/internal/testutils/admock/vendor_samba/gp/util/logging.py index dd4bc4bfe..a42e95801 100644 --- a/internal/testutils/admock/vendor_samba/gp/util/logging.py +++ b/internal/testutils/admock/vendor_samba/gp/util/logging.py @@ -1,2 +1,7 @@ def logger_init(_name, _level): pass + +class log(object): + @staticmethod + def warning(msg): + print(f'WARNING: {msg}')