From c340e79ee308aad0b84052d2a5187e3e1047c703 Mon Sep 17 00:00:00 2001 From: Ludwig Lehnert Date: Wed, 18 Feb 2026 19:57:08 +0100 Subject: [PATCH] attempted fix on group shares not appearing (GID not found) (4) --- README.md | 2 +- app/init.sh | 51 ++++++++++++++++++----------------------- app/reconcile_shares.py | 8 +++++-- etc/samba/smb.conf | 9 +++----- 4 files changed, 32 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 6cc2a75..2a70932 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,7 @@ Kerberos requires close time alignment. - Backing path: `/data/groups/` - Share exposure generated in `/etc/samba/generated/shares.conf` - Dynamic share names are validated for SMB compatibility and deduplicated case-insensitively. -- Group membership changes are refreshed during each reconciliation cycle (winbind cache flush + Samba config reload). +- Group membership changes are refreshed continuously via winbind cache updates (`winbind cache time = 60`) and Samba config reload during reconciliation. ## Useful Commands diff --git a/app/init.sh b/app/init.sh index 294257e..ae47f01 100755 --- a/app/init.sh +++ b/app/init.sh @@ -64,21 +64,8 @@ derive_netbios_name() { resolve_sid_to_group() { local sid="$1" - local gid="" - local gid_entry="" local resolved_name="" local sid_output="" - local candidate="" - local lower_candidate="" - - gid="$(wbinfo --sid-to-gid "$sid" 2>/dev/null || true)" - if [[ -n "$gid" ]]; then - gid_entry="$(getent group "$gid" || true)" - if [[ -n "$gid_entry" ]]; then - printf '%s\n' "${gid_entry%%:*}" - return 0 - fi - fi if sid_output="$(wbinfo --sid-to-fullname "$sid" 2>/dev/null)"; then resolved_name="${sid_output%%$'\t'*}" @@ -94,25 +81,30 @@ resolve_sid_to_group() { return 1 fi - for candidate in "$resolved_name" "${resolved_name#*\\}"; do - if [[ -z "$candidate" ]]; then - continue - fi - if getent group "$candidate" >/dev/null 2>&1; then - printf '%s\n' "$candidate" - return 0 - fi - lower_candidate="${candidate,,}" - if [[ "$lower_candidate" != "$candidate" ]] && getent group "$lower_candidate" >/dev/null 2>&1; then - printf '%s\n' "$lower_candidate" - return 0 - fi - done - - printf '[init] WARN: SID %s resolved to %s but NSS lookup failed; using raw name.\n' "$sid" "$resolved_name" >&2 + if [[ "$resolved_name" != *\\* ]]; then + resolved_name="${WORKGROUP}\\${resolved_name}" + fi printf '%s\n' "$resolved_name" } +ensure_machine_keytab() { + local keytab_path="/var/lib/samba/private/krb5.keytab" + mkdir -p /var/lib/samba/private + + if [[ ! -s /etc/krb5.keytab ]]; then + if ! net ads keytab create -P >/dev/null 2>&1; then + if [[ -n "${JOIN_USER:-}" && -n "${JOIN_PASSWORD:-}" ]]; then + printf '%s\n' "$JOIN_PASSWORD" | net ads keytab create -U "$JOIN_USER" >/dev/null 2>&1 || true + fi + fi + fi + + if [[ -s /etc/krb5.keytab ]]; then + cp /etc/krb5.keytab "$keytab_path" + chmod 600 "$keytab_path" + fi +} + resolve_share_groups_from_sids() { export DOMAIN_USERS_GROUP DOMAIN_USERS_GROUP="$(resolve_sid_to_group "$DOMAIN_USERS_SID")" @@ -249,6 +241,7 @@ derive_netbios_name render_krb5_conf render_smb_conf join_domain_if_needed +ensure_machine_keytab log 'Starting winbindd' winbindd -F --no-process-group & diff --git a/app/reconcile_shares.py b/app/reconcile_shares.py index f804b7d..72fb609 100755 --- a/app/reconcile_shares.py +++ b/app/reconcile_shares.py @@ -386,7 +386,12 @@ def reconcile_db(conn: sqlite3.Connection, ad_groups: List[Dict[str, str]]) -> N def qualify_group(group_name: str) -> str: - return f'+"{group_name}"' + if "\\" in group_name: + return f'@"{group_name}"' + workgroup = os.getenv("WORKGROUP", "").strip() + if workgroup: + return f'@"{workgroup}\\{group_name}"' + return f'@"{group_name}"' def is_valid_share_name(share_name: str) -> bool: @@ -731,7 +736,6 @@ def with_lock() -> bool: sync_public_directory() sync_private_directories() - refresh_winbind_cache() reload_samba() log("Reconciliation completed") return True diff --git a/etc/samba/smb.conf b/etc/samba/smb.conf index a156a5f..6a9f0db 100644 --- a/etc/samba/smb.conf +++ b/etc/samba/smb.conf @@ -14,6 +14,7 @@ winbind use default domain = yes winbind enum users = yes winbind enum groups = yes + winbind cache time = 60 vfs objects = acl_xattr map acl inherit = yes @@ -48,15 +49,11 @@ full_audit:success = all full_audit:failure = all full_audit:syslog = false - valid users = +"${DOMAIN_USERS_GROUP}" + valid users = @"${DOMAIN_USERS_GROUP}" hide unreadable = yes access based share enum = yes ea support = yes nt acl support = no - security mask = 0000 - force security mode = 0000 - directory security mask = 0000 - force directory security mode = 0000 [Public] path = /data/public @@ -68,7 +65,7 @@ full_audit:success = all full_audit:failure = all full_audit:syslog = false - valid users = +"${PUBLIC_GROUP}" + valid users = @"${PUBLIC_GROUP}" force group = "${PUBLIC_GROUP}" create mask = 0660 directory mask = 2770