aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharl Botha <cpbotha@cpbotha.net>2000-05-22 20:55:34 +0000
committerCharl Botha <cpbotha@cpbotha.net>2000-05-22 20:55:34 +0000
commit98713a7b959ff3dd7197e3718b3002635c4e975d (patch)
tree069e0051a004392eaf3065458e0019342b765d3a
parent60d8c9e5a38161624cb7f620b012e85c3b7fb378 (diff)
downloadlibpam-pwdfile-98713a7b959ff3dd7197e3718b3002635c4e975d.tar.gz
Release 0.2 version.
-rw-r--r--README21
-rw-r--r--changelog15
-rw-r--r--pam_pwdfile.c448
3 files changed, 273 insertions, 211 deletions
diff --git a/README b/README
index 4934098..3d65e7c 100644
--- a/README
+++ b/README
@@ -1,8 +1,8 @@
README for pam_pwdfile PAM module - Charl P. Botha <cpbotha@ieee.org>
-$Id: README,v 1.1.1.1 1999-08-05 13:09:07 cpbotha Exp $
+$Id: README,v 1.2 2000-05-22 20:55:34 cpbotha Exp $
---------------------------------------------------------------------------
-Let's say that this is version 0.1 of pam_pwdfile.
+This is version 0.2 of pam_pwdfile.
This pam module can be used for the authentication service only, in cases
where one wants to use a different set of passwords than those in the main
@@ -10,14 +10,21 @@ system password database. E.g. in our case we have an imap server running,
and prefer to keep the imap passwords different from the system passwords
for security reasons.
-The /etc/pam.d/imap looks like this:
+The /etc/pam.d/imap looks like this (e.g.)
#%PAM-1.0
auth required /lib/security/pam_pwdfile.so pwdfile /etc/imap.passwd
account required /lib/security/pam_pwdb.so
At the moment the only parameters that pam_pwdfile.so parses for is
"pwdfile", followed by the name of the ASCII password database, as in the
-above example.
+above example. Also, thanks to Jacob Schroeder <jacob@quantec.de>,
+pam_pwdfile now supports password file locking. Adding an "flock" parameter
+activates this feature: pam_pwdfile uses and honours flock() file locking on
+the specified password file. Specifying "noflock" or no flock-type
+parameter at all deactivates this feature.
+
+Example:
+auth required /lib/security/pam_pwdfile.so pwdfile /etc/blah.passwd flock
The ASCII password file is simply a list of lines, each looking like this:
username:crypted_passwd[13]
@@ -25,6 +32,10 @@ username:crypted_passwd[13]
Note that we still expect users to have accounts in the usual place, as we
make use of the pam_pwdb.so module for the account service. This module is
just so that one can have multiple sets of passwords for different services,
-e.g. with our /etc/imap.passwd.
+e.g. with our /etc/imap.passwd. It is however possible with certain
+applications patched for pam (Cyrus IMAP server e.g.) that one does not need
+the users to exist in the system database.
These files have been created for inclusion into the PAM source tree.
+Thanks to Michael-John Turner <mj@debian.org> pam_pwdfile is available as a
+debian package (libpam-pwdfile) from potato onwards.
diff --git a/changelog b/changelog
new file mode 100644
index 0000000..b8a4561
--- /dev/null
+++ b/changelog
@@ -0,0 +1,15 @@
+changelog for pam_pwdfile PAM module - Charl P. Botha <cpbotha@ieee.org>
+$Id: changelog,v 1.1 2000-05-22 20:55:34 cpbotha Exp $
+---------------------------------------------------------------------------
+
+0.2: Mon May 22 22:41:30 SAST 2000
+
+* integrated patch by Jacob Schroeder <jacob@quantec.de> to implement
+ flock()-based password file locking
+* minor code tweaks (indentation, unnecessary variables removed)
+* minor README file updates
+* this file
+
+0.1: ?
+
+* Initial release
diff --git a/pam_pwdfile.c b/pam_pwdfile.c
index cd5c828..2a3abd2 100644
--- a/pam_pwdfile.c
+++ b/pam_pwdfile.c
@@ -1,6 +1,6 @@
/* pam_pwdfile.c copyright 1999 by Charl P. Botha <cpbotha@ieee.org>
*
- * $Id: pam_pwdfile.c,v 1.1.1.1 1999-08-05 13:09:07 cpbotha Exp $
+ * $Id: pam_pwdfile.c,v 1.2 2000-05-22 20:55:34 cpbotha Exp $
*
* pam authentication module that can be pointed at any username/crypted
* text file so that pam using application can use an alternate set of
@@ -52,6 +52,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/file.h>
#define _XOPEN_SOURCE
#include <unistd.h>
@@ -60,6 +65,7 @@
extern char *crypt(const char *key, const char *salt);
#define PWDF_PARAM "pwdfile"
+#define FLOCK_PARAM "flock"
#define PWDFN_LEN 256
#define CRYPTEDPWD_LEN 13
@@ -74,83 +80,96 @@ int converse(pam_handle_t *, int, struct pam_message **, struct pam_response **)
int _set_auth_tok(pam_handle_t *, int, int, const char **);
/* logging function ripped from pam_listfile.c */
-static void _pam_log(int err, const char *format, ...)
-{
- va_list args;
+static void _pam_log(int err, const char *format, ...) {
+ va_list args;
+
+ va_start(args, format);
+ openlog("pam_pwdfile", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+static int lock_fd(int fd) {
+ int delay;
- va_start(args, format);
- openlog("pam_pwdfile", LOG_CONS|LOG_PID, LOG_AUTH);
- vsyslog(err, format, args);
- va_end(args);
- closelog();
+ for (delay = 5; delay <= 40; delay *= 2) {
+ if (flock(fd, LOCK_SH | LOCK_NB) == -1) {
+ /* failed */
+ if (errno != EWOULDBLOCK) goto failed;
+ sleep(delay);
+ }else{
+ return 0;
+ }
+ }
+ if (flock(fd, LOCK_SH | LOCK_NB) != -1) return 0;
+failed:
+ return -1;
}
/* this function ripped from pam_unix/support.c */
int converse( pam_handle_t *pamh,
int nargs,
struct pam_message **message,
- struct pam_response **response )
-
-{
- int retval;
- struct pam_conv *conv;
-
- retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ;
- if ( retval == PAM_SUCCESS )
- {
- retval = conv->conv( nargs,
- ( const struct pam_message ** ) message,
- response,
- conv->appdata_ptr );
- }
- return retval;
+ struct pam_response **response ) {
+ int retval;
+ struct pam_conv *conv;
+
+ retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ;
+ if ( retval == PAM_SUCCESS ) {
+ retval = conv->conv( nargs,
+ ( const struct pam_message ** ) message,
+ response,
+ conv->appdata_ptr );
+ }
+ return retval;
}
/* this function ripped from pam_unix/support.c */
int _set_auth_tok( pam_handle_t *pamh,
int flags, int argc,
const char **argv ) {
- int retval;
- char *p;
+ int retval;
+ char *p;
+
+ struct pam_message msg[1],*pmsg[1];
+ struct pam_response *resp;
+
+ /* set up conversation call */
+
+ pmsg[0] = &msg[0];
+ msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[0].msg = "Password: ";
+ resp = NULL;
+
+ if ( ( retval = converse( pamh, 1 , pmsg, &resp ) ) != PAM_SUCCESS )
+ return retval;
+
+ if ( resp )
+ {
+ if ( ( flags & PAM_DISALLOW_NULL_AUTHTOK ) &&
+ resp[0].resp == NULL )
+ {
+ free( resp );
+ return PAM_AUTH_ERR;
+ }
- struct pam_message msg[1],*pmsg[1];
- struct pam_response *resp;
-
- /* set up conversation call */
-
- pmsg[0] = &msg[0];
- msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
- msg[0].msg = "Password: ";
- resp = NULL;
-
- if ( ( retval = converse( pamh, 1 , pmsg, &resp ) ) != PAM_SUCCESS )
- return retval;
-
- if ( resp )
- {
- if ( ( flags & PAM_DISALLOW_NULL_AUTHTOK ) &&
- resp[0].resp == NULL )
- {
- free( resp );
- return PAM_AUTH_ERR;
- }
-
- p = resp[ 0 ].resp;
-
- /* This could be a memory leak. If resp[0].resp
- is malloc()ed, then it has to be free()ed!
- -- alex
- */
-
- resp[ 0 ].resp = NULL;
-
- }
- else
- return PAM_CONV_ERR;
-
- free( resp );
- pam_set_item( pamh, PAM_AUTHTOK, p );
- return PAM_SUCCESS;
+ p = resp[ 0 ].resp;
+
+ /* This could be a memory leak. If resp[0].resp
+ is malloc()ed, then it has to be free()ed!
+ -- alex
+ */
+
+ resp[ 0 ].resp = NULL;
+
+ }
+ else
+ return PAM_CONV_ERR;
+
+ free( resp );
+ pam_set_item( pamh, PAM_AUTHTOK, p );
+ return PAM_SUCCESS;
}
@@ -159,168 +178,185 @@ int _set_auth_tok( pam_handle_t *pamh,
* if unsucessful, returns 0
*/
static int fgetpwnam(FILE *stream, const char *name, char *password) {
- char tempLine[256], *tpointer, *curname, *curpass, *fgr;
- int loopdone, pwdfound;
-
- /* go to beginning of file */
- rewind(stream);
- /* some control variables */
- loopdone = pwdfound = 0;
- /* iterate through lines in file, until end of file */
- do {
- /* get the current line */
- fgr = fgets(tempLine,256,stream);
- /* if it's valid, go on */
- if ( fgr != NULL) {
- /* first get the username out */
- tpointer = tempLine;
- curname = strsep(&tpointer,":");
- /* check to see if it's the right one */
- if (strcmp(curname,name)==0) {
- /* at least we know our loop is done */
- loopdone = 1;
- /* get the password and put it in its place */
- curpass = strsep(&tpointer,":");
- if (curpass != NULL) {
- strncpy(password,curpass,CRYPTEDPWD_LEN+1);
- pwdfound = 1;
- } /* if (curpass... */
- } /* if (strcmp(curname... */
- } /* if (tempLine... */
- } while (fgr != NULL);
- return pwdfound;
+ char tempLine[256], *tpointer, *curname, *curpass, *fgr;
+ int loopdone, pwdfound;
+
+ /* go to beginning of file */
+ rewind(stream);
+ /* some control variables */
+ loopdone = pwdfound = 0;
+ /* iterate through lines in file, until end of file */
+ do {
+ /* get the current line */
+ fgr = fgets(tempLine,256,stream);
+ /* if it's valid, go on */
+ if ( fgr != NULL) {
+ /* first get the username out */
+ tpointer = tempLine;
+ curname = strsep(&tpointer,":");
+ /* check to see if it's the right one */
+ if (strcmp(curname,name)==0) {
+ /* at least we know our loop is done */
+ loopdone = 1;
+ /* get the password and put it in its place */
+ curpass = strsep(&tpointer,":");
+ if (curpass != NULL) {
+ strncpy(password,curpass,CRYPTEDPWD_LEN+1);
+ pwdfound = 1;
+ } /* if (curpass... */
+ } /* if (strcmp(curname... */
+ } /* if (tempLine... */
+ } while (fgr != NULL);
+ return pwdfound;
}
/* expected hook for auth service */
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags,
int argc, const char **argv) {
- int retval, pcnt, pwdfilename_found, loopdone;
- const char *name;
- char *password;
- char pwdfilename[PWDFN_LEN];
- char salt[3], crypted_password[CRYPTEDPWD_LEN+1];
- FILE *pwdfile;
+ int retval, pcnt, pwdfilename_found;
+ const char *name;
+ char *password;
+ char pwdfilename[PWDFN_LEN];
+ char salt[3], crypted_password[CRYPTEDPWD_LEN+1];
+ FILE *pwdfile;
+ int use_flock = 0;
- /* we require the pwdfile switch and argument to be present, else we don't work */
- /* pcnt is the parameter counter variable for iterating through argv
- * loopdone is an extra loop control variable */
- pcnt = loopdone = pwdfilename_found = 0;
- do {
- /* see if the current parameter looks like "pwdfile" */
- if (strcmp(argv[pcnt],PWDF_PARAM)==0) {
- /* if argv is long enough, grab the subsequent parameter */
- if (pcnt+1 < argc) {
- /* make sure we can't overflow */
- strncpy(pwdfilename,argv[pcnt+1],PWDFN_LEN);
- /* indicate that we've found it */
- pwdfilename_found = 1;
+ /* we require the pwdfile switch and argument to be present, else we don't work */
+ /* pcnt is the parameter counter variable for iterating through argv */
+ pcnt = pwdfilename_found = 0;
+ do {
+ /* see if the current parameter looks like "pwdfile" */
+ if (strcmp(argv[pcnt],PWDF_PARAM)==0) {
+ /* if argv is long enough, grab the subsequent parameter */
+ if (pcnt+1 < argc) {
+ /* make sure we can't overflow */
+ strncpy(pwdfilename,argv[++pcnt],PWDFN_LEN);
+ /* indicate that we've found it */
+ pwdfilename_found = 1;
+ }
+ /* also check for "pwdfile=blah" */
+ } else if (strncmp(argv[pcnt],PWDF_PARAM "=",sizeof(PWDF_PARAM "=")-1)==0) {
+ /* make sure we can't overflow */
+ strncpy(pwdfilename,argv[pcnt]+sizeof(PWDF_PARAM),PWDFN_LEN);
+ /* indicate that we've found it */
+ pwdfilename_found = 1;
+ } else if (strcmp(argv[pcnt],FLOCK_PARAM)==0) {
+ /* we have a "flock" parameter */
+ use_flock = 1;
+ } else if (strcmp(argv[pcnt],"no" FLOCK_PARAM)==0) {
+ /* or a "noflock" parameter */
+ use_flock = 0;
}
- /* whether we actually found the name or not, this loop is done,
- * as we have found the pwdfile switch itself */
- loopdone = 1;
- }
- } while (!loopdone && pcnt++ < argc);
-
- /* for some or other reason, the password file wasn't specified */
- if (!pwdfilename_found) {
- _pam_log(LOG_ERR,"password file name not specified");
- return PAM_AUTHINFO_UNAVAIL;
- }
-
- /* DEBUG */
- D(_pam_log(LOG_ERR, "password filename extracted"));
-
- /* now try to open the password file */
- if ((pwdfile=fopen(pwdfilename,"r"))==NULL) {
- _pam_log(LOG_ERR,"couldn't open password file %s",pwdfilename);
- return PAM_AUTHINFO_UNAVAIL;
- }
-
- /* get user name */
- if ((retval = pam_get_user(pamh,&name,"login: ")) != PAM_SUCCESS) {
- _pam_log(LOG_ERR, "username not found");
- fclose(pwdfile);
- return retval;
- }
-
- /* DEBUG */
- D(_pam_log(LOG_ERR,"username is %s", name));
- /* get password - code from pam_unix_auth.c */
- pam_get_item(pamh, PAM_AUTHTOK, (void *)&password);
- if (!password) {
- retval = _set_auth_tok(pamh, flags, argc, argv);
- if (retval!=PAM_SUCCESS) {
+ } while (++pcnt < argc);
+
+ /* for some or other reason, the password file wasn't specified */
+ if (!pwdfilename_found) {
+ _pam_log(LOG_ERR,"password file name not specified");
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+
+ /* DEBUG */
+ D(_pam_log(LOG_ERR, "password filename extracted"));
+
+ /* now try to open the password file */
+ if ((pwdfile=fopen(pwdfilename,"r"))==NULL) {
+ _pam_log(LOG_ERR,"couldn't open password file %s",pwdfilename);
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+
+ /* set a lock on the password file */
+ if (use_flock && lock_fd(fileno(pwdfile)) == -1) {
+ _pam_log(LOG_ERR,"couldn't lock password file %s",pwdfilename);
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+
+ /* get user name */
+ if ((retval = pam_get_user(pamh,&name,"login: ")) != PAM_SUCCESS) {
+ _pam_log(LOG_ERR, "username not found");
fclose(pwdfile);
return retval;
- }
- }
- pam_get_item(pamh, PAM_AUTHTOK, (void *)&password);
-
- if ((retval = pam_get_item(pamh, PAM_AUTHTOK, (void *)&password)) != PAM_SUCCESS) {
- _pam_log(LOG_ERR, "auth token not found");
- fclose(pwdfile);
- return retval;
- }
-
- /* DEBUG */
- D(_pam_log(LOG_ERR,"got password from user", password));
-
- /* now crypt password and compare to the user entry in the password file */
- /* first make sure password is long enough -- may I do this? */
- if (strlen(password)<2 || password==NULL) {
- _pam_log(LOG_ERR,"password too short or NULL");
- fclose(pwdfile);
- return PAM_AUTH_ERR;
- }
-
- /* get the crypted password corresponding to this user */
- if (!fgetpwnam(pwdfile, name, crypted_password)) {
- _pam_log(LOG_ERR,"password file corrupt");
- fclose(pwdfile);
- return PAM_AUTHINFO_UNAVAIL;
- }
-
- /* DEBUG */
- D(_pam_log(LOG_ERR,"got crypted password == %s", crypted_password));
-
- /* extract the salt */
- salt[0] = crypted_password[0]; salt[1] = crypted_password[1]; salt[2] = '\0';
-
- /* DEBUG */
- D(_pam_log(LOG_ERR,"user password crypted is %s", crypt(password,salt)));
-
- /* if things don't match up, complain */
- crypted_password[CRYPTEDPWD_LEN] = '\0';
- if (strcmp(crypt(password,salt),crypted_password)!=0) {
- _pam_log(LOG_ERR,"wrong password for user %s",name);
- fclose(pwdfile);
- return PAM_AUTH_ERR;
- }
+ }
- /* DEBUG */
- D(_pam_log(LOG_ERR,"passwords match"));
-
- /* we've gotten here, i.e. authentication was sucessful! */
- fclose(pwdfile);
- return PAM_SUCCESS;
+
+ /* DEBUG */
+ D(_pam_log(LOG_ERR,"username is %s", name));
+
+ /* get password - code from pam_unix_auth.c */
+ pam_get_item(pamh, PAM_AUTHTOK, (void *)&password);
+ if (!password) {
+ retval = _set_auth_tok(pamh, flags, argc, argv);
+ if (retval!=PAM_SUCCESS) {
+ fclose(pwdfile);
+ return retval;
+ }
+ }
+ pam_get_item(pamh, PAM_AUTHTOK, (void *)&password);
+
+ if ((retval = pam_get_item(pamh, PAM_AUTHTOK, (void *)&password)) != PAM_SUCCESS) {
+ _pam_log(LOG_ERR, "auth token not found");
+ fclose(pwdfile);
+ return retval;
+ }
+
+ /* DEBUG */
+ D(_pam_log(LOG_ERR,"got password from user", password));
+
+ /* now crypt password and compare to the user entry in the password file */
+ /* first make sure password is long enough -- may I do this? */
+ if (strlen(password)<2 || password==NULL) {
+ _pam_log(LOG_ERR,"password too short or NULL");
+ fclose(pwdfile);
+ return PAM_AUTH_ERR;
+ }
+
+ /* get the crypted password corresponding to this user */
+ if (!fgetpwnam(pwdfile, name, crypted_password)) {
+ _pam_log(LOG_ERR,"password file corrupt");
+ fclose(pwdfile);
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+
+ /* DEBUG */
+ D(_pam_log(LOG_ERR,"got crypted password == %s", crypted_password));
+
+ /* extract the salt */
+ salt[0] = crypted_password[0]; salt[1] = crypted_password[1]; salt[2] = '\0';
+
+ /* DEBUG */
+ D(_pam_log(LOG_ERR,"user password crypted is %s", crypt(password,salt)));
+
+ /* if things don't match up, complain */
+ crypted_password[CRYPTEDPWD_LEN] = '\0';
+ if (strcmp(crypt(password,salt),crypted_password)!=0) {
+ _pam_log(LOG_ERR,"wrong password for user %s",name);
+ fclose(pwdfile);
+ return PAM_AUTH_ERR;
+ }
+
+ /* DEBUG */
+ D(_pam_log(LOG_ERR,"passwords match"));
+
+ /* we've gotten here, i.e. authentication was sucessful! */
+ fclose(pwdfile);
+ return PAM_SUCCESS;
}
/* another expected hook */
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
- return PAM_SUCCESS;
+ return PAM_SUCCESS;
}
#ifdef PAM_STATIC
struct pam_module _pam_listfile_modstruct = {
- "pam_pwdfile",
- pam_sm_authenticate,
- pam_sm_setcred,
- NULL,
- NULL,
- NULL,
- NULL,
+ "pam_pwdfile",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
};
#endif