What the pam_cracklib module really lacks is the ability to define that the password must have - at least x digits - at least x non-alphabetic character - at least x upper case letter - at least x character long At my work we have a lot of security policies and one of our policy is to force people to use at least one digit, one non-alphabetic character, and at least one upper case letter in their passwords. These restricions are very easy to set on AIX and NT. Since I'm working on the integration of Linux into our architecture, I made some changes to the pam_cracklib module so that our managers and don't have to write a risk acceptance specifically for Linux. My suggestions is as follows: ----------------------------- E.g. when you pass the parameter dcredit >= 0, then credits are used (this is what pam_cracklib currently does). If you pass the parameter dcredit < 0, then the password must contain at least abs(dcredit) digit, hence no credits are given. The same applies to ucredit and ocredit. So the parameters in /etc/pam.d/passwd for these kind of restrictions look like: password required /lib/security/pam_cracklib.so retry=3 lcredit=0 dcredit=-1 ucredit=-1 ocredit=-1 minlen=8 difok=0 Let me know what you think about it. Here is the patch for these 3 parameters and as you can see these are very small changes in pam_cracklib.c. --- pam_cracklib.c.orig Sat Mar 31 17:50:41 2001 +++ pam_cracklib.c Sat Mar 31 22:05:45 2001 @@ -151,11 +151,11 @@ opt->min_length = CO_MIN_LENGTH_BASE; } else if (!strncmp(*argv,"dcredit=",8)) { opt->dig_credit = strtol(*argv+8,&ep,10); - if (!ep || (opt->dig_credit < 0)) + if (!ep) opt->dig_credit = 0; } else if (!strncmp(*argv,"ucredit=",8)) { opt->up_credit = strtol(*argv+8,&ep,10); - if (!ep || (opt->up_credit < 0)) + if (!ep) opt->up_credit = 0; } else if (!strncmp(*argv,"lcredit=",8)) { opt->low_credit = strtol(*argv+8,&ep,10); @@ -163,7 +163,7 @@ opt->low_credit = 0; } else if (!strncmp(*argv,"ocredit=",8)) { opt->oth_credit = strtol(*argv+8,&ep,10); - if (!ep || (opt->oth_credit < 0)) + if (!ep) opt->oth_credit = 0; } else if (!strncmp(*argv,"use_authtok",11)) { opt->use_authtok = 1; @@ -354,23 +354,41 @@ * defaults cause the effect to be the same as before the change */ - if (digits > opt->dig_credit) + if (opt->dig_credit >= 0 && digits > opt->dig_credit) digits = opt->dig_credit; - if (uppers > opt->up_credit) + if (opt->up_credit >= 0 && uppers > opt->up_credit) uppers = opt->up_credit; if (lowers > opt->low_credit) lowers = opt->low_credit; - if (others > opt->oth_credit) + if (opt->oth_credit >= 0 && others > opt->oth_credit) others = opt->oth_credit; size = opt->min_length; - size -= digits; - size -= uppers; + if (opt->dig_credit >= 0) + size -= digits; + else + { + if (digits < opt->dig_credit * -1) + return 1; + } + if (opt->up_credit >= 0) + size -= uppers; + else + { + if (uppers < opt->up_credit * -1) + return 1; + } size -= lowers; - size -= others; + if (opt->oth_credit >= 0) + size -= others; + else + { + if (others < opt->oth_credit * -1) + return 1; + } if (size <= i) return 0; Thanks Werner