Yubico / pam-u2f

Pluggable Authentication Module (PAM) for U2F and FIDO2

Home Page:https://developers.yubico.com/pam-u2f/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Enhancement proposal: expansion of ${USER} variable in 'authfile' module argument

rolandog opened this issue · comments

This may be related to #152 ,

As the title suggests, it would be nice to have the ${USER} variable expansion in the authfile module argument to allow for multiple users having their own sub-directory with a common structure; this would be paired with the openasuser module argument like this:

auth sufficient pam_u2f.so authfile=/etc/2fa/u2f/${USER}/u2f_mappings openasuser

This would allow for this file structure:

/etc/2fa/
└── u2f/
    └── ${USER}/
        └── u2f_mappings

Each u2f_mappings would need their according 0400 access permissions, as well as the correct user and group for each user's mappings.

This would allow for the benefits of a centralized and an individual authorization file (usage of an encrypted home directory, for instance).

Hello. Just checking in if this would sound reasonable to Yubico's pam-u2f developers.

Hi, sorry for the delay. While the exact details would probably require a closer look, my initial impression is that the idea does sound reasonable and interesting. We'd probably consider using %u as the token to align with other modules.

I cannot say exactly when we'd have time to look into an implementation, contributions are welcome!

Hey, no problem @LDVG, I understand that this season is usually really busy. Actually, I first saw this on the documentation and source code of Google's google-authenticator-libpam module (search for "${USER}"). I don't know if it is permissible to re-use functions/code from an Apache 2.0 license project on a BSD-2 clause project... so it's most likely that a clean room design would be needed for that string substitution.

I could give it a go, but I'm definitely no C expert. Also, do you think the %u expansion would be possible when a user is signing in with SSH? In a couple of weeks, I may have some spare time to do a deep dive and try to contribute.

Thanks!

Also, do you think the %u expansion would be possible when a user is signing in with SSH?

This module only works locally (barring the manual mode) since it talks directly to the authenticator. If you'd like to use FIDO2 with SSH, you might want to have a look at the SSH *-sk [1] key types (which are also recognized by pam-u2f).

[1] https://developers.yubico.com/SSH/Securing_SSH_with_FIDO2.html

Hi again,

Apologies for the long delays. If you're still interested in this feature, we have a candidate implementation and documentation pushed to the expand branch. If you're willing to try it out and have feedback for us, we'd very much appreciate it. 🙂

No worries! And thanks for taking the time to work on it.

I'll give it a test after work, as I'll be leaving the day after tomorrow for a couple of weeks on vacation, but I'd love to have helped out to test it.

Anything in particular you would like me to check/report on?

Thank you!

Anything in particular you would like me to check/report on?

Nothing in particular, mostly a sanity check that the feature behavior/arguments/documentation makes sense and matches what you had in mind or if I've missed any subtleties. 🙂

I have tested both with and without the openasuser option (having the mappings associated to the user, or to root). Both worked like a charm!

The only observation that I can think of making is to perhaps make a small note to mention that, in some cases, libpam0g-dev provides libpam-dev.

Here is some of the stderr output in case it is useful:

