static int check_old_password(const char *forwho, const char *newpass) { static char buf[16384]; char *s_luser, *s_uid, *s_npas, *s_pas; int retval = PAM_SUCCESS; FILE *opwfile; opwfile = fopen(OLD_PASSWORDS_FILE, "r"); if (opwfile == NULL) return PAM_AUTHTOK_ERR; while (fgets(buf, 16380, opwfile)) { if (!strncmp(buf, forwho, strlen(forwho))) { buf[strlen(buf) - 1] = '\0'; s_luser = strtok(buf, ":,"); s_uid = strtok(NULL, ":,"); s_npas = strtok(NULL, ":,"); s_pas = strtok(NULL, ":,"); while (s_pas != NULL) { if (!strcmp(Goodcrypt_md5(newpass, s_pas), s_pas)) { retval = PAM_AUTHTOK_ERR; break; } s_pas = strtok(NULL, ":,"); } break; } } fclose(opwfile); return retval; }
static char *crypt_md5_wrapper(const char *pass_new) { /* * Code lifted from Marek Michalkiewicz's shadow suite. (CG) * removed use of static variables (AGM) */ struct timeval tv; MD5_CTX ctx; unsigned char result[16]; char *cp = (char *) result; unsigned char tmp[16]; int i; char *x = NULL; GoodMD5Init(&ctx); gettimeofday(&tv, (struct timezone *) 0); GoodMD5Update(&ctx, (void *) &tv, sizeof tv); i = getpid(); GoodMD5Update(&ctx, (void *) &i, sizeof i); i = clock(); GoodMD5Update(&ctx, (void *) &i, sizeof i); GoodMD5Update(&ctx, result, sizeof result); GoodMD5Final(tmp, &ctx); strcpy(cp, "$1$"); /* magic for the MD5 */ cp += strlen(cp); for (i = 0; i < 8; i++) *cp++ = i64c(tmp[i] & 077); *cp = '\0'; /* no longer need cleartext */ x = Goodcrypt_md5(pass_new, (const char *) result); return x; }
char * crypt_md5_wrapper(const char *pass_new) { unsigned char result[16]; char *cp = (char *) result; cp = stpcpy(cp, "$1$"); /* magic for the MD5 */ crypt_make_salt(cp, 8); /* no longer need cleartext */ cp = Goodcrypt_md5(pass_new, (const char *) result); pass_new = NULL; return cp; }
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; }
/* 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; }