diff -urNp pam_passwdqc-1.0.5-orig/pam_passwdqc.c pam_passwdqc-1.0.5/pam_passwdqc.c --- pam_passwdqc-1.0.5-orig/pam_passwdqc.c 2008-02-12 15:11:13.000000000 -0500 +++ pam_passwdqc-1.0.5/pam_passwdqc.c 2009-09-28 12:10:32.171696694 -0400 @@ -70,6 +70,8 @@ typedef struct { passwdqc_params_t qc; int flags; int retry; + char oldpass_prompt_file[FILE_LEN+1]; + char newpass_prompt_file[FILE_LEN+1]; } params_t; static params_t defaults = { @@ -79,10 +81,13 @@ static params_t defaults = { 3, /* passphrase_words */ 4, /* match_length */ 1, /* similar_deny */ - 42 /* random_bits */ + 42, /* random_bits */ + 1 /* firstupper_lastdigit_check */ }, F_ENFORCE_EVERYONE, /* flags */ - 3 /* retry */ + 3, /* retry */ + "", /* oldpass_prompt_file */ + "" /* newpass_prompt_file */ }; #define PROMPT_OLDPASS \ @@ -361,6 +366,37 @@ static int parse(params_t *params, pam_h if (!strcmp(*argv, "use_authtok")) { params->flags |= F_USE_AUTHTOK; } else + if (!strcmp(*argv, "disable_firstupper_lastdigit_check")) { + params->qc.firstupper_lastdigit_check = 0; + } else + if (!strncmp(*argv, "oldpass_prompt_file=", 20)) { + int n; + FILE *fp = fopen(*argv + 20, "r"); + if (fp) { + n=fread(params->oldpass_prompt_file, sizeof(char), FILE_LEN, fp); + if (0==n || ferror(fp)!=0 ) { + memset(params->oldpass_prompt_file, '\0', FILE_LEN+1); + } + else { + feof(fp)? (params->oldpass_prompt_file[n-1]='\0'): (params->oldpass_prompt_file[n]='\0'); + } + fclose(fp); + } + } else + if (!strncmp(*argv, "newpass_prompt_file=", 20)) { + int n; + FILE *fp = fopen(*argv + 20, "r"); + if (fp) { + n=fread(params->newpass_prompt_file, sizeof(char), FILE_LEN, fp); + if (0==n || ferror(fp)!=0 ) { + memset(params->newpass_prompt_file, '\0', FILE_LEN+1); + } + else { + feof(fp)? (params->newpass_prompt_file[n-1]='\0'): (params->newpass_prompt_file[n]='\0'); + } + fclose(fp); + } + } else break; argc--; argv++; } @@ -406,7 +442,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_hand if (ask_oldauthtok && !am_root(pamh)) { status = converse(pamh, PAM_PROMPT_ECHO_OFF, - PROMPT_OLDPASS, &resp); + strlen(params.oldpass_prompt_file) ? params.oldpass_prompt_file : PROMPT_OLDPASS, &resp); if (status == PAM_SUCCESS) { if (resp && resp->resp) { @@ -540,8 +576,7 @@ retry: MESSAGE_RANDOMFAILED : MESSAGE_MISCONFIGURED); return PAM_AUTHTOK_ERR; } - - status = converse(pamh, PAM_PROMPT_ECHO_OFF, PROMPT_NEWPASS1, &resp); + status = converse(pamh, PAM_PROMPT_ECHO_OFF, strlen(params.newpass_prompt_file) ? params.newpass_prompt_file : PROMPT_NEWPASS1, &resp); if (status == PAM_SUCCESS && (!resp || !resp->resp)) status = PAM_AUTHTOK_ERR; diff -urNp pam_passwdqc-1.0.5-orig/passwdqc_check.c pam_passwdqc-1.0.5/passwdqc_check.c --- pam_passwdqc-1.0.5-orig/passwdqc_check.c 2008-02-12 14:31:52.000000000 -0500 +++ pam_passwdqc-1.0.5/passwdqc_check.c 2009-09-25 22:45:16.080842425 -0400 @@ -90,10 +90,12 @@ static int is_simple(passwdqc_params_t * /* Upper case characters and digits used in common ways don't increase the * strength of a password */ - c = (unsigned char)newpass[0]; - if (uppers && isascii(c) && isupper(c)) uppers--; - c = (unsigned char)newpass[length - 1]; - if (digits && isascii(c) && isdigit(c)) digits--; + if (params->firstupper_lastdigit_check) { + c = (unsigned char)newpass[0]; + if (uppers && isascii(c) && isupper(c)) uppers--; + c = (unsigned char)newpass[length - 1]; + if (digits && isascii(c) && isdigit(c)) digits--; + } /* Count the number of different character classes we've seen. We assume * that there are no non-ASCII characters for digits. */ diff -urNp pam_passwdqc-1.0.5-orig/passwdqc.h pam_passwdqc-1.0.5/passwdqc.h --- pam_passwdqc-1.0.5-orig/passwdqc.h 2008-02-12 14:30:00.000000000 -0500 +++ pam_passwdqc-1.0.5/passwdqc.h 2009-09-25 14:08:56.214695858 -0400 @@ -7,12 +7,15 @@ #include +#define FILE_LEN 4096 /* Max file len = 4096 */ + typedef struct { int min[5], max; int passphrase_words; int match_length; int similar_deny; int random_bits; + int firstupper_lastdigit_check; } passwdqc_params_t; extern char _passwdqc_wordset_4k[0x1000][6]; diff -urNp pam_passwdqc-1.0.5-orig/README pam_passwdqc-1.0.5/README --- pam_passwdqc-1.0.5-orig/README 2008-02-12 14:43:33.000000000 -0500 +++ pam_passwdqc-1.0.5/README 2009-09-28 12:12:40.251016423 -0400 @@ -41,9 +41,12 @@ words (see the "passphrase" option below N3 and N4 are used for passwords consisting of characters from three and four character classes, respectively. + disable_firstupper_lastdigit_check [] + When calculating the number of character classes, upper-case letters used as the first character and digits used as the last character of a -password are not counted. +password are not counted. To disable this, you can specify +"disable_firstupper_lastdigit_check". In addition to being sufficiently long, passwords are required to contain enough different characters for the character classes and @@ -142,6 +145,14 @@ This disables user interaction within pa the only difference between "use_first_pass" and "use_authtok" is that the former is incompatible with "ask_oldauthtok". + oldpass_prompt_file=absolute-file-path [] + newpass_prompt_file=abosulte-file-path [] + +The options "oldpass_prompt_file" and "newpass_prompt_file" can be used +to override prompts while requesting old password and new password, +respectively. The maximum size of the prompt files can be 4096 +characters at present. If the file size is more than 4096 characters, the +output will be truncated to 4096 characters. -- Solar Designer