password expiration (PAM Account support)

Andrew Bartlett abartlet at pcug.org.au
Tue Feb 20 12:58:46 GMT 2001


Andrew Bartlett wrote:
> 
> Gerald Carter wrote:
> >
> > Alaa AlAmood wrote:
> > >
> > > Hi
> > > I'm new  subscribe in this mail list, sorry if this subject been
> > > discussed before.
> > > my problem is that I used linux 7.0 and I have pptp which using
> > > smbpasswd, I tried to find out to make samba to expiring
> > > the password for the user, is any good advice here
> > > thanks for help
> >
> > Password expiration has not implemented yet. (unless someone
> > has a private patch).
> >
> > Cheers, jerry
> 
> I do!
> 
> http://samba.org/samba-patches?findid=231
> 
> Gives samba PAM support for password expiration (account manangement),
> and I am in the process of porting the same functionality to 2.0.7.
> 
> Hope its usefull,
> 
> Andrew Bartlett
> 
> PS. All my testing is on RH7, but you will need to use a different
> /etc/pam.d/samba (I use the one from ppp) to get the 'system-auth' and
> you will need to enable utmp support (I use its connection number
> tracking).
> 
> --
> Andrew Bartlett
> abartlet at pcug.org.au

Attached is the port to 2.0.7, and appears to work.  I also have RPMS
with this included (this is how I test) if anybody wants.  This
particular version does not record rhost values for PAM and does not
require UTMP.  Feedback is appreciated.

-- 
Andrew Bartlett
abartlet at pcug.org.au
-------------- next part --------------
diff -ur samba-2.0.7/source/passdb/pass_check.c samba-2.0.7-PAM/source/passdb/pass_check.c
--- samba-2.0.7/source/passdb/pass_check.c	Wed Jul 21 11:25:12 1999
+++ samba-2.0.7-PAM/source/passdb/pass_check.c	Tue Feb 20 17:14:16 2001
@@ -19,6 +19,33 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+/* Some of the PAM Code has been borowed from OpenSSH and carries the 
+   following copyright.  */
+
+/*
+ * Copyright (c) 2000 Damien Miller.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
 /* this module is for checking a username/password against a system
    password database. The SMB encrypted password support is elsewhere */
 
@@ -94,44 +121,169 @@
     NULL
 };
 
+static BOOL end_pam(pam_handle_t *pamh)
+{
+	int pam_retval;
+	if (pamh != NULL) {
+	  pam_retval = pam_end(pamh, pam_retval);
+	  if (pam_retval != PAM_SUCCESS) {
+	    DEBUG(2,("Cannot release PAM authentication[%d]: %.200s\n", 
+		     pam_retval, pam_strerror(pamh, pam_retval)));
+	    return False;
+	  }
+	  return True; 
+	} else {
+	  DEBUG(2,("PAM not initialised"));
+	  return False;
+	};
+}
+
 
