Skip to content

Commit ab3b09b

Browse files
tests: keep the integration suite runnable on modern Samba and NSS users
The adsysd integration tests run the daemon against a guest-only smbd with no real KDC, relying on libsmbclient falling back from kerberos to anonymous authentication. Samba >= 4.23 dropped that implicit fallback, so the SMB fetch fails with EINVAL on current systems. Gating a test-only ADSYS_TESTS_WITHOUT_KERBEROS variable in ad.New() lets the daemon skip kerberos under the harness; it must never be set in production. The mock D-Bus/polkit/systemd containers also resolve the connecting user through the bind-mounted /etc/passwd and /etc/group. When the suite runs as a user only known through NSS (e.g. an LDAP/SSSD user absent from the local files), the container cannot resolve the UID and resets the connection, so the harness now generates augmented passwd/group databases that include the current user before mounting them. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent b3ad3e2 commit ab3b09b

2 files changed

Lines changed: 72 additions & 2 deletions

File tree

cmd/adsysd/integration_tests/adsys_test.go

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313
"os"
1414
"os/exec"
1515
"path/filepath"
16+
"strconv"
17+
"strings"
1618
"sync"
1719
"testing"
1820
"time"
@@ -33,6 +35,15 @@ var (
3335
)
3436

3537
func TestMain(m *testing.M) {
38+
// The integration tests run the daemon against a guest-only smbd with no
39+
// real KDC, relying on libsmbclient falling back from kerberos to
40+
// anonymous. Newer Samba (>= 4.23) dropped that implicit fallback, so we
41+
// tell the daemon to skip kerberos entirely. This env var is only honored
42+
// by the daemon for tests and is propagated to re-exec'd helper processes.
43+
if err := os.Setenv("ADSYS_TESTS_WITHOUT_KERBEROS", "1"); err != nil {
44+
log.Fatalf("Setup: can't disable kerberos for tests: %v", err)
45+
}
46+
3647
if os.Getenv("ADSYS_SKIP_INTEGRATION_TESTS") != "" {
3748
fmt.Println("Integration tests skipped as requested")
3849
return
@@ -402,6 +413,15 @@ func runDaemons() (teardown func()) {
402413
answers[mode] = filepath.Join(dir, mode)
403414
}
404415

416+
// The mock containers resolve the connecting user through the bind-mounted
417+
// /etc/passwd and /etc/group. When the tests run as a user that is only
418+
// known through NSS (e.g. an LDAP/SSSD user not present in the local files),
419+
// the container's D-Bus daemon can't resolve the UID and resets the
420+
// connection. Generate augmented databases that also contain the current
421+
// user and group so the mocks work regardless of the NSS backend.
422+
passwdFile := writeUserDatabase(dir, "passwd", "/etc/passwd")
423+
groupFile := writeUserDatabase(dir, "group", "/etc/group")
424+
405425
var errsDocker error
406426
var wg sync.WaitGroup
407427
for answer, socketDir := range answers {
@@ -422,8 +442,8 @@ func runDaemons() (teardown func()) {
422442
"run", "--rm", "--pid", "host",
423443
"--name", containerName+answer,
424444
"--volume", fmt.Sprintf("%s:%s:ro", adsysActionsDir, "/usr/share/polkit-1/actions.orig"),
425-
"--volume", `/etc/group:/etc/group:ro`,
426-
"--volume", `/etc/passwd:/etc/passwd:ro`,
445+
"--volume", fmt.Sprintf("%s:/etc/group:ro", groupFile),
446+
"--volume", fmt.Sprintf("%s:/etc/passwd:ro", passwdFile),
427447
"--volume", fmt.Sprintf("%s:/dbus/", socketDir),
428448
dockerSystemDaemonsImage,
429449
answer,
@@ -474,6 +494,49 @@ func runDaemons() (teardown func()) {
474494
}
475495
}
476496

497+
// writeUserDatabase copies the host NSS database file (/etc/passwd or /etc/group)
498+
// into dir and ensures the current user and group are present so that the mock
499+
// containers can resolve the connecting UID even when it is only provided through
500+
// NSS (e.g. an LDAP/SSSD user not listed in the local files). It returns the path
501+
// to the generated file.
502+
func writeUserDatabase(dir, name, src string) string {
503+
content, err := os.ReadFile(src)
504+
if err != nil {
505+
log.Fatalf("Setup: can't read %s: %v", src, err)
506+
}
507+
508+
// Resolve the current user (passwd) or group (group) entry through NSS and
509+
// append it if it isn't already provided by the local file.
510+
var id, entry string
511+
switch name {
512+
case "passwd":
513+
id = strconv.Itoa(os.Getuid())
514+
case "group":
515+
id = strconv.Itoa(os.Getgid())
516+
}
517+
518+
// #nosec G204: name and id are controlled by the test.
519+
out, err := exec.Command("getent", name, id).Output()
520+
if err == nil {
521+
entry = strings.TrimSpace(string(out))
522+
}
523+
if entry != "" {
524+
field := entry[:strings.Index(entry, ":")+1]
525+
if !bytes.Contains(content, []byte("\n"+field)) && !bytes.HasPrefix(content, []byte(field)) {
526+
if len(content) > 0 && content[len(content)-1] != '\n' {
527+
content = append(content, '\n')
528+
}
529+
content = append(content, []byte(entry+"\n")...)
530+
}
531+
}
532+
533+
dest := filepath.Join(dir, name)
534+
if err := os.WriteFile(dest, content, 0644); err != nil {
535+
log.Fatalf("Setup: can't write %s database: %v", name, err)
536+
}
537+
return dest
538+
}
539+
477540
// dbusAnswer will flip to which polkit and systemd mock to communicate to:
478541
// - yes for polkit always authorizing our actions, with a harcoded startup time and next refresh unit time.
479542
// - no for polkit always denying our actions, with a harcoded startup time and next refresh unit time.

internal/ad/ad.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,13 @@ func New(ctx context.Context, configBackend backends.Backend, hostname string, o
149149
}
150150
}
151151

152+
// Allow integration tests running the real daemon binary to disable
153+
// kerberos authentication, as they have no real KDC to authenticate
154+
// against. This must never be set in production.
155+
if os.Getenv("ADSYS_TESTS_WITHOUT_KERBEROS") != "" {
156+
args.withoutKerberos = true
157+
}
158+
152159
krb5CacheDir := filepath.Join(args.runDir, "krb5cc")
153160
if err := os.MkdirAll(filepath.Join(krb5CacheDir, "tracking"), 0700); err != nil {
154161
return nil, err

0 commit comments

Comments
 (0)