[Fedora-directory-devel] Please review: make PAM passthru plugin thread safe

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Since PAM is not thread safe, only 1 thread at a time may access the PAM API. This fix adds a mutex around the critical section where we call all of the PAM functions. I've also added another init function which is used to create the mutex. This has been tested on RHEL4 under a moderate load and seems to work fine.
Index: pam_passthru.h
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/pam_passthru/pam_passthru.h,v
retrieving revision 1.4
diff -u -8 -r1.4 pam_passthru.h
--- pam_passthru.h	19 Apr 2005 22:07:30 -0000	1.4
+++ pam_passthru.h	6 Jul 2005 22:20:33 -0000
@@ -126,11 +126,12 @@
  */
 int pam_passthru_config( Slapi_Entry *config_e );
 Pam_PassthruConfig *pam_passthru_get_config( void );
 int pam_passthru_check_suffix(Pam_PassthruConfig *cfg, char *binddn);
 
 /*
  * pam_ptimpl.c
  */
+int pam_passthru_pam_init( void );
 int pam_passthru_do_pam_auth(Slapi_PBlock *pb, Pam_PassthruConfig *cfg);
 
 #endif	/* _PAM_PASSTHRU_H_ */
Index: pam_ptimpl.c
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/pam_passthru/pam_ptimpl.c,v
retrieving revision 1.7
diff -u -8 -r1.7 pam_ptimpl.c
--- pam_ptimpl.c	19 Apr 2005 22:07:30 -0000	1.7
+++ pam_ptimpl.c	6 Jul 2005 22:20:33 -0000
@@ -34,16 +34,21 @@
  * Copyright (C) 2005 Red Hat, Inc.
  * All rights reserved.
  * END COPYRIGHT BLOCK **/
 
 #include <security/pam_appl.h>
 
 #include "pam_passthru.h"
 
+/*
+ * PAM is not thread safe.  We have to execute any PAM API calls in
+ * a critical section.  This is the lock that protects that code.
+ */
+static Slapi_Mutex *PAMLock;
 
 /* Utility struct to wrap strings to avoid mallocs if possible - use
    stack allocated string space */
 #define MY_STATIC_BUF_SIZE 256
 typedef struct my_str_buf {
 	char fixbuf[MY_STATIC_BUF_SIZE];
 	char *str;
 } MyStrBuf;
@@ -266,16 +271,18 @@
 	} else {
 		init_my_str_buf(&pam_id, binddn);
 	}
 
 	/* do the pam stuff */
 	my_data.pb = pb;
 	my_data.pam_identity = pam_id.str;
 	my_pam_conv.appdata_ptr = &my_data;
+	slapi_lock_mutex(PAMLock);
+	/* from this point on we are in the critical section */
 	rc = pam_start(pam_service, pam_id.str, &my_pam_conv, &pam_handle);
 	report_pam_error("during pam_start", rc, pam_handle);
 
 	if (rc == PAM_SUCCESS) {
 		/* use PAM_SILENT - there is no user interaction at this point */
 		rc = pam_authenticate(pam_handle, 0);
 		report_pam_error("during pam_authenticate", rc, pam_handle);
 		/* check different types of errors here */
@@ -346,16 +353,18 @@
 			errmsg = PR_smprintf("Unknown PAM error [%s] for user id [%s], bind DN [%s]",
 								 pam_strerror(pam_handle, rc), pam_id.str, escape_string(binddn, buf));
 			retcode = LDAP_OPERATIONS_ERROR; /* unknown */
 		}
 	}
 
 	rc = pam_end(pam_handle, rc);
 	report_pam_error("during pam_end", rc, pam_handle);
+	slapi_unlock_mutex(PAMLock);
+	/* not in critical section any more */
 
 	delete_my_str_buf(&pam_id);
 
 	if ((retcode == LDAP_SUCCESS) && (rc != PAM_SUCCESS)) {
 		errmsg = PR_smprintf("Unknown PAM error [%d] for user id [%d], bind DN [%s]",
 							 rc, pam_id.str, escape_string(binddn, buf));
 		retcode = LDAP_OPERATIONS_ERROR;
 	}
@@ -371,16 +380,30 @@
 	if (errmsg) {
 		PR_smprintf_free(errmsg);
 	}
 
 	return retcode;
 }
 
 /*
+ * Perform any PAM subsystem initialization that must be done at startup time.
+ * For now, this means only the PAM mutex since PAM is not thread safe.
+ */
+int
+pam_passthru_pam_init( void )
+{
+	if (!(PAMLock = slapi_new_mutex())) {
+		return LDAP_LOCAL_ERROR;
+	}
+
+	return 0;
+}
+
+/*
  * Entry point into the PAM auth code.  Shields the rest of the app
  * from PAM API code.  Get our config params, then call the actual
  * code that does the PAM auth.  Can call that code up to 3 times,
  * depending on what methods are set in the config.
  */
 int
 pam_passthru_do_pam_auth(Slapi_PBlock *pb, Pam_PassthruConfig *cfg)
 {
Index: pam_ptpreop.c
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/pam_passthru/pam_ptpreop.c,v
retrieving revision 1.4
diff -u -8 -r1.4 pam_ptpreop.c
--- pam_ptpreop.c	19 Apr 2005 22:07:30 -0000	1.4
+++ pam_ptpreop.c	6 Jul 2005 22:20:33 -0000
@@ -123,16 +123,22 @@
     }
 
     if (( rc = pam_passthru_config( config_e )) != LDAP_SUCCESS ) {
 		slapi_log_error( SLAPI_LOG_FATAL, PAM_PASSTHRU_PLUGIN_SUBSYSTEM,
 						 "configuration failed (%s)\n", ldap_err2string( rc ));
 		return( -1 );
     }
 
+    if (( rc = pam_passthru_pam_init()) != LDAP_SUCCESS ) {
+		slapi_log_error( SLAPI_LOG_FATAL, PAM_PASSTHRU_PLUGIN_SUBSYSTEM,
+						 "could not initialize PAM subsystem (%d)\n", rc);
+		return( -1 );
+    }
+
     return( 0 );
 }
 
 
 /*
  * Called right before the Directory Server shuts down.
  */
 static int

[Index of Archives]     [Fedora Directory Announce]     [Fedora Users]     [Older Fedora Users Mail]     [Fedora Advisory Board]     [Fedora Security]     [Fedora Devel Java]     [Fedora Desktop]     [ATA RAID]     [Fedora Marketing]     [Fedora Mentors]     [Fedora Package Review]     [Fedora Art]     [Fedora Music]     [Fedora Packaging]     [CentOS]     [Fedora SELinux]     [Big List of Linux Books]     [KDE Users]     [Fedora Art]     [Fedora Docs]

  Powered by Linux