-static BOOL pam_auth(char *user,char *password)
+/* Start PAM authentication for specified account */
+static BOOL start_pam(pam_handle_t **pamh, char *user)
 {
-  pam_handle_t *pamh;
-  int pam_error;
+	int pam_retval;
+
+	DEBUG(4,("Starting up PAM with username \"%.200s\"\n", user));
+
+	pam_retval = pam_start("samba", user, &PAM_conversation, *&pamh);
+
+	if (pam_retval != PAM_SUCCESS) {
+		DEBUG(0,("PAM initialisation failed[%d]: %.200s\n", 
+			pam_retval, pam_strerror(*pamh, pam_retval)));
+		end_pam(*pamh);
+		return False;
+	}
+
+#ifdef PAM_TTY_KLUDGE
+	/*
+	 * (Comment from OpenSSH, but applies equaly to samba):
+	 * Some PAM modules (e.g. pam_time) require a TTY to operate,
+	 * and will fail in various stupid ways if they don't get one. 
+	 * sshd doesn't set the tty until too late in the auth process and may
+	 * not even need one (for tty-less connections)
+	 * Kludge: Set a fake PAM_TTY 
+	 */
+	pam_retval = pam_set_item(*pamh, PAM_TTY, "ssh");
+	if (pam_retval != PAM_SUCCESS) {
+		DEBUG(0,("PAM set tty failed[%d]: %.200s\n", 
+			pam_retval, pam_strerror(*pamh, pam_retval)));
+		return False;
+	}
+#endif /* PAM_TTY_KLUDGE */
+
+	return True;
+}
+
+static BOOL pam_auth(pam_handle_t *pamh, char *user, char *password)
+{
+	int pam_error;
+
+	/* Now use PAM to do authentication.  For now, we won't worry about
+	 * session logging, only authentication.  Bail out if there are any
+	 * errors.  Since this is a limited protocol, and an even more limited
+	 * function within a server speaking this protocol, we can't be as
+	 * verbose as would otherwise make sense.
+	 * Query: should we be using PAM_SILENT to shut PAM up?
+	 */
+
+	PAM_password = password;
+	PAM_username = user;
+
+	DEBUG(4,("Doing PAM password verification with username \"%.200s\"\n", user));
 
-  /* Now use PAM to do authentication.  For now, we won't worry about
-   * session logging, only authentication.  Bail out if there are any
-   * errors.  Since this is a limited protocol, and an even more limited
-   * function within a server speaking this protocol, we can't be as
-   * verbose as would otherwise make sense.
-   * Query: should we be using PAM_SILENT to shut PAM up?
-   */
-  #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
-     pam_end(pamh, 0); return False; \
-   }
-  PAM_password = password;
-  PAM_username = user;
-  pam_error = pam_start("samba", user, &PAM_conversation, &pamh);
-  PAM_BAIL;
 /* Setting PAM_SILENT stops generation of error messages to syslog
  * to enable debugging on Red Hat Linux set:
  * /etc/pam.d/samba:
  *	auth required /lib/security/pam_pwdb.so nullok shadow audit
  * _OR_ change PAM_SILENT to 0 to force detailed reporting (logging)
  */
-  pam_error = pam_authenticate(pamh, PAM_SILENT);
-  PAM_BAIL;
-  /* It is not clear to me that account management is the right thing
-   * to do, but it is not clear that it isn't, either.  This can be
-   * removed if no account management should be done.  Alternately,
-   * put a pam_allow.so entry in /etc/pam.conf for account handling. */
-  pam_error = pam_acct_mgmt(pamh, PAM_SILENT);
-  PAM_BAIL;
-  pam_end(pamh, PAM_SUCCESS);
-  /* If this point is reached, the user has been authenticated. */
-  return(True);
+	pam_error = pam_authenticate(pamh, 0);
+	if (pam_error != PAM_SUCCESS) {
+	  DEBUG(0,("PAM authentication failed[%d]: %.200s\n", 
+		   pam_error, pam_strerror(pamh, pam_error)));
+	  return False;
+	} else {
+	  DEBUG(4,("PAM authentication suceeded[%d]: %.200s\n", 
+		   pam_error, pam_strerror(pamh, pam_error)));
+	};
+		
+	return (True);
+};
+
+static BOOL pam_account(pam_handle_t *pamh, char *user)
+{
+	int pam_error;
+
+	PAM_password = NULL;
+	PAM_username = user;
+
+	/* It is not clear to me that account management is the right thing
+	 * to do, but it is not clear that it isn't, either.  This can be
+	 * removed if no account management should be done.  Alternately,
+	 * put a pam_allow.so entry in /etc/pam.conf for account handling. */
+
+	DEBUG(4,("Doing PAM account management with username \"%.200s\"\n", user));
+
+	pam_error = pam_acct_mgmt(pamh, 0);
+	if (pam_error != PAM_SUCCESS) {
+	  DEBUG(0,("PAM set account management failed[%d]: %.200s\n", 
+		   pam_error, pam_strerror(pamh, pam_error)));
+	  return False;
+	} else {
+	  DEBUG(4,("PAM account management suceeded[%d]: %.200s\n", 
+		   pam_error, pam_strerror(pamh, pam_error)));
+	};
+
+	/*
+	 * This will allow samba to aquire a kerberos token. And, when
+	 * exporting an AFS cell, be able to /write/ to this cell.
+	 */
+	pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED));
+	if (pam_error != PAM_SUCCESS) {
+	  DEBUG(0,("PAM set credentials failed[%d]: %.200s\n", 
+		   pam_error, pam_strerror(pamh, pam_error)));
+	  return False;
+	}
+	
+	/* If this point is reached, the user has been authenticated. */
+	return (True);
+}
+
+static BOOL pam_session(pam_handle_t *pamh, char *user, char *ttyname, BOOL claim)
+{
+	int pam_error;
+
+	PAM_password = NULL;
+	PAM_username = user;
+
+	DEBUG(4,("PAM setting tty to \"%.200s\"\n", ttyname));
+	pam_error = pam_set_item(pamh, PAM_TTY, ttyname);
+	if (pam_error != PAM_SUCCESS) {
+	  DEBUG(0,("PAM set tty failed[%d]: %.200s\n", 
+		   pam_error, pam_strerror(pamh, pam_error)));
+	  return False;
+	}
+
+	if (claim) {
+	  pam_error = pam_open_session(pamh, 0);
+	  if (pam_error != PAM_SUCCESS) {
+	    DEBUG(0,("PAM session setup failed[%d]: %.200s\n", 
+		     pam_error, pam_strerror(pamh, pam_error)));
+	    return False;
+	  }
+	} else {
+	  pam_error = pam_close_session(pamh, 0);
+	  if (pam_error != PAM_SUCCESS) {
+	    DEBUG(0,("PAM session close failed[%d]: %.200s\n", 
+		     pam_error, pam_strerror(pamh, pam_error)));
+	    return False;
+	  }
+	};
+
+	return (True);
 }
