Package: libpam-modules Version: 0.99.7.1-5 Severity: wishlist Tags: patch Hi there,
I've been working on the debconf.org machines, which use ud-ldap the same way the debian.org machines do. Currently what happens when an account is locked for wahtever reason is that the LDAP password field is updated with a special prefix to indicate this, but the password expiry field is not updated (this last is arguably a bug in ud-ldap). In order to work around this, DSA has been carrying around a patched sshd for years to check the password field for this special marker. The attached pam module would solve this, either as a standalone module, or (perhaps better) as something merged into pam_unix or the like. Thanks for considering, -- System Information: Debian Release: lenny/sid APT prefers unstable APT policy: (500, 'unstable'), (500, 'stable'), (1, 'experimental') Architecture: i386 (i686) Kernel: Linux 2.6.22-2-686 (SMP w/4 CPU cores) Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) (ignored: LC_ALL set to en_US.UTF-8) Shell: /bin/sh linked to /bin/bash Versions of packages libpam-modules depends on: ii libc6 2.6.1-6 GNU C Library: Shared libraries ii libdb4.6 4.6.21-2 Berkeley v4.6 Database Libraries [ ii libpam0g 0.99.7.1-5 Pluggable Authentication Modules l ii libselinux1 2.0.15-2+b1 SELinux shared libraries libpam-modules recommends no packages. -- no debconf information -- ----------------------------------------------------------------- | ,''`. Stephen Gran | | : :' : [EMAIL PROTECTED] | | `. `' Debian user, admin, and developer | | `- http://www.debian.org | -----------------------------------------------------------------
#include <syslog.h>
#include <shadow.h>
#include <stdlib.h>
#include <string.h>
#define PAM_SM_AUTH
#define PAM_SM_ACCOUNT
#define PAM_SM_SESSION
#define PAM_SM_PASSWORD
#ifndef BUFSIZE
#define BUFSIZ 1024
#endif
#include <security/pam_modules.h>
#include <security/pam_ext.h>
/*
* _is_shadow_locked gets called with any arguments placed in argv.
* The only valid argument at the moment is marker, which can be used
* either as marker=foo (single item) or marker='(foo|bar)' (list form)
* We store all the tokens seen in marker[0] .. marker[n] and later check
* them against the shadow password string for the user.
*
* The point of this module is to check for certain characters at the beginning
* of a shadow password marking the account as locked or disabled. This will
* fail logins even when an alternate auth mechanism (like ssh keys) is used
* and passwords would normally not be consulted
*/
static int
_is_shadow_locked(pam_handle_t *pamh, int argc, const char **argv)
{
int a, n = 0;
char **marker;
char *cpyptr = NULL;
if ((marker = malloc(BUFSIZ)) == NULL) {
pam_syslog(pamh, LOG_ERR, "malloc failed");
return 1;
}
for (; argc-- > 0; ++argv) {
if (!strncmp(*argv, "marker=", 7)) {
char *sptr = NULL;
char *saveptr = NULL;
int len = strlen(*argv) - 7;
if (len > BUFSIZ) {
pam_syslog(pamh, LOG_ERR, "Saw too long a line, truncating");
len = BUFSIZ;
}
if ((sptr = strndup(*argv+7,len)) == NULL)
goto ERROR;
/* sptr now contains something guaranteed to be <= BUFSIZ, so we don't need to
check lengths for greater than BUFSIZ later on */
/* Save a copy of sptr, so we can free the memory later */
cpyptr = sptr;
if ( (!strncmp(sptr, "'(", 2)) && (!strncmp(sptr+len-2, ")'", 2)) ) {
/* the line matches '(foo)' or '(foo|bar)', so we want to strip the outer brackets */
sptr[len-2] = '\0';
sptr = sptr+2;
char *temp;
for (n = 0 ; ; sptr = NULL, n++) {
if ( (temp = strtok_r(sptr, "|", &saveptr) ) == NULL )
break;
if ((marker[n] = strdup(temp)) == NULL)
goto ERROR;
}
} else {
/* We only saw marker=foo. Just take the value of marker */
if ((marker[0] = strdup(sptr)) == NULL) {
goto ERROR;
}
n = 1;
}
/* free sptr/cpyptr - this is the only way to do it, I think, since strtok is destructive */
if (cpyptr)
free(cpyptr);
break;
} else {
pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
}
}
/* we didn't see a marker= line, give it the defaults */
if (n < 1) {
if (((marker[0] = malloc(2)) == NULL) || ((marker[1] = malloc(2)) == NULL)) {
goto ERROR;
}
strncpy (marker[0],"*\0",2);
strncpy (marker[1],"!\0",2);
n = 2;
}
/* Now do the actual comparison against the crypt password string */
const char *user;
int pamretval;
int ret = 0;
pamretval = pam_get_user(pamh, &user, NULL);
if (pamretval == PAM_SUCCESS) {
struct spwd *spw;
int i;
if ((spw = getspnam(user)) != NULL) {
for (i = 0; i < n; i++) {
if (!strncmp(spw->sp_pwdp,marker[i],strlen(marker[i]))) {
pam_syslog(pamh, LOG_INFO, "Refusing locked account for %s", user);
ret = 1;
}
}
}
}
for (a = 0;a < n; a++) {
if (marker[a])
free(marker[a]);
}
free(marker);
return ret;
ERROR:
pam_syslog(pamh, LOG_ERR, "malloc failed");
if (cpyptr)
free(cpyptr);
for (a = 0;a < n; a++) {
if (marker[a])
free(marker[a]);
}
if (marker)
free(marker);
return 1;
}
PAM_EXTERN int
pam_sm_authenticate(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
if (_is_shadow_locked(pamh,argc,argv))
return PAM_AUTH_ERR;
return PAM_SUCCESS;
}
PAM_EXTERN int
pam_sm_setcred(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
if (_is_shadow_locked(pamh,argc,argv))
return PAM_CRED_ERR;
return PAM_SUCCESS;
}
/* --- account management functions --- */
PAM_EXTERN int
pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
if (_is_shadow_locked(pamh,argc,argv))
return PAM_AUTH_ERR;
return PAM_SUCCESS;
}
/* --- password management --- */
PAM_EXTERN int
pam_sm_chauthtok(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
if (_is_shadow_locked(pamh,argc,argv))
return PAM_AUTHTOK_ERR;
return PAM_SUCCESS;
}
/* --- session management --- */
PAM_EXTERN int
pam_sm_open_session(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
if (_is_shadow_locked(pamh,argc,argv))
return PAM_SESSION_ERR;
return PAM_SUCCESS;
}
PAM_EXTERN int
pam_sm_close_session(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
if (_is_shadow_locked(pamh,argc,argv))
return PAM_SESSION_ERR;
return PAM_SUCCESS;
}
/* end of module definition */
/* static module data */
#ifdef PAM_STATIC
struct pam_module _pam_shadow_locked_modstruct = {
"pam_shadow_locked",
pam_sm_authenticate,
pam_sm_setcred,
pam_sm_acct_mgmt,
pam_sm_open_session,
pam_sm_close_session,
pam_sm_chauthtok
};
#endif
signature.asc
Description: Digital signature