autoreconf --install
user@computer:~/projects/pam-u2f$ autoreconf --install 
libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, 'build-aux'.
libtoolize: copying file 'build-aux/ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'.
libtoolize: copying file 'm4/libtool.m4'
libtoolize: copying file 'm4/ltoptions.m4'
libtoolize: copying file 'm4/ltsugar.m4'
libtoolize: copying file 'm4/ltversion.m4'
libtoolize: copying file 'm4/lt~obsolete.m4'
configure.ac:17: installing 'build-aux/ar-lib'
configure.ac:15: installing 'build-aux/compile'
configure.ac:8: installing 'build-aux/config.guess'
configure.ac:8: installing 'build-aux/config.sub'
configure.ac:10: installing 'build-aux/install-sh'
configure.ac:10: installing 'build-aux/missing'
Makefile.am: installing 'build-aux/depcomp'
parallel-tests: installing 'build-aux/test-driver'
./configure
user@computer:~/projects/pam-u2f$ ./configure 
checking build system type... x86_64-pc-linux-gnu
checking host system type... x86_64-pc-linux-gnu
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a race-free mkdir -p... /usr/bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking whether make supports nested variables... (cached) yes
checking whether to enable maintainer-specific portions of Makefiles... no
checking whether make supports the include directive... yes (GNU style)
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables... 
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether the compiler supports GNU C... yes
checking whether gcc accepts -g... yes
checking for gcc option to enable C11 features... none needed
checking whether gcc understands -c and -o together... yes
checking dependency style of gcc... gcc3
checking for stdio.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for strings.h... yes
checking for sys/stat.h... yes
checking for sys/types.h... yes
checking for unistd.h... yes
checking for wchar.h... yes
checking for minix/config.h... no
checking whether it is safe to define __EXTENSIONS__... yes
checking whether _XOPEN_SOURCE should be defined... no
checking for ar... ar
checking the archiver (ar) interface... ar
checking how to print strings... printf
checking for a sed that does not truncate output... /usr/bin/sed
checking for grep that handles long lines and -e... /usr/bin/grep
checking for egrep... /usr/bin/grep -E
checking for fgrep... /usr/bin/grep -F
checking for ld used by gcc... /usr/bin/ld
checking if the linker (/usr/bin/ld) is GNU ld... yes
checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
checking the name lister (/usr/bin/nm -B) interface... BSD nm
checking whether ln -s works... yes
checking the maximum length of command line arguments... 1572864
checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop
checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop
checking for /usr/bin/ld option to reload object files... -r
checking for file... file
checking for objdump... objdump
checking how to recognize dependent libraries... pass_all
checking for dlltool... no
checking how to associate runtime and link libraries... printf %s\n
checking for archiver @FILE support... @
checking for strip... strip
checking for ranlib... ranlib
checking command to parse /usr/bin/nm -B output from gcc object... ok
checking for sysroot... no
checking for a working dd... /usr/bin/dd
checking how to truncate binary pipes... /usr/bin/dd bs=4096 count=1
checking for mt... mt
checking if mt is a manifest tool... no
checking for dlfcn.h... yes
checking for objdir... .libs
checking if gcc supports -fno-rtti -fno-exceptions... no
checking for gcc option to produce PIC... -fPIC -DPIC
checking if gcc PIC flag -fPIC -DPIC works... yes
checking if gcc static flag -static works... yes
checking if gcc supports -c -o file.o... yes
checking if gcc supports -c -o file.o... (cached) yes
checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
checking whether -lc should be explicitly linked in... no
checking dynamic linker characteristics... GNU/Linux ld.so
checking how to hardcode library paths into programs... immediate
checking whether stripping libraries is possible... yes
checking if libtool supports shared libraries... yes
checking whether to build shared libraries... yes
checking whether to build static libraries... no
checking for gcc... (cached) gcc
checking whether the compiler supports GNU C... (cached) yes
checking whether gcc accepts -g... (cached) yes
checking for gcc option to enable C11 features... (cached) none needed
checking whether gcc understands -c and -o together... (cached) yes
checking dependency style of gcc... (cached) gcc3
checking for security/pam_appl.h... yes
checking for security/pam_modules.h... yes
checking for security/pam_modutil.h... yes
checking for security/openpam.h... no
checking for pam_start in -lpam... yes
checking for pam_modutil_drop_priv... yes
checking for openpam_borrow_cred... no
checking for pkg-config... /usr/bin/pkg-config
checking pkg-config is at least version 0.9.0... yes
checking for libcrypto... yes
checking for libfido2 >= 1.3.0... yes
checking for secure_getenv... yes
checking for strlcpy... no
checking for readpassphrase... no
checking for explicit_bzero... yes
checking for memset_s... no
checking whether C compiler accepts -Werror=unknown-warning-option... no
checking whether C compiler accepts -Wall... yes
checking whether C compiler accepts -Wextra... yes
checking whether C compiler accepts -Wconversion... yes
checking whether C compiler accepts -Wconversion... (cached) yes
checking whether C compiler accepts -Wpedantic... yes
checking whether C compiler accepts -Wformat=2... yes
checking whether C compiler accepts -Wstrict-prototypes... yes
checking whether C compiler accepts -Wmissing-declarations... yes
checking whether C compiler accepts -Wmissing-prototypes... yes
checking whether C compiler accepts -Wnull-dereference... yes
checking whether C compiler accepts -Wshadow... yes
checking whether C compiler accepts -Wpointer-arith... yes
checking whether C compiler accepts -Wno-unused-but-set-variable... yes
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating Makefile
config.status: creating pamu2fcfg/Makefile
config.status: creating tests/Makefile
config.status: creating fuzz/Makefile
config.status: creating man/Makefile
config.status: creating tests/credentials/new_double_-N.cred
config.status: creating tests/credentials/new_double_-P-N.cred
config.status: creating tests/credentials/new_double_-P.cred
config.status: creating tests/credentials/new_double_-P-V-N.cred
config.status: creating tests/credentials/new_double_-P-V.cred
config.status: creating tests/credentials/new_double_-r-N.cred
config.status: creating tests/credentials/new_double_-r-P-N.cred
config.status: creating tests/credentials/new_double_-r-P.cred
config.status: creating tests/credentials/new_double_-r-P-V-N.cred
config.status: creating tests/credentials/new_double_-r-P-V.cred
config.status: creating tests/credentials/new_double_-r.cred
config.status: creating tests/credentials/new_double_-r-V-N.cred
config.status: creating tests/credentials/new_double_-r-V.cred
config.status: creating tests/credentials/new_double_.cred
config.status: creating tests/credentials/new_double_-V-N.cred
config.status: creating tests/credentials/new_double_-V.cred
config.status: creating tests/credentials/new_mixed_12.cred
config.status: creating tests/credentials/new_mixed_1-P2.cred
config.status: creating tests/credentials/new_mixed_-P12.cred
config.status: creating tests/credentials/new_mixed_-P1-P2.cred
config.status: creating tests/credentials/new_-N.cred
config.status: creating tests/credentials/new_-P-N.cred
config.status: creating tests/credentials/new_-P.cred
config.status: creating tests/credentials/new_-P-V-N.cred
config.status: creating tests/credentials/new_-P-V.cred
config.status: creating tests/credentials/new_-r-N.cred
config.status: creating tests/credentials/new_-r-P-N.cred
config.status: creating tests/credentials/new_-r-P.cred
config.status: creating tests/credentials/new_-r-P-V-N.cred
config.status: creating tests/credentials/new_-r-P-V.cred
config.status: creating tests/credentials/new_-r.cred
config.status: creating tests/credentials/new_-r-V-N.cred
config.status: creating tests/credentials/new_-r-V.cred
config.status: creating tests/credentials/new_.cred
config.status: creating tests/credentials/new_-V-N.cred
config.status: creating tests/credentials/new_-V.cred
config.status: creating tests/credentials/old_credential.cred
config.status: creating tests/credentials/ssh_credential.cred
config.status: creating tests/credentials/new_limited_count.cred
config.status: executing depfiles commands
config.status: executing libtool commands
configure: Summary of build options:

  Version:             1.2.2
  Host type:           x86_64-pc-linux-gnu
  Install prefix:      /usr/local
  Compiler:            gcc
  CFLAGS:              -g -O2
  CWFLAGS:             -Wall -Wextra -Wconversion -Wno-sign-conversion -Wpedantic -Wformat=2 -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -Wnull-dereference -Wshadow -Wpointer-arith
  CSFLAGS:             -Wno-unused-but-set-variable
  Library types:       Shared=yes, Static=no
  LIBFIDO2 CFLAGS:     
  LIBFIDO2 LIBS:       -lfido2 -lcrypto
  LIBCRYPTO CFLAGS:    
  LIBCRYPTO LIBS:      -lcrypto
  PAMDIR:              /lib/x86_64-linux-gnu/security