+
 #endif
 
 
@@ -677,6 +829,8 @@
 {
 
 #ifdef WITH_PAM
+	pam_handle_t *pamh=NULL;
+
 	/* This falls through if the password check fails
 	   - if HAVE_CRYPT is not defined this causes an error msg
 	   saying Warning - no crypt available
@@ -685,8 +839,18 @@
 	   settings say it should fail.
 	   if (pam_auth(user,password)) return(True);
 	   Hence we make a direct return to avoid a second chance!!!
-	*/
-	return (pam_auth(this_user,password));
+	 */
+        
+	if (start_pam(&pamh, this_user)) {
+	  if (pam_auth(pamh, this_user, password)) {
+	    if (pam_account(pamh, this_user)) {
+	      return end_pam(pamh);
+	    };
+	  };
+	};
+	end_pam(pamh);
+	return False;
+	
 #endif /* WITH_PAM */
 	
 #ifdef WITH_AFS
@@ -867,8 +1031,10 @@
 	this_salt[2] = 0;
 #endif
 	
-	fstrcpy(this_crypted,pass->pw_passwd);
-	
+#ifndef WITH_PAM
+	fstrcpy(this_crypted, pass->pw_passwd);
+
+	/* PAM can handle this, and there could be other factors */
 	if (!*this_crypted) {
 		if (!lp_null_passwords()) {
 			DEBUG(2,("Disallowing %s with null password\n",
@@ -881,6 +1047,7 @@
 			return(True);
 		}
 	}
+#endif
 
 	/* try it as it came to us */
 	if (password_check(password)) {
@@ -927,3 +1094,53 @@
   
 	return(False);
 }
+
+#ifdef WITH_PAM
+BOOL account_pam(char *user)
+{
+	  /* Check the account with the PAM account module:
+	      - This means that accounts can be disabled
+	        and or expired without samba then just
+		bypassing the situation.
+	  */ 
+
+	  pam_handle_t *pamh = NULL;
+	   
+	  char * PAMuser;
+	  PAMuser = malloc(strlen(user)+1);
+	  /* This is freed by PAM */
+	  strncpy(PAMuser, user, strlen(user)+1);
+
+	  if (start_pam(&pamh, PAMuser)) {
+	    if (pam_account(pamh, PAMuser)) {
+	      return end_pam(pamh);
+	    }
+	  }
+	  end_pam(pamh);
+	  return False;
+};
+
+BOOL session_pam(BOOL claim, const connection_struct *conn, int conn_num, char *ttyname)
+{
+  pam_handle_t *pamh=NULL;
+  char * user;
+  user = malloc(strlen(conn->user)+1);
+  /* This is freed by PAM */
+  strncpy(user, conn->user, strlen(conn->user)+1);
+  
+  if (!start_pam(&pamh, user)) {
+    end_pam(pamh);
+    return False;
+  }
+  
+  if (pam_session(pamh, user, ttyname, claim)) {
+    return end_pam(pamh);
+  } else {
+    end_pam(pamh);
+    return False;
+  };
+}
+#endif
+
+
+
Only in samba-2.0.7-PAM/source/passdb: pass_check.c~
diff -ur samba-2.0.7/source/smbd/connection.c samba-2.0.7-PAM/source/smbd/connection.c
--- samba-2.0.7/source/smbd/connection.c	Wed Apr 26 09:07:09 2000
+++ samba-2.0.7-PAM/source/smbd/connection.c	Tue Feb 20 17:49:05 2001
@@ -30,6 +30,10 @@
 static void utmp_yield(pid_t pid, const connection_struct *conn, int i);
 static void utmp_claim(const struct connect_record *crec, connection_struct *conn, int i);
 #endif
+#ifdef WITH_PAM
+static BOOL claim_pam(const connection_struct *conn, int i);
+static BOOL yield_pam(const connection_struct *conn, int i);
+#endif
 
 /****************************************************************************
 simple routines to do connection counting
@@ -114,6 +118,9 @@
 #ifdef WITH_UTMP
 	utmp_yield(mypid, conn, i);
 #endif
+#ifdef WITH_PAM
+	return(yield_pam(conn, i));
+#endif
 
 	return(True);
 }
@@ -238,7 +245,9 @@
 #ifdef WITH_UTMP
 	utmp_claim(&crec, conn, foundi);
 #endif
-
+#ifdef WITH_PAM
+	claim_pam(conn, foundi);
+#endif
 	return(True);
 }
 
@@ -594,5 +603,36 @@
 		utmp_update(&u, host);
 	}
 }
+#endif	/* WITH_UTMP */
 
-#endif
+
+#ifdef WITH_PAM
+/*******************************************************************
+ PAM Session handling (same idea as utmp, just with pam)
+  - Called from within the utmp functions to get 'terminal' names
+
+  Despite what it looks this patch does have a practical purpose:
+  This system allows the administrator to use modules like 'pam_limits'
+  that work on a per session basis. It can be used with ANY pam 
+  session module (AFAIK).
+
+  It also uses the utmp consolidate, for extra flexability.
+
+  (c) Andrew Bartlett 2001
+********************************************************************/
+
+static BOOL claim_pam(const connection_struct *conn, int conn_num)
+{
+  char ttyname[1024];
+  slprintf(ttyname, 12, "smb/%d", conn_num);
+  return session_pam(True, conn, conn_num, ttyname);
+}
+
+static BOOL yield_pam(const connection_struct *conn, int conn_num)
+{
+  char ttyname[1024];
+  slprintf(ttyname, 12, "smb/%d", conn_num);
+  return session_pam(False, conn, conn_num, ttyname);
+}
+
+#endif	/* WITH_PAM */
Only in samba-2.0.7-PAM/source/smbd: connection.c~
diff -ur samba-2.0.7/source/smbd/password.c samba-2.0.7-PAM/source/smbd/password.c
--- samba-2.0.7/source/smbd/password.c	Wed Apr 26 09:07:11 2000
+++ samba-2.0.7-PAM/source/smbd/password.c	Sun Feb 18 22:09:57 2001
@@ -536,6 +536,7 @@
 ****************************************************************************/
 BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd)
 {
+  BOOL ret;
 	if (pwlen == 24 || (lp_encrypted_passwords() && (pwlen == 0) && lp_null_passwords()))
 	{
 		/* if 24 bytes long assume it is an encrypted password */
@@ -547,8 +548,16 @@
 			return False;
 		}
 
-		return pass_check_smb(user, global_myworkgroup,
+		ret = pass_check_smb(user, global_myworkgroup,
 		                      challenge, (uchar *)password, (uchar *)password, pwd);
+
+#ifdef WITH_PAM
+	if (ret) {
+	  ret = account_pam(user);
+	}
+#endif /* WITH_PAM */
+        
+	return ret;
 	} 
 
 	return pass_check(user, password, pwlen, pwd, 
Only in samba-2.0.7-PAM/source/smbd: password.c~


More information about the samba mailing list