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