Guest User

OpenSSH FeatureRequest: PamServiceName

a guest
Mar 12th, 2019
138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.62 KB | None | 0 0
  1. Hi,
  2.  
  3. I am trying to setup OpenSSH for 2 factor authentication.
  4. Specifically, I want users to be able to log in with either:
  5. public key + liboath token
  6. or
  7. password + liboath token
  8.  
  9. as well as public key only for some privileged internal hosts
  10. and public key or password for user/host pairs that recently logged in succesfully.
  11.  
  12. I managed to do this, but it's very hacky. I think openssh needs to be modified to facilitate this use case better.
  13. My Solution:
  14. I set in sshd_config:
  15. PasswordAuthentication yes
  16. ChallengeResponseAuthentication yes
  17. PubkeyAuthentication yes
  18. UsePAM yes
  19. AuthenticationMethods publickey,keyboard-interactive password,keyboard-interactive
  20. Match Address [privileged address/range]
  21. AuthenticaionMethods publickey
  22.  
  23. Now I can set up /etc/pam.d/sshd in such a way, it asks and checks the liboath token using pam_oath.so
  24.  
  25. The Problem:
  26. Both PasswordAuthentication and ChallengeResponseAuthentication use the same PAM service in /etc/pam.d/sshd for authentication. The only difference is that PasswordAuthentication does not allow a challenge response prompt via pam_conv, and "dumb" provides a password, while ChallengeResponseAuthentication allows for arbitrary prompts.
  27. As such, I have to check for both password and oath token in the same pam service configuration
  28.  
  29. Wrong solution 1:
  30. I could have either authentication method satisfy PAM,
  31.  
  32. auth [default=ignore] pam_echo.so #ask for token
  33. auth sufficient pam_unix.so nullok_secure try_first_pass
  34. auth sufficient pam_oath.so use_first_pass
  35.  
  36. but then one could enter the password twice, or the oath token twice even if asked for the other, and bypass the security check
  37.  
  38. Wrong solution 2:
  39. I could ask pam to satisfy both and get rid of password authentication, the challenge response will then ask for both password AND oath token with separate prompts:
  40.  
  41. auth [default=ignore] pam_echo.so #ask for password
  42. auth required pam_unix.so nullok_secure try_first_pass
  43. auth [default=ignore] pam_echo.so #ask for token
  44. auth sufficient pam_oath.so
  45.  
  46. but that breaks the keybased authentication, as it would ask for all 3: key, password AND token
  47.  
  48. Hacky Solution:
  49. I can make a custom script or pam module that somehow guesses which case is present and enforces the correct behavior, but pam is really not flexible enough to do this gracefully in the same service config:
  50.  
  51. My choice was to use pam_script.so This third party module forks a process which runs a shell script with password/token, host, service name, ... in env variables. It has the advantage that it is already written, but the disadvantage that it is limited in its I/O. It can indicate success or failure through return code but is unable to access the pam_conv conversation and as such cannot actively do challenge response dialogs.
  52.  
  53. auth [default=ignore] pam_echo.so #ask for token
  54. auth [success=ignore default=die] pam_script.so use_first_pass # runs an auth check script.
  55. auth sufficient pam_unix.so nullok_secure try_first_pass
  56. auth sufficient pam_oath.so use_first_pass
  57.  
  58. The check script needs to distinguish two valid cases:
  59. Case 1:
  60. PAM was called via PasswordAuthentication.
  61. The supplied password is a login password
  62. return success. pam_unix will then validate the password, while pam_oath will fail
  63. Case 2:
  64. PAM was called via ChallengeResponseAuthentication
  65. The supplied password is a syntactically correct OATH token.
  66. return success. pam_oath will then validate the token, while pam_unix will fail
  67. Else:
  68. return failure and cause authentication to fail hard.
  69.  
  70. Identifying the password is straightforward, as OATH tokens are too short to be accepted as passwords and can be identified with regular expression.
  71. The tricky part is identifieing if sshd called pam from Password or ChallengeResponse authentication.
  72.  
  73. If I were to write my own pam module, I could try to initiate my own challenge response (which would hopefully fail for PasswordAuthentication) but this is a callback function I cannot call from a shell script in a forked process environment
  74.  
  75. The Hack:
  76. Although ChallengeResponse authentication forks a subprocess for pam authentication, this process has a socket open pair open ( auth-pam.c line 798 ctxt->psock & csock ) for communication with the sshd mother process (used for challenge and return)
  77. When pam-script.so forks the calling PAM authentication process, it does not close the forked file descriptors.before starting the script. As such the open file descriptios of the calling sshd authentication process are exposed through /proc/self/fd/*
  78. For ChallengeResponse authentication the above socket can be found in /proc/self/fd, while with PasswordAuthentication this is absent.
  79.  
  80. How do do this properly:
  81. Identifying the context in which PAM is called from SSHD from within PAM is - while possible - very very hacky, unclean, and possibly insecure, and might stop working with any update of openssh as it doesn't rely on any proper API
  82.  
  83. The best way how sshd could enforce a different PAM context would be by using different service names in pam_start()
  84. currently this is hardcoded to argv[0] of the sshd process (usually "sshd"). There should be at least 1 config file parameter in sshd_config to specify PAMServiceName (which could then be chosen within different Match directived)
  85.  
  86. PAMServiceName should obviously default to argv[0] for backwards compatibility
  87.  
  88. but to solve the described usecase above, PAM needs to be able to distinguish between ChallengeResponse and Password (both using PAM)
  89.  
  90. I therefore suggest two more parameters for sshd_config
  91. PasswordPAMServiceName
  92. ChallengeresponsePAMServiceName
  93.  
  94. both would default to the value of PAMServiceName if unset.
  95.  
  96. is this feasible?
Add Comment
Please, Sign In to add comment