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