int verify_pwd_hash(const char *p, char *hash, unsigned int nullok) { size_t hash_len; char *pp = NULL; int retval; D(("called")); strip_hpux_aging(hash); hash_len = strlen(hash); if (!hash_len) { /* the stored password is NULL */ if (nullok) { /* this means we've succeeded */ D(("user has empty password - access granted")); retval = PAM_SUCCESS; } else { D(("user has empty password - access denied")); retval = PAM_AUTH_ERR; } } else if (!p || *hash == '*' || *hash == '!') { retval = PAM_AUTH_ERR; } else { if (!strncmp(hash, "$1$", 3)) { pp = Goodcrypt_md5(p, hash); if (pp && strcmp(pp, hash) != 0) { _pam_delete(pp); pp = Brokencrypt_md5(p, hash); } } else if (*hash != '$' && hash_len >= 13) { pp = bigcrypt(p, hash); if (pp && hash_len == 13 && strlen(pp) > hash_len) { _pam_overwrite(pp + hash_len); } } else { /* * Ok, we don't know the crypt algorithm, but maybe * libcrypt knows about it? We should try it. */ #ifdef HAVE_CRYPT_R struct crypt_data *cdata; cdata = malloc(sizeof(*cdata)); if (cdata != NULL) { cdata->initialized = 0; pp = x_strdup(crypt_r(p, hash, cdata)); memset(cdata, '\0', sizeof(*cdata)); free(cdata); } #else pp = x_strdup(crypt(p, hash)); #endif } p = NULL; /* no longer needed here */ /* the moment of truth -- do we agree with the password? */ D(("comparing state of pp[%s] and hash[%s]", pp, hash)); if (pp && strcmp(pp, hash) == 0) { retval = PAM_SUCCESS; } else { retval = PAM_AUTH_ERR; } } if (pp) _pam_delete(pp); D(("done [%d].", retval)); return retval; }
static int _unix_verify_password(const char *name, const char *p, int opt) { struct passwd *pwd = NULL; struct spwd *spwdent = NULL; char *salt = NULL; char *pp = NULL; int retval = UNIX_FAILED; /* UNIX passwords area */ setpwent(); pwd = getpwnam(name); /* Get password file entry... */ endpwent(); if (pwd != NULL) { if (strcmp(pwd->pw_passwd, "x") == 0) { /* * ...and shadow password file entry for this user, * if shadowing is enabled */ setspent(); spwdent = getspnam(name); endspent(); if (spwdent != NULL) salt = x_strdup(spwdent->sp_pwdp); else pwd = NULL; } else { if (strcmp(pwd->pw_passwd, "*NP*") == 0) { /* NIS+ */ uid_t save_uid; save_uid = geteuid(); seteuid(pwd->pw_uid); spwdent = getspnam(name); seteuid(save_uid); salt = x_strdup(spwdent->sp_pwdp); } else { salt = x_strdup(pwd->pw_passwd); } } } if (pwd == NULL || salt == NULL) { _log_err(LOG_ALERT, "check pass; user unknown"); p = NULL; return retval; } if (strlen(salt) == 0) return (opt == 0) ? UNIX_FAILED : UNIX_PASSED; /* the moment of truth -- do we agree with the password? */ retval = UNIX_FAILED; if (!strncmp(salt, "$1$", 3)) { pp = Goodcrypt_md5(p, salt); if (strcmp(pp, salt) == 0) { retval = UNIX_PASSED; } else { pp = Brokencrypt_md5(p, salt); if (strcmp(pp, salt) == 0) retval = UNIX_PASSED; } } else { pp = bigcrypt(p, salt); if (strcmp(pp, salt) == 0) { retval = UNIX_PASSED; } } p = NULL; /* no longer needed here */ /* clean up */ { char *tp = pp; if (pp != NULL) { while (tp && *tp) *tp++ = '\0'; } pp = tp = NULL; } return retval; }
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { int i; const char *name; char const * password; char const * pwdfilename = NULL; char const * stored_crypted_password = NULL; char const * crypted_password; FILE *pwdfile; int use_flock = 0; int use_delay = 1; int legacy_crypt = 0; int debug = 0; char * linebuf = NULL; size_t linebuflen; #ifdef USE_CRYPT_R struct crypt_data crypt_buf; #endif /* we require the pwdfile switch and argument to be present, else we don't work */ for (i = 0; i < argc; ++i) { if (!strcmp(argv[i], "pwdfile") && i + 1 < argc) pwdfilename = argv[++i]; else if (!strncmp(argv[i], "pwdfile=", strlen("pwdfile="))) pwdfilename = argv[i] + strlen("pwdfile="); else if (!strcmp(argv[i], "flock")) use_flock = 1; else if (!strcmp(argv[i], "noflock")) use_flock = 0; else if (!strcmp(argv[i], "nodelay")) use_delay = 0; else if (!strcmp(argv[i], "debug")) debug = 1; else if (!strcmp(argv[i], "legacy_crypt")) legacy_crypt = 1; } #ifdef HAVE_PAM_FAIL_DELAY if (use_delay) { if (debug) pam_syslog(pamh, LOG_DEBUG, "setting fail delay"); (void) pam_fail_delay(pamh, 2000000); /* 2 sec */ } #endif if (!pwdfilename) { pam_syslog(pamh, LOG_ERR, "password file name not specified"); return PAM_AUTHINFO_UNAVAIL; } if (pam_get_user(pamh, &name, NULL) != PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "couldn't get username from PAM stack"); return PAM_AUTH_ERR; } if (debug) pam_syslog(pamh, LOG_DEBUG, "username is %s", name); if (!(pwdfile = fopen(pwdfilename, "r"))) { pam_syslog(pamh, LOG_ALERT, "couldn't open password file %s", pwdfilename); return PAM_AUTHINFO_UNAVAIL; } if (use_flock && lock_fd(fileno(pwdfile)) == -1) { pam_syslog(pamh, LOG_ALERT, "couldn't lock password file %s", pwdfilename); fclose(pwdfile); return PAM_AUTHINFO_UNAVAIL; } /* get the crypted password corresponding to this user out of pwdfile */ while (getline(&linebuf, &linebuflen, pwdfile) > 0) { /* strsep changes its argument, make a copy */ char * nexttok = linebuf; /* first field: username */ char * curtok = strsep(&nexttok, ":"); /* skip non-matching usernames */ if (strcmp(curtok, name)) continue; /* second field: password (until next colon or newline) */ if ((curtok = strsep(&nexttok, ":\n"))) { stored_crypted_password = curtok; break; } } fclose(pwdfile); /* we keep linebuf (allocated by getline), stored_crypted_password is pointing into it */ if (!stored_crypted_password) if (debug) pam_syslog(pamh, LOG_ERR, "user not found in password database"); if (stored_crypted_password && !strlen(stored_crypted_password)) { if (debug) pam_syslog(pamh, LOG_DEBUG, "user has empty password field"); free(linebuf); return flags & PAM_DISALLOW_NULL_AUTHTOK ? PAM_AUTH_ERR : PAM_SUCCESS; } if (pam_get_authtok(pamh, PAM_AUTHTOK, &password, NULL) != PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "couldn't get password from PAM stack"); free(linebuf); return PAM_AUTH_ERR; } if (!stored_crypted_password) { free(linebuf); return PAM_USER_UNKNOWN; } if (debug) pam_syslog(pamh, LOG_DEBUG, "got crypted password == '%s'", stored_crypted_password); #ifdef USE_CRYPT_R crypt_buf.initialized = 0; if (!(crypted_password = crypt_r(password, stored_crypted_password, &crypt_buf))) #else if (!(crypted_password = crypt(password, stored_crypted_password))) #endif { pam_syslog(pamh, LOG_ERR, "crypt() failed"); free(linebuf); return PAM_AUTH_ERR; } if (legacy_crypt && strcmp(crypted_password, stored_crypted_password)) { if (!strncmp(stored_crypted_password, "$1$", 3)) crypted_password = Brokencrypt_md5(password, stored_crypted_password); else crypted_password = bigcrypt(password, stored_crypted_password); } if (strcmp(crypted_password, stored_crypted_password)) { pam_syslog(pamh, LOG_NOTICE, "wrong password for user %s", name); free(linebuf); return PAM_AUTH_ERR; } if (debug) pam_syslog(pamh, LOG_DEBUG, "passwords match"); free(linebuf); return PAM_SUCCESS; }
/* expected hook for auth service */ 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_BCPWD_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: "******"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) { D(_pam_log(LOG_ERR,"password hash type is 'md5'")); /* 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_BCPWD_LEN] = '\0'; if (strlen(stored_crypted_password) <= CRYPTED_DESPWD_LEN) { D(_pam_log(LOG_ERR,"password hash type is 'crypt'")); crypted_password = crypt(password, salt); } else { D(_pam_log(LOG_ERR,"password hash type is 'bigcrypt'")); 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; }