make (warnings; Guix's python couldn't find asciidoc)
user@computer:~/projects/pam-u2f$ make
Making all in .
make[1]: Entering directory '/home/user/projects/pam-u2f'
  CC       pam-u2f.lo
  CC       b64.lo
  CC       debug.lo
  CC       expand.lo
  CC       explicit_bzero.lo
  CC       util.lo
  CCLD     libmodule.la
  CCLD     pam_u2f.la
make[1]: Leaving directory '/home/user/projects/pam-u2f'
Making all in pamu2fcfg
make[1]: Entering directory '/home/user/projects/pam-u2f/pamu2fcfg'
  CC       pamu2fcfg.o
  CC       readpassphrase.o
readpassphrase.c: In function ‘readpassphrase’:
readpassphrase.c:133:23: warning: ignoring return value of ‘write’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
  133 |                 (void)write(output, prompt, strlen(prompt));
      |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
readpassphrase.c:152:23: warning: ignoring return value of ‘write’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
  152 |                 (void)write(output, "\n", 1);
      |                       ^~~~~~~~~~~~~~~~~~~~~~
  CC       strlcpy.o
  CC       ../util.o
  CC       ../b64.o
  CC       ../explicit_bzero.o
  CCLD     pamu2fcfg
make[1]: Leaving directory '/home/user/projects/pam-u2f/pamu2fcfg'
Making all in tests
make[1]: Entering directory '/home/user/projects/pam-u2f/tests'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/home/user/projects/pam-u2f/tests'
Making all in man
make[1]: Entering directory '/home/user/projects/pam-u2f/man'
  GEN      pamu2fcfg.1
