From 2d9501a56c4b0283fa406c909d21ed01239b54d6 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 10 Aug 2026 20:00:24 +0000 Subject: [PATCH 1/2] Fix CIFS mount error(79) caused by missing keyutils package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Errno 79 is ELIBACC ("Can not access a needed shared library"), not ENOKEY as previously assumed — mount.cifs prints glibc's literal strerror() text for it. It recurred with valid, correctly-captured credentials because the real cause was never authentication: cifs-utils hard-depends on the libkeyutils1 library but only Recommends the keyutils package itself, which ships /sbin/request-key and the /etc/request-key.d/*.conf handlers the kernel's upcall path invokes. Minimal cloud VPS images commonly disable install-recommends, so `apt-get install cifs-utils` alone silently skips it and every mount — guest or fully credentialed — fails identically. Install keyutils explicitly wherever cifs-utils is installed: services/base.sh's unconditional package list, vpn-data-mount.sh's lazy install-on-mount path, and tools/mount-network-drive.sh's SMB branch. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01H4k6J1qXXyYxhGEgnJaMvn --- services/base.sh | 11 ++++++++--- services/vpn-data-mount.sh | 29 +++++++++++++++++++++++------ tools/mount-network-drive.sh | 9 ++++++++- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/services/base.sh b/services/base.sh index a60d90b..5637d63 100644 --- a/services/base.sh +++ b/services/base.sh @@ -27,14 +27,19 @@ install_base() { run_cmd apt-get update -y - # Core utilities present on every install. cifs-utils here (not lazily - # installed on first use, the way tools/mount-network-drive.sh and + # Core utilities present on every install. cifs-utils/keyutils here (not + # lazily installed on first use, the way tools/mount-network-drive.sh and # vpn-data-mount.sh's own local-mount step would otherwise do it) so SMB # mounts work immediately whenever they're set up later, same reasoning # as Docker/Compose being unconditional here instead of on-demand. + # keyutils explicitly, not left to cifs-utils' Recommends — some minimal + # cloud VPS images disable install-recommends, and without keyutils' + # /etc/request-key.d handlers every mount.cifs call (guest or fully + # credentialed) fails with "mount error(79): Can not access a needed + # shared library" regardless of the password being correct. run_cmd apt-get install -y \ net-tools ncdu git curl wget htop btop tree zip unzip \ - ca-certificates gnupg jq rsync ssh-import-id cifs-utils \ + ca-certificates gnupg jq rsync ssh-import-id cifs-utils keyutils \ || log_warning "Some essential packages failed to install" # glow — terminal markdown reader (charmbracelet). Not in Ubuntu repos, diff --git a/services/vpn-data-mount.sh b/services/vpn-data-mount.sh index d6e436a..5289611 100644 --- a/services/vpn-data-mount.sh +++ b/services/vpn-data-mount.sh @@ -43,12 +43,25 @@ # Mounts use real Samba credentials (a username/password you provide for # an account that already exists on the home box), stored locally in a # root-only credentials file, same convention tools/mount-network-drive.sh -# already uses — never guest access. A CIFS guest mount with no explicit -# security mode can hit "mount error(79): Can not access a needed shared -# library" — a misleadingly-worded cifs-utils message for errno 79 -# (ENOKEY), a known rough edge in the kernel cifs.ko keyring/upcall path -# for anonymous sessions. Credentialed mounts with an explicit sec=ntlmssp -# take the normal NTLMSSP auth path instead and don't hit it. +# already uses — never guest access. +# +# "mount error(79): Can not access a needed shared library" is NOT a +# credentials problem, guest-vs-authenticated problem, or a mislabeled +# ENOKEY — errno 79 is literally ELIBACC, and mount.cifs prints glibc's +# literal strerror() text for it. Confirmed live: this recurred identically +# with a real Samba account and a verified, correctly-captured password +# (see the read()/IFS note above — that was a real bug too, just not this +# one). Root cause is the `keyutils` package being missing on the client +# (VPS) side: mount.cifs dlopen()s libkeyutils.so.1 at runtime for the +# upcall path (idmapping/SPNEGO), and while cifs-utils hard-depends on the +# libkeyutils1 *library*, the keyutils *package* — which ships +# /sbin/request-key and the /etc/request-key.d/*.conf handler +# registrations the kernel's upcall actually invokes — is only a Recommends. +# Plenty of minimal cloud VPS images (unlike a typical desktop/full-server +# install) turn off APT's install-recommends, so `apt-get install +# cifs-utils` alone silently skips it and every mount — guest or fully +# credentialed — fails the same way. Install `keyutils` explicitly instead +# of relying on it riding along. # ── Standalone bootstrap ────────────────────────────────────────────────────── if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then @@ -322,6 +335,10 @@ _vdm_mount_local() { local host="$1" share_name="$2" mount_point="$3" label="$4" smb_user="$5" smb_pass="$6" command -v mount.cifs >/dev/null 2>&1 || apt-get install -y cifs-utils -qq + # Explicit, not left to cifs-utils' Recommends — see file header on + # errno 79/ELIBACC. dpkg -s (not command -v: keyutils ships no binary + # this script calls directly, just the request-key handler files). + dpkg -s keyutils >/dev/null 2>&1 || apt-get install -y keyutils -qq mkdir -p "$mount_point" diff --git a/tools/mount-network-drive.sh b/tools/mount-network-drive.sh index e1ebb86..60260f2 100644 --- a/tools/mount-network-drive.sh +++ b/tools/mount-network-drive.sh @@ -29,7 +29,14 @@ ACTUAL_GID="$(id -g "$ACTUAL_USER")" ensure_packages() { local pkgs=() case "$1" in - smb) command -v mount.cifs &>/dev/null || pkgs+=(cifs-utils) ;; + smb) + command -v mount.cifs &>/dev/null || pkgs+=(cifs-utils) + # keyutils explicitly, not left to cifs-utils' Recommends — on + # images with install-recommends disabled, missing keyutils + # makes every mount.cifs call fail with "mount error(79): Can + # not access a needed shared library" regardless of credentials. + dpkg -s keyutils &>/dev/null || pkgs+=(keyutils) + ;; nfs) command -v mount.nfs &>/dev/null || pkgs+=(nfs-common) ;; esac if [[ ${#pkgs[@]} -gt 0 ]]; then From 9e886ff9a7fe12a1d0bae80e1a6fd19894b6ae10 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 10 Aug 2026 20:11:05 +0000 Subject: [PATCH 2/2] Fix CIFS mount error(79) caused by missing nls_utf8 kernel module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The keyutils fix alone didn't resolve it — confirmed live with keyutils already installed, the same error persisted. Root cause: the hardcoded iocharset=utf8 mount option requires the kernel's nls_utf8 module, which some kernels don't ship at all (confirmed live: `modprobe nls_utf8` on a stock Ubuntu 6.8.0-137-generic VPS kernel returns "FATAL: Module nls_utf8 not found" — not loadable, not built in). Every such mount fails with errno 79 (ELIBACC) regardless of credentials, which is why this recurred identically after the keyutils fix. Both vpn-data-mount.sh and mount-network-drive.sh now probe with a harmless `modprobe nls_utf8` before adding the option, and mount without it (falling back to the kernel's build-time nls_default) with a clear warning if the module isn't available, instead of hard-failing. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01H4k6J1qXXyYxhGEgnJaMvn --- services/vpn-data-mount.sh | 45 +++++++++++++++++++++++++----------- tools/mount-network-drive.sh | 14 ++++++++++- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/services/vpn-data-mount.sh b/services/vpn-data-mount.sh index 5289611..a2a9ba8 100644 --- a/services/vpn-data-mount.sh +++ b/services/vpn-data-mount.sh @@ -51,17 +51,26 @@ # literal strerror() text for it. Confirmed live: this recurred identically # with a real Samba account and a verified, correctly-captured password # (see the read()/IFS note above — that was a real bug too, just not this -# one). Root cause is the `keyutils` package being missing on the client -# (VPS) side: mount.cifs dlopen()s libkeyutils.so.1 at runtime for the -# upcall path (idmapping/SPNEGO), and while cifs-utils hard-depends on the -# libkeyutils1 *library*, the keyutils *package* — which ships -# /sbin/request-key and the /etc/request-key.d/*.conf handler -# registrations the kernel's upcall actually invokes — is only a Recommends. -# Plenty of minimal cloud VPS images (unlike a typical desktop/full-server -# install) turn off APT's install-recommends, so `apt-get install -# cifs-utils` alone silently skips it and every mount — guest or fully -# credentialed — fails the same way. Install `keyutils` explicitly instead -# of relying on it riding along. +# one), and again after keyutils was already installed — so it's not that +# either, at least not on every host. Two independent real causes share +# this exact errno/message, both fixed defensively below: +# 1. `keyutils` missing on the client. cifs-utils hard-depends on the +# libkeyutils1 *library* but only Recommends the keyutils *package* +# (/sbin/request-key + /etc/request-key.d/*.conf, what the kernel's +# upcall actually invokes) — minimal cloud images that disable +# install-recommends silently skip it. +# 2. The hardcoded `iocharset=utf8` mount option needs the kernel's +# nls_utf8 module. Confirmed live on a stock Ubuntu 6.8.0-137-generic +# VPS kernel: `modprobe nls_utf8` → "FATAL: Module nls_utf8 not found" +# — not loadable, not built in, just absent from that kernel build. +# Every mount asking for that codepage fails with errno 79 regardless +# of credentials. `_vdm_mount_local` probes for it with a harmless +# `modprobe` and only adds `iocharset=utf8` if it actually loads; +# otherwise it warns and mounts without it (kernel falls back to its +# build's nls_default — fine for ASCII-heavy filenames, the common +# case for a home-data share; non-ASCII filenames may not round-trip +# perfectly on a kernel missing this module, which is a kernel +# limitation this script can't paper over further). # ── Standalone bootstrap ────────────────────────────────────────────────────── if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then @@ -353,8 +362,18 @@ CREDS chmod 600 "$creds_file" chown root:root "$creds_file" - # sec=ntlmssp explicitly — see the file header on errno 79/ENOKEY. - local opts="credentials=${creds_file},sec=ntlmssp,uid=$(id -u "$ACTUAL_USER"),gid=$(id -g "$ACTUAL_USER"),iocharset=utf8,nofail,_netdev" + # sec=ntlmssp explicitly — see the file header on errno 79. + local opts="credentials=${creds_file},sec=ntlmssp,uid=$(id -u "$ACTUAL_USER"),gid=$(id -g "$ACTUAL_USER"),nofail,_netdev" + + # iocharset=utf8 only if the kernel can actually load nls_utf8 — see + # the file header. modprobe on an already-loaded/built-in module is a + # harmless no-op, so this is safe to call unconditionally. + if modprobe nls_utf8 >/dev/null 2>&1; then + opts="${opts},iocharset=utf8" + else + log_warning "This kernel ($(uname -r)) has no nls_utf8 module — mounting without iocharset=utf8. Non-ASCII filenames may not display correctly; try 'sudo apt-get install --reinstall linux-modules-$(uname -r)' to see if it restores the module." + fi + local share="//${host}/${share_name}" log_info "Testing mount..." diff --git a/tools/mount-network-drive.sh b/tools/mount-network-drive.sh index 60260f2..70604bb 100644 --- a/tools/mount-network-drive.sh +++ b/tools/mount-network-drive.sh @@ -121,7 +121,19 @@ CREDS local ver_opt="" [[ -n "$smb_ver" ]] && ver_opt=",vers=${smb_ver}" - local opts="uid=${ACTUAL_UID},gid=${ACTUAL_GID},${creds_opt}${ver_opt},iocharset=utf8,nofail,_netdev" + local opts="uid=${ACTUAL_UID},gid=${ACTUAL_GID},${creds_opt}${ver_opt},nofail,_netdev" + + # iocharset=utf8 only if the kernel can actually load nls_utf8 — some + # kernels (confirmed live: a stock Ubuntu 6.8.0-137-generic VPS) don't + # ship that module at all, and mount.cifs fails every such mount with + # "mount error(79): Can not access a needed shared library" regardless + # of credentials. modprobe on an already-loaded/built-in module is a + # harmless no-op, so this check is safe to run unconditionally. + if modprobe nls_utf8 >/dev/null 2>&1; then + opts="${opts},iocharset=utf8" + else + warn "This kernel ($(uname -r)) has no nls_utf8 module — mounting without iocharset=utf8. Non-ASCII filenames may not display correctly; try 'sudo apt-get install --reinstall linux-modules-$(uname -r)' to see if it restores the module." + fi _do_mount "cifs" "$share" "$mount_point" "$opts" }