char salt[12], stored_crypted_password[CRYPTED_MD5PWD_LEN+1];
char salt[12], stored_crypted_password[CRYPTED_BCPWD_LEN+1];
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags,				   int argc, const char **argv) {    int retval, pcnt, pwdfilename_found;    const char *name;    char *password;    char pwdfilename[PWDFN_LEN];    char salt[12], stored_crypted_password[CRYPTED_MD5PWD_LEN+1];    char *crypted_password;    FILE *pwdfile;    int use_flock = 0;    int use_delay = 1;    int temp_result = 0;        /* we require the pwdfile switch and argument to be present, else we don't work */    /* pcnt is the parameter counter variable for iterating through argv */    pcnt = pwdfilename_found = 0;    do {	/* see if the current parameter looks like "pwdfile" */	if (strcmp(argv[pcnt],PWDF_PARAM)==0) {	    /* if argv is long enough, grab the subsequent parameter */	    if (pcnt+1 < argc) {		/* make sure we can't overflow */		strncpy(pwdfilename,argv[++pcnt],PWDFN_LEN);		/* indicate that we've found it */		pwdfilename_found = 1;	    }	    /* also check for "pwdfile=blah" */	} else if (strncmp(argv[pcnt],PWDF_PARAM "=",sizeof(PWDF_PARAM "=")-1)==0) {	    /* make sure we can't overflow */	    strncpy(pwdfilename,argv[pcnt]+sizeof(PWDF_PARAM),PWDFN_LEN);	    /* indicate that we've found it */	    pwdfilename_found = 1;	} else if (strcmp(argv[pcnt],FLOCK_PARAM)==0) {	    /* we have a "flock" parameter */	    use_flock = 1;	} else if (strcmp(argv[pcnt],"no" FLOCK_PARAM)==0) {	    /* or a "noflock" parameter */	    use_flock = 0;	} else if (strcmp(argv[pcnt],NODELAY_PARAM)==0) {	    /* no delay on authentication failure */	    use_delay = 0;	}	    } while (++pcnt < argc);    #ifdef HAVE_PAM_FAIL_DELAY    if (use_delay) {	D(("setting delay"));	(void) pam_fail_delay(pamh, 2000000);   /* 2 sec delay for on failure */    }#endif        /* for some or other reason, the password file wasn't specified */    if (!pwdfilename_found) {	_pam_log(LOG_ERR,"password file name not specified");	return PAM_AUTHINFO_UNAVAIL;    }        /* DEBUG */    D(_pam_log(LOG_ERR, "password filename extracted"));        /* now try to open the password file */    if ((pwdfile=fopen(pwdfilename,"r"))==NULL) {	_pam_log(LOG_ERR,"couldn't open password file %s",pwdfilename);	return PAM_AUTHINFO_UNAVAIL;    }        /* set a lock on the password file */    if (use_flock && lock_fd(fileno(pwdfile)) == -1) {	_pam_log(LOG_ERR,"couldn't lock password file %s",pwdfilename);	return PAM_AUTHINFO_UNAVAIL;    }        /* get user name */    if ((retval = pam_get_user(pamh,&name,"login: ")) != PAM_SUCCESS) {	_pam_log(LOG_ERR, "username not found");	fclose(pwdfile);	return retval;    }            /* DEBUG */    D(_pam_log(LOG_ERR,"username is %s", name));        /* get password - code from pam_unix_auth.c */    pam_get_item(pamh, PAM_AUTHTOK, (void *)&password);    if (!password) {	retval = _set_auth_tok(pamh, flags, argc, argv);	if (retval!=PAM_SUCCESS) {	    fclose(pwdfile);	    return retval;	}    }    pam_get_item(pamh, PAM_AUTHTOK, (void *)&password);        if ((retval = pam_get_item(pamh, PAM_AUTHTOK, (void *)&password)) != PAM_SUCCESS) {	_pam_log(LOG_ERR, "auth token not found");	fclose(pwdfile);	return retval;    }        /* DEBUG */    D(_pam_log(LOG_ERR,"got password from user", password));        /* now crypt password and compare to the user entry in the password file */    /* first make sure password is long enough -- may I do this? */    if (strlen(password)<2 || password==NULL) {	_pam_log(LOG_ERR,"password too short or NULL");	fclose(pwdfile);	return PAM_AUTH_ERR;    }        /* get the crypted password corresponding to this user */    if (!fgetpwnam(pwdfile, name, stored_crypted_password)) {	_pam_log(LOG_ERR,"user not found in password database");	fclose(pwdfile);	return PAM_AUTHINFO_UNAVAIL;    }        /* DEBUG */    D(_pam_log(LOG_ERR,"got crypted password == '%s'", stored_crypted_password));            temp_result = 0;        /* Extract the salt and set the passwd length, depending on MD5 or DES */    if (strncmp(stored_crypted_password, "$1$", 3) == 0) {	/* get out the salt into "salt" */	strncpy(salt, stored_crypted_password, 11);	salt[11] = '\0';	stored_crypted_password[CRYPTED_MD5PWD_LEN] = '\0';	/* try both md5 crypts */	crypted_password = Goodcrypt_md5(password, salt);	if (strcmp(crypted_password, stored_crypted_password) == 0)	{	    temp_result = 1;	}	else	{	    crypted_password = Brokencrypt_md5(password, salt);	    if (strcmp(crypted_password, stored_crypted_password) == 0)	    {		temp_result = 1;	    }	}    } else {	/* get the salt out into "salt" */	strncpy(salt, stored_crypted_password, 2);	salt[2] = '\0';	stored_crypted_password[CRYPTED_DESPWD_LEN] = '\0';		crypted_password = bigcrypt(password, salt);	if (strcmp(crypted_password, stored_crypted_password) == 0)	{	    temp_result = 1;	}    }        /* DEBUG */    D(_pam_log(LOG_ERR,"user password crypted is '%s'", crypted_password));        /* if things don't match up, complain */    if (!temp_result)     {	_pam_log(LOG_ERR,"wrong password for user %s",name);	fclose(pwdfile);	return PAM_AUTH_ERR;    }        /* DEBUG */    D(_pam_log(LOG_ERR,"passwords match"));        /* we've gotten here, i.e. authentication was sucessful! */    fclose(pwdfile);    return PAM_SUCCESS;}