/home/user/.guix-profile/bin/python3: Error while finding module specification for 'asciidoc.a2x' (ModuleNotFoundError: No module named 'asciidoc')
make[1]: *** [Makefile:581: pamu2fcfg.1] Error 1
make[1]: Leaving directory '/home/user/projects/pam-u2f/man'
make: *** [Makefile:782: all-recursive] Error 1
make (fixed PATH)
user@computer:~/projects/pam-u2f$ make
Making all in .
make[1]: Entering directory '/home/user/projects/pam-u2f'
make[1]: Nothing to be done for 'all-am'.
make[1]: Leaving directory '/home/user/projects/pam-u2f'
Making all in pamu2fcfg
make[1]: Entering directory '/home/user/projects/pam-u2f/pamu2fcfg'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/home/user/projects/pam-u2f/pamu2fcfg'
Making all in tests
make[1]: Entering directory '/home/user/projects/pam-u2f/tests'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/home/user/projects/pam-u2f/tests'
Making all in man
make[1]: Entering directory '/home/user/projects/pam-u2f/man'
  GEN      pamu2fcfg.1
  GEN      pam_u2f.8
make[1]: Leaving directory '/home/user/projects/pam-u2f/man'
make install
user@computer:~/projects/pam-u2f$ make install
Making install in .
make[1]: Entering directory '/home/user/projects/pam-u2f'
make[2]: Entering directory '/home/user/projects/pam-u2f'
 /usr/bin/mkdir -p '/lib/x86_64-linux-gnu/security'
 /bin/bash ./libtool   --mode=install /usr/bin/install -c   pam_u2f.la '/lib/x86_64-linux-gnu/security'
