Skip to content

Instantly share code, notes, and snippets.

@geofft
Last active October 9, 2024 00:44
Show Gist options
  • Save geofft/257647efe3963f74b20044bd61048ddd to your computer and use it in GitHub Desktop.
Save geofft/257647efe3963f74b20044bd61048ddd to your computer and use it in GitHub Desktop.
PAM module in Swift
*.so
nixpkgs-*

This is a PAM module in Swift that builds using Nix to get dependencies. For inexplicable reasons, it does not use Nix as a build system, which might have made this a little less painful. I also wonder if this is less painful on e.g. Debian.

To build, use nix-shell -E 'with import <nixpkgs> {}; mkShell.override {stdenv = swift.stdenv;} {buildInputs = [swift swiftPackages.Foundation];}' to get a working Swift dev shell (see NixOS/nixpkgs#242779) and then run make.

To use it, add session required /path/to/libpam_swift.so to /etc/pam.d/sshd or something it includes. (Again, on NixOS, there is probably a more pleasant way to do this, but I copied the file that /etc/pam.d/sshd points to and replaced the symlink with my updated file. Don't worry, I'm doing this on a live CD in a VM.)

You should see something like:

pokio:~ geofft$ ssh [email protected]
([email protected]) Password: 
Hello from Swift!
Last login: Wed Oct  9 00:37:13 2024

[nixos@nixos:~]$

For reasons probably related to the above nixpkgs issue, I needed to explicitly add the location of libdispatch to the rpath, and then also explicitly link libdispatch (which is an indirect dependency of libswift_Concurrency, so neither the PAM module's DT_RPATH nor DT_RUNPATH will get used when locating it). The rpath issue is probably relatively Nix-specific, but I'm not actually sure why Concurrency is getting linked at all when I'm not using it, and that seems mildly concerning for a loadable module, so maybe we should solve that first.

This uses @_cdecl, which is discussed in detail in https://forums.swift.org/t/best-way-to-call-a-swift-function-from-c/9829 . If anyone really wants to start writing Linux userspace libraries in Swift, a proposal for stabilizing @_cdecl would be the first step.

all: libpam_swift.so
nixpkgs-%:
nix-build -o $@ -E 'with import <nixpkgs> {}; $*'
libpam_swift.so: pam_swift.swift nixpkgs-swift-corelibs-libdispatch nixpkgs-pam
swiftc \
-emit-library \
pam_swift.swift \
-import-objc-header nixpkgs-pam/include/security/pam_ext.h \
-I nixpkgs-pam/include \
-ldispatch \
-Xlinker -rpath \
-Xlinker `readlink -f nixpkgs-swift-corelibs-libdispatch`/lib
clean:
-rm -f `cat .gitignore`
.PHONY: all clean
@_cdecl("pam_sm_open_session")
public func pam_sm_open_session(
pamh: OpaquePointer, flags: Int32, argc: Int32, argv: UnsafePointer<UnsafePointer<Int8>?>
) -> Int32 {
withVaList([]) { va_list in
_ = pam_vprompt(pamh, PAM_TEXT_INFO, nil, "Hello from Swift!", va_list)
}
return PAM_SUCCESS
}
@_cdecl("pam_sm_close_session")
public func pam_sm_close_session(
pamh: OpaquePointer, flags: Int32, argc: Int32, argv: UnsafePointer<UnsafePointer<Int8>?>
) -> Int32 {
return PAM_SUCCESS
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment