Menu

Tree [e19ce9] master /
 History

HTTPS access


File Date Author Commit
 changelog 2019-09-18 JT Moree JT Moree [e19ce9] first attempt at integer username check failed....
 debian 2017-11-21 JT Moree JT Moree [3d7ec4] cleaned up some misc issues with deb packaging.
 doc 2017-11-03 JT Moree JT Moree [dba5eb] initial checkin
 etc 2019-09-18 JT Moree JT Moree [e26303] clean up documentation for transition to redhat...
 lib 2019-09-18 JT Moree JT Moree [e19ce9] first attempt at integer username check failed....
 sbin 2019-09-18 JT Moree JT Moree [e19ce9] first attempt at integer username check failed....
 test 2017-11-03 JT Moree JT Moree [dba5eb] initial checkin
 ASPNETIDENTITY.txt 2019-09-18 JT Moree JT Moree [e26303] clean up documentation for transition to redhat...
 Makefile 2017-12-13 JT Moree JT Moree [f49cc9] added make tar process for tarball
 README.txt 2019-09-18 JT Moree JT Moree [e26303] clean up documentation for transition to redhat...
 SFTP.txt 2019-09-18 JT Moree JT Moree [e26303] clean up documentation for transition to redhat...
 TODO.txt 2017-11-06 JT Moree JT Moree [bab796] fleshed out xml changelog conversion to deb and...
 conf 2019-09-18 JT Moree JT Moree [e19ce9] first attempt at integer username check failed....
 configure 2017-11-03 JT Moree JT Moree [dba5eb] initial checkin
 debuild-wrapper 2017-11-21 JT Moree JT Moree [3d7ec4] cleaned up some misc issues with deb packaging.
 pam-anyauth.cron 2017-12-07 JT Moree JT Moree [147ab6] <ITEM>replaced wonky write-debug, write-verbose...
 pam-anyauth.logrotate 2017-12-13 JT Moree JT Moree [8706c6] removed OUTGOING option. use /etc/skel instead
 pam-anyauth.spec.in 2019-09-18 JT Moree JT Moree [e26303] clean up documentation for transition to redhat...
 rpmbuild-wrapper 2017-11-06 JT Moree JT Moree [bab796] fleshed out xml changelog conversion to deb and...
 tar-wrapper 2017-12-13 JT Moree JT Moree [f49cc9] added make tar process for tarball

Read Me

pam-anyauth
===========

This project allows pam to authenticate users against anything you desire

tl;dr

* install pam-anyauth utilities using your preferred method
 - yum install pam-anyauth
 - apt install pam-anyauth
 - ./configure && make install
* setup odbc and isql if using it for accessing credentials
* create user/pass SQL query
* configure files in /etc/pam-anyauth
* test pam-anyauth
* modify pam configuration to use pam_exec.so pam-anyauth


DEPENDENCIES
------------

This utility can use putty and puttygen.  install it if you want to enable that feature.

If connecting to SQL you will also need isql from unixodbc or the microsoft odbc driver.  


MANUAL INSTALL
--------------

Why would you do this manually?  if the other three options dont work you should probably give up....

* copy /etc files to /etc/pam-anyauth
* copy sbin files to /usr/sbin/
* create a group for the users on the local system
* setup odbc and isql
* create sql query for authenticating users
* modify settings in conf, odbc.conf, ensure.conf


HOW DOES THIS WORK?
-------------------

This utility is a wrapper around other processes.  The parent process pam-anyauth calls two sub processes:
1) authenticate a user
2) ensure user is setup on local system

If you want to swap out either the auth or the ensure processes change the commands in the config file:

  /etc/pam-anyauth/conf

The two options are included and commented out by default.  AUTH is the command that authenticates the user.  ENSURE makes sure the user exists and is setup on the local system.

The password is sent to each subprocesses using stdin.  See AUTHENTICATING USERS

The username is an environment variable inherited from pam_exec: $PAM_USER.

### DEBUG mode

You may turn on debugging output by setting DEBUGPREFERENCE=continue in the conf file or setting the environment variable.


CAVEATS
-------

If the user does not exist on the system ssh (and other programs?) may trash the password before it gets to pam-anyauth.  Without a valid password pam-anyauth cannot make sure a user is valid and therefore cannot create the user.

This leads to a chicken and egg problem that I have not been able to solve.  The workaround right now is to pre-seed the users.  Use pam-anyauth-odbc-sync from a cron job to preseed users.  See PAM-ANYAUTH-ODBC-SYNC

https://www.redhat.com/archives/pam-list/2006-July/msg00029.html  
This article suggests that pam_exec cannot be told to retrieve the password using try_first_pass or use_first_pass.  I'm looking into writing a c wrapper pam module to work around this issue.


AUTHENTICATING USERS
--------------------

The authentication process must read the user password from stdin and use the PAM_USER variable to get the username.  Ex.

  PAM_PASS=$(cat -)
  echo "User: $PAM_USER has password $PAM_PASS"

The included odbc based authentication script uses isql to connect to an odbc database.  The configuration settings (including a password!!!  keep this file private) are stored in /etc/pam-anyauth/odbc.conf.  Modify these for your environment.  see PAM-ANYAUTH-ODBC for more details.

If you want to create your own process it must:

* accept the password on stdin
* ouput return code 0 on success and anything else on failure to find a match
* output something on successful match (such as a username or id)


PAM-ANYAUTH-ENSURE
------------------

To make sure your ensure command works, pick a user and run the command

  PAM_USER=<someuser>
  echo '*' | pam-anyauth-ensure
  echo "return code: $?"

  The return code should be 0.


PAM-ANYAUTH-ODBC
----------------

The included odbc based authentication script uses isql to connect to an odbc database.  The configuration settings (including a password!!!  keep this file private) are stored in /etc/pam-anyauth/odbc.conf.  Modify these for your environment.  

To use this process setup odbc on your system (this is outside the scope of this document) and get db connectivity working with isql before configuring this utility.  Once isql is working make sure you have a way to check the user credentials in the database.  

You will need to create some database infrastructure to support your authentication. At the very least you need a query that will match the user and password specified by pam.  See PAM_SQL_LOOKUP below for examples.  Develop your query and test using isql on the command line before trying to hook all this up to pam.  Once the query is working modify PAM_SQL_LOOKUP in pam-anyauth/odbc.conf.  Use placeholders for the {USERNAME} AND {PASSWORD}.  Those tokens are substituted (after some sql injection sanity checking) before the query is run against the database.

Also set the username and password for the isql connection.  You can test that it is working by running

  PAM_USER=<someuser>
  export PAM_USER
  echo '<userpassword>' | pam-anyauth-odbc
  echo "return code: $?"

### PAM_SQL_LOOKUP

PAM_SQL_LOOKUP must be set to a query which will be executed against the specified data source.  The query must return 'Y' as the first column of the result set to indicate that the user is enabled and not locked out.  The query may optionally return nothing if the credentials are disabled, locked out, or invalid.

#### EXAMPLE 1

We wrote a function called [authenticate] that takes the username and password then checks them against the user tables in the database.  The function returns a record if a valid, enabled, not-locked out matching username and password is found and nothing otherwise.  We use this for the configuration in pam-anyauth/odbc.conf

  PAM_SQL_LOOKUP="select 'Y', IsEnabled, UserId from [dbo].[authenticate]( N'{USERNAME}' , N'{PASSWORD}');"

#### EXAMPLE 2

If you are using Microsoft SQL with aspnetIdentity in an MVC application your database will include a table dbo.aspnetUsers.  The older model uses dbo.aspnet_Users.  Let's assume you are using clear text passwords for this example.  The password is stored in the PasswordHash field.  It should include a marker in the field for the format used (clear, hashed, or encrypted) along with the password hash and the salt.  A number designates which method is used: 0 => clear, 1 => hash, 2 => encrypted.  This code will parse out the clear text password and try to match it.  Note that we include 'Y' as the first column

  PAM_SQL_LOOKUP="select 'Y' as [Enabled], Id from [dbo].[aspnetUsers] where Username = N'{USERNAME}' and left(PasswordHash,charindex('|',PasswordHash,0) - 1) = N'{PASSWORD}';"
  
#### EXAMPLE 3

If you are using Microsoft SQL with aspnetIdentity in an MVC application like example 2 but the passwords are hashed you will need a way to hash the password you get from pam so that you can compare the two.  First you have to base 64 encode the salt and then hash the password using the methods used by aspnet systems.  See the file ASPNETIDENTITY.txt use as reference. Using the routines documented there allows this SQL command to check the database for the specified user and password the pam specified username and password will be substituted for the two tokens (including the curly braces).  The resulting sql will be echoed to PAM_SQL_CMD

PAM_SQL_LOOKUP="select 'Y', UserId from [users].[authenticate]( N'{USERNAME}' , N'{PASSWORD}');"


PAM-ANYAUTH-ODBC-SYNC
---------------------

A cron job is available but disabled by default for a sync process.  If enabled the process will call the ensure script on all valid database users so that they will exist on the system before they try to login.  This gets around the problem of ssh trashing the password for unknown users by pre-creating the users.

This utility requires another sql query to get the list of valid users.  Check /etc/pam-anyauth/odbc.conf for

  PAM_SQL_LIST="SELECT UserName, ID as UserId, Email,IsEnabled FROM dbo.aspnetusers where IsEnabled = 1"

The first column in the result set MUST be the username.  You may return anything else after that.  The username will be used to ensure users exist on the system.


pam-anyauth test
----------------

Test to make sure everything works together by testing a real user from your database.  Dont forget to ensure the user first.

PAM_USER=<someuser>
  export PAM_USER
  echo '<userpassword>' | pam-anyauth-ensure
  echo '<userpassword>' | pam-anyauth
  echo "return code: $?"


CONFIGURING PAM
---------------

pam-anyauth was developed to be used with pam_exec.  On Debian/Ubuntu we modified /etc/pam.d/common-auth but on centos we modified /etc/pam.d/password-auth.  It looks something like this

  # here are the per-package modules (the "Primary" block)
  auth	[success=2 default=ignore]	pam_unix.so nullok_secure
  auth	[success=1 default=ignore]	pam_sss.so use_first_pass
  
  auth  sufficient pam_exec.so expose_authtok debug log=/var/log/pam-anyauth.log /usr/sbin/pam-anyauth    #### added this line for pam-anyauth
  
  # here's the fallback if no module succeeds
  auth	requisite			pam_deny.so
  # prime the stack with a positive return value if there isn't one already;
  # this avoids us returning an error just because nothing sets a success code
  # since the modules above will each just jump around
  auth	required			pam_permit.so

After getting it to work you may want to take out the debug option on the pam-anyauth line.


CONFIGURING SFTP
----------------

you may find the SFTP.txt file useful if using pam-anyauth with sftp


TROUBLESHOOTING
---------------

### Make sure that debug is set in the call to pam exec and add a log entry.  e.g.

  auth  sufficient pam_exec.so expose_authtok debug log=/var/log/pam-anyauth.log /usr/sbin/pam-anyauth

### Turn on the debug output in /etc/pam-anyauth/conf

  DEBUGPREFERENCE=continue
  
### Make sure all of the pam-anyauth files in sbin are executable

  chmod a+x /usr/sbin/pam-anyauth*
  
### Test each component of the system individually

test odbc and isql

  echo 'select * from usertable' | isql -v dsn dbuser dbpass

test pam odbc

  PAM_USER=foo
  export PAM_USER
  echo 'password' | /usr/sbin/pam-anyauth-odbc
  if [ "$?" = "0" ] ; then echo success ; else echo failed fi

test pam-anyauth-ensure

  PAM_USER=foo
  export PAM_USER
  echo 'password' | /usr/sbin/pam-anyauth-ensure
  if [ "$?" = "0" ] ; then echo success ; else echo failed fi
  
test pam anyauth from command line

  PAM_USER=foo
  export PAM_USER
  echo 'password' | /usr/sbin/pam-anyauth
  if [ "$?" = "0" ] ; then echo success ; else echo failed fi

### pam and password manipulation

check the output from pam and ssh in the logs.  The password may be overwritten by ssh because it does not like the user.  For example, if ssh is only allowing certain users with an allow directive it may trash the password for invalid users before it sends it on to PAM.   here is a post discussing it

  https://superuser.com/questions/900417/pam-exec-so-doesnt-write-password-to-script-when-expose-authtok-is-enabled/1260309#1260309

Test the process with a system user that works with ssh then add that user to your database authentication.
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.