libtool: install: /usr/bin/install -c .libs/pam_u2f.so /lib/x86_64-linux-gnu/security/pam_u2f.so
/usr/bin/install: cannot create regular file '/lib/x86_64-linux-gnu/security/pam_u2f.so': Permission denied
make[2]: *** [Makefile:673: install-pampluginexecLTLIBRARIES] Error 1
make[2]: Leaving directory '/home/user/projects/pam-u2f'
make[1]: *** [Makefile:1091: install-am] Error 2
make[1]: Leaving directory '/home/user/projects/pam-u2f'
make: *** [Makefile:782: install-recursive] Error 1
sudo make install
user@computer:~/projects/pam-u2f$ sudo make install
Making install in .
make[1]: Entering directory '/home/user/projects/pam-u2f'
make[2]: Entering directory '/home/user/projects/pam-u2f'
 /usr/bin/mkdir -p '/lib/x86_64-linux-gnu/security'
 /bin/bash ./libtool   --mode=install /usr/bin/install -c   pam_u2f.la '/lib/x86_64-linux-gnu/security'
libtool: install: /usr/bin/install -c .libs/pam_u2f.so /lib/x86_64-linux-gnu/security/pam_u2f.so
libtool: install: /usr/bin/install -c .libs/pam_u2f.lai /lib/x86_64-linux-gnu/security/pam_u2f.la
libtool: finish: PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:/sbin" ldconfig -n /lib/x86_64-linux-gnu/security
----------------------------------------------------------------------
Libraries have been installed in:
   /lib/x86_64-linux-gnu/security

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the '-LLIBDIR'
flag during linking and do at least one of the following:
   - add LIBDIR to the 'LD_LIBRARY_PATH' environment variable
     during execution
   - add LIBDIR to the 'LD_RUN_PATH' environment variable
     during linking
   - use the '-Wl,-rpath -Wl,LIBDIR' linker flag
   - have your system administrator add LIBDIR to '/etc/ld.so.conf'

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------
make  install-exec-hook
make[3]: Entering directory '/home/user/projects/pam-u2f'
rm -f /lib/x86_64-linux-gnu/security/pam_u2f.la
chmod -f 644 /lib/x86_64-linux-gnu/security/pam_u2f.so || true
make[3]: Leaving directory '/home/user/projects/pam-u2f'
make[2]: Nothing to be done for 'install-data-am'.
make[2]: Leaving directory '/home/user/projects/pam-u2f'
make[1]: Leaving directory '/home/user/projects/pam-u2f'
Making install in pamu2fcfg
make[1]: Entering directory '/home/user/projects/pam-u2f/pamu2fcfg'
make[2]: Entering directory '/home/user/projects/pam-u2f/pamu2fcfg'
 /usr/bin/mkdir -p '/usr/local/bin'
  /bin/bash ../libtool   --mode=install /usr/bin/install -c pamu2fcfg '/usr/local/bin'
libtool: install: /usr/bin/install -c pamu2fcfg /usr/local/bin/pamu2fcfg
make[2]: Nothing to be done for 'install-data-am'.
make[2]: Leaving directory '/home/user/projects/pam-u2f/pamu2fcfg'
make[1]: Leaving directory '/home/user/projects/pam-u2f/pamu2fcfg'
Making install in tests
make[1]: Entering directory '/home/user/projects/pam-u2f/tests'
make[2]: Entering directory '/home/user/projects/pam-u2f/tests'
make[2]: Nothing to be done for 'install-exec-am'.
make[2]: Nothing to be done for 'install-data-am'.
make[2]: Leaving directory '/home/user/projects/pam-u2f/tests'
make[1]: Leaving directory '/home/user/projects/pam-u2f/tests'
Making install in man
make[1]: Entering directory '/home/user/projects/pam-u2f/man'
make[2]: Entering directory '/home/user/projects/pam-u2f/man'
make[2]: Nothing to be done for 'install-exec-am'.
 /usr/bin/mkdir -p '/usr/local/share/man/man1'
 /usr/bin/install -c -m 644 pamu2fcfg.1 '/usr/local/share/man/man1'
 /usr/bin/mkdir -p '/usr/local/share/man/man8'
 /usr/bin/install -c -m 644 pam_u2f.8 '/usr/local/share/man/man8'
make[2]: Leaving directory '/home/user/projects/pam-u2f/man'
make[1]: Leaving directory '/home/user/projects/pam-u2f/man'

Again, thanks so much for taking the time to implement this feature!