/* * skey_authenticate() * * Used when calling program will allow input of the user's * response to the challenge. * * Returns: 0 success, -1 failure * */ int skey_authenticate(char *username) { char pbuf[SKEY_MAX_PW_LEN+1], skeyprompt[SKEY_MAX_CHALLENGE+1]; struct skey skey; int i; /* Get the S/Key challenge (may be fake) */ i = skeychallenge(&skey, username, skeyprompt); (void)fprintf(stderr, "%s\nResponse: ", skeyprompt); (void)fflush(stderr); /* Time out on user input after 2 minutes */ tgetline(fileno(stdin), pbuf, sizeof(pbuf), 120); sevenbit(pbuf); (void)rewind(stdin); /* Is it a valid response? */ if (i == 0 && skeyverify(&skey, pbuf) == 0) { if (skey.n < 5) { (void)fprintf(stderr, "\nWarning! Key initialization needed soon. (%d logins left)\n", skey.n); } return (0); } return (-1); }
/* * skey_passcheck() * * Check to see if answer is the correct one to the current * challenge. * * Returns: 0 success, -1 failure * */ int skey_passcheck(char *username, char *passwd) { struct skey skey; int i; i = skeylookup(&skey, username); if (i == -1 || i == 1) return (-1); if (skeyverify(&skey, passwd) == 0) return (skey.n); return (-1); }
int pw_auth (const char *cipher, const char *user, int reason, const char *input) { char prompt[1024]; char *clear = NULL; const char *cp; int retval; #ifdef SKEY int use_skey = 0; char challenge_info[40]; struct skey skey; #endif /* * There are programs for adding and deleting authentication data. */ if (reason == PW_ADD || reason == PW_DELETE) return 0; /* * There are even programs for changing the user name ... */ if (reason == PW_CHANGE && input != (char *) 0) return 0; /* * WARNING: * * When we change a password and we are root, we don't prompt. * This is so root can change any password without having to * know it. This is a policy decision that might have to be * revisited. */ if (reason == PW_CHANGE && getuid () == 0) return 0; /* * WARNING: * * When we are logging in a user with no ciphertext password, * we don't prompt for the password or anything. In reality * the user could just hit <ENTER>, so it doesn't really * matter. */ if (cipher == (char *) 0 || *cipher == '\0') return 0; #ifdef SKEY /* * If the user has an S/KEY entry show them the pertinent info * and then we can try validating the created cyphertext and the SKEY. * If there is no SKEY information we default to not using SKEY. */ if (skeychallenge (&skey, user, challenge_info) == 0) use_skey = 1; #endif /* * Prompt for the password as required. FTPD and REXECD both * get the cleartext password for us. */ if (reason != PW_FTP && reason != PW_REXEC && !input) { if (!(cp = getdef_str ("LOGIN_STRING"))) cp = _(PROMPT); #ifdef SKEY if (use_skey) printf ("[%s]\n", challenge_info); #endif snprintf (prompt, sizeof prompt, cp, user); clear = getpass (prompt); if (!clear) { static char c[1]; c[0] = '\0'; clear = c; } input = clear; } /* * Convert the cleartext password into a ciphertext string. * If the two match, the return value will be zero, which is * SUCCESS. Otherwise we see if SKEY is being used and check * the results there as well. */ retval = strcmp (pw_encrypt (input, cipher), cipher); #ifdef SKEY /* * If (1) The password fails to match, and * (2) The password is empty and * (3) We are using OPIE or S/Key, then * ...Re-prompt, with echo on. * -- AR 8/22/1999 */ if (retval && !input[0] && (use_skey)) { strncat (prompt, "(Echo on) ", (sizeof (prompt) - strlen (prompt))); clear = getpass_with_echo (prompt); if (!clear) { static char c[1]; c[0] = '\0'; clear = c; } input = clear; } if (retval && use_skey) { int passcheck = -1; if (skeyverify (&skey, input) == 0) passcheck = skey.n; if (passcheck > 0) retval = 0; } #endif /* * Things like RADIUS authentication may need the password - * if the external variable wipe_clear_pass is zero, we will * not wipe it (the caller should wipe clear_pass when it is * no longer needed). --marekm */ clear_pass = clear; if (wipe_clear_pass && clear && *clear) strzero (clear); return retval; }