mirror of
https://github.com/Yubico/yubico-pam.git
synced 2024-12-03 03:24:12 +01:00
Further cleanups to challenge response code, and move more code to util.c.
This commit is contained in:
parent
cb16817047
commit
69ec1bf8a0
91
pam_yubico.c
91
pam_yubico.c
@ -51,19 +51,6 @@
|
||||
#include <security/pam_modules.h>
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG_PAM)
|
||||
# if defined(HAVE_SECURITY__PAM_MACROS_H)
|
||||
# define DEBUG
|
||||
# include <security/_pam_macros.h>
|
||||
# else
|
||||
# define D(x) do { \
|
||||
printf ("debug: %s:%d (%s): ", __FILE__, __LINE__, __FUNCTION__); \
|
||||
printf x; \
|
||||
printf ("\n"); \
|
||||
} while (0)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBLDAP
|
||||
/* Some functions like ldap_init, ldap_simple_bind_s, ldap_unbind are
|
||||
deprecated but still available. We will drop support for 'ldapserver'
|
||||
@ -88,12 +75,6 @@
|
||||
#define MAX_TOKEN_ID_LEN 16
|
||||
#define DEFAULT_TOKEN_ID_LEN 12
|
||||
|
||||
/* Challenges can be 0..63 or 64 bytes long, depending on YubiKey configuration.
|
||||
* We settle for 63 bytes to have something that works with all configurations.
|
||||
*/
|
||||
#define CR_CHALLENGE_SIZE 63
|
||||
#define CR_RESPONSE_SIZE 20
|
||||
|
||||
/*
|
||||
* This function will look for users name with valid user token id. It
|
||||
* will returns 0 for failure and 1 for success.
|
||||
@ -396,17 +377,15 @@ do_challenge_response(struct cfg *cfg, const char *username)
|
||||
{
|
||||
char *userfile = NULL, *tmpfile = NULL;
|
||||
FILE *f = NULL;
|
||||
unsigned char challenge[CR_CHALLENGE_SIZE + 1];
|
||||
unsigned char challenge_hex[sizeof(challenge) * 2 + 1], expected_response[CR_RESPONSE_SIZE * 2 + 1];
|
||||
int r, slot, ret, fd;
|
||||
unsigned char buf[CR_RESPONSE_SIZE + 16], response_hex[CR_RESPONSE_SIZE * 2 + 1];
|
||||
int ret;
|
||||
|
||||
unsigned char response[CR_RESPONSE_SIZE + 16]; /* Need some extra bytes in this read buffer */
|
||||
unsigned char response_hex[CR_RESPONSE_SIZE * 2 + 1];
|
||||
int yk_cmd;
|
||||
unsigned int flags = 0;
|
||||
unsigned int response_len = 0;
|
||||
unsigned int expect_bytes = 0;
|
||||
YK_KEY *yk = NULL;
|
||||
CR_STATE state;
|
||||
|
||||
int len;
|
||||
|
||||
ret = PAM_AUTH_ERR;
|
||||
@ -421,31 +400,9 @@ do_challenge_response(struct cfg *cfg, const char *username)
|
||||
|
||||
/* XXX should drop root privileges before opening file in user's home directory */
|
||||
f = fopen(userfile, "r");
|
||||
if (! f)
|
||||
goto out;
|
||||
/* XXX not ideal with hard coded lengths in this scan string.
|
||||
* 126 corresponds to twice the size of CR_CHALLENGE_SIZE,
|
||||
* 40 is twice the size of CR_RESPONSE_SIZE
|
||||
* (twice because we hex encode the challenge and response)
|
||||
*/
|
||||
r = fscanf(f, "%126[0-9a-z]:%40[0-9a-z]:%d", &challenge_hex, &expected_response, &slot);
|
||||
D(("Challenge: %s, response: %s, slot: %d", challenge_hex, expected_response, slot));
|
||||
if (r != 3)
|
||||
goto out;
|
||||
|
||||
if (! yubikey_hex_p(challenge_hex)) {
|
||||
D(("Invalid challenge hex input : %s", challenge_hex));
|
||||
if (! load_chalresp_state(f, &state))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (! yubikey_hex_p(expected_response)) {
|
||||
D(("Invalid expected response hex input : %s", expected_response));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (slot != 1 && slot != 2) {
|
||||
D(("Invalid slot input : %i", slot));
|
||||
}
|
||||
|
||||
if (! init_yubikey(&yk)) {
|
||||
D(("Failed initializing YubiKey"));
|
||||
@ -457,11 +414,9 @@ do_challenge_response(struct cfg *cfg, const char *username)
|
||||
goto out;
|
||||
}
|
||||
|
||||
yubikey_hex_decode(challenge, challenge_hex, sizeof(challenge));
|
||||
len = strlen(challenge_hex) / 2;
|
||||
|
||||
if (! challenge_response(yk, slot, challenge, len, true, flags, false,
|
||||
response, sizeof(response), &response_len)) {
|
||||
if (! challenge_response(yk, state.slot, state.challenge, state.challenge_len,
|
||||
true, flags, false,
|
||||
buf, sizeof(buf), &response_len)) {
|
||||
D(("Challenge-response FAILED"));
|
||||
goto out;
|
||||
}
|
||||
@ -470,9 +425,9 @@ do_challenge_response(struct cfg *cfg, const char *username)
|
||||
* Check YubiKey response against the expected response
|
||||
*/
|
||||
|
||||
yubikey_hex_encode(response_hex, (char *)response, response_len);
|
||||
yubikey_hex_encode(response_hex, (char *)buf, response_len);
|
||||
|
||||
if (strcmp(response_hex, expected_response) == 0) {
|
||||
if (memcmp(buf, state.response, response_len) == 0) {
|
||||
ret = PAM_SUCCESS;
|
||||
} else {
|
||||
D(("Unexpected C/R response : %s", response_hex));
|
||||
@ -481,13 +436,14 @@ do_challenge_response(struct cfg *cfg, const char *username)
|
||||
|
||||
D(("Got the expected response, generating new challenge (%i bytes).", CR_CHALLENGE_SIZE));
|
||||
|
||||
if (generate_random(challenge, CR_CHALLENGE_SIZE)) {
|
||||
if (generate_random(state.challenge, sizeof(state.challenge))) {
|
||||
D(("Failed generating new challenge!"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (! challenge_response(yk, slot, challenge, CR_CHALLENGE_SIZE, true, flags, false,
|
||||
response, sizeof(response), &response_len)) {
|
||||
if (! challenge_response(yk, state.slot, state.challenge, CR_CHALLENGE_SIZE,
|
||||
true, flags, false,
|
||||
buf, sizeof(buf), &response_len)) {
|
||||
D(("Second challenge-response FAILED"));
|
||||
goto out;
|
||||
}
|
||||
@ -498,11 +454,6 @@ do_challenge_response(struct cfg *cfg, const char *username)
|
||||
/*
|
||||
* Write the challenge and response we will expect the next time to the state file.
|
||||
*/
|
||||
|
||||
memset(challenge_hex, 0, sizeof(challenge_hex));
|
||||
memset(response_hex, 0, sizeof(response_hex));
|
||||
yubikey_hex_encode(challenge_hex, (char *)challenge, CR_CHALLENGE_SIZE);
|
||||
yubikey_hex_encode(response_hex, (char *)response, response_len);
|
||||
/* Write out the new file */
|
||||
if (fclose(f) < 0) {
|
||||
f = NULL;
|
||||
@ -519,14 +470,16 @@ do_challenge_response(struct cfg *cfg, const char *username)
|
||||
if (! f)
|
||||
goto out;
|
||||
|
||||
fd = fileno(f);
|
||||
if (fd == -1)
|
||||
if (response_len > sizeof(state.response)) {
|
||||
D(("Got too long response ??? (%i/%i)", response_len, sizeof(state.response)));
|
||||
goto out;
|
||||
fprintf(f, "%s:%s:%d\n", challenge_hex, response_hex, slot);
|
||||
if (fflush(f) < 0)
|
||||
goto out;
|
||||
if (fsync(fd) < 0)
|
||||
}
|
||||
memcpy (state.response, buf, response_len);
|
||||
state.response_len = response_len;
|
||||
|
||||
if (! write_chalresp_state (f, &state))
|
||||
goto out;
|
||||
|
||||
if (fclose(f) < 0) {
|
||||
f = NULL;
|
||||
goto out;
|
||||
|
83
util.c
83
util.c
@ -184,3 +184,86 @@ int challenge_response(YK_KEY *yk, int slot,
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
load_chalresp_state(FILE *f, CR_STATE *state)
|
||||
{
|
||||
unsigned char challenge_hex[CR_CHALLENGE_SIZE * 2 + 1], response_hex[CR_RESPONSE_SIZE * 2 + 1];
|
||||
int slot;
|
||||
int r;
|
||||
|
||||
if (! f)
|
||||
goto out;
|
||||
|
||||
/* XXX not ideal with hard coded lengths in this scan string.
|
||||
* 126 corresponds to twice the size of CR_CHALLENGE_SIZE,
|
||||
* 40 is twice the size of CR_RESPONSE_SIZE
|
||||
* (twice because we hex encode the challenge and response)
|
||||
*/
|
||||
r = fscanf(f, "%126[0-9a-z]:%40[0-9a-z]:%d", &challenge_hex, &response_hex, &slot);
|
||||
D(("Challenge: %s, response: %s, slot: %d", challenge_hex, response_hex, slot));
|
||||
if (r != 3)
|
||||
goto out;
|
||||
|
||||
if (! yubikey_hex_p(challenge_hex)) {
|
||||
D(("Invalid challenge hex input : %s", challenge_hex));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (! yubikey_hex_p(response_hex)) {
|
||||
D(("Invalid expected response hex input : %s", response_hex));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (slot != 1 && slot != 2) {
|
||||
D(("Invalid slot input : %i", slot));
|
||||
goto out;
|
||||
}
|
||||
|
||||
yubikey_hex_decode(state->challenge, challenge_hex, sizeof(state->challenge));
|
||||
state->challenge_len = strlen(challenge_hex) / 2;
|
||||
|
||||
yubikey_hex_decode(state->response, response_hex, sizeof(state->response));
|
||||
state->response_len = strlen(response_hex) / 2;
|
||||
|
||||
state->slot = slot;
|
||||
|
||||
return 1;
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
write_chalresp_state(FILE *f, CR_STATE *state)
|
||||
{
|
||||
unsigned char challenge_hex[CR_CHALLENGE_SIZE * 2 + 1], response_hex[CR_RESPONSE_SIZE * 2 + 1];
|
||||
int fd;
|
||||
|
||||
memset(challenge_hex, 0, sizeof(challenge_hex));
|
||||
memset(response_hex, 0, sizeof(response_hex));
|
||||
|
||||
yubikey_hex_encode(challenge_hex, (char *)state->challenge, state->challenge_len);
|
||||
yubikey_hex_encode(response_hex, (char *)state->response, state->response_len);
|
||||
|
||||
rewind(f);
|
||||
|
||||
fd = fileno(f);
|
||||
if (fd == -1)
|
||||
goto out;
|
||||
|
||||
if (ftruncate(fd, 0))
|
||||
goto out;
|
||||
|
||||
fprintf(f, "%s:%s:%d\n", challenge_hex, response_hex, state->slot);
|
||||
|
||||
if (fflush(f) < 0)
|
||||
goto out;
|
||||
|
||||
if (fsync(fd) < 0)
|
||||
goto out;
|
||||
|
||||
return 1;
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
34
util.h
34
util.h
@ -36,9 +36,43 @@
|
||||
#include <ykstatus.h>
|
||||
#include <ykdef.h>
|
||||
|
||||
#ifndef D
|
||||
#if defined(DEBUG_PAM)
|
||||
# if defined(HAVE_SECURITY__PAM_MACROS_H)
|
||||
# define DEBUG
|
||||
# include <security/_pam_macros.h>
|
||||
# else
|
||||
# define D(x) do { \
|
||||
printf ("debug: %s:%d (%s): ", __FILE__, __LINE__, __FUNCTION__); \
|
||||
printf x; \
|
||||
printf ("\n"); \
|
||||
} while (0)
|
||||
# endif /* HAVE_SECURITY__PAM_MACROS_H */
|
||||
#endif /* DEBUG_PAM */
|
||||
#endif /* D */
|
||||
|
||||
/* Challenges can be 0..63 or 64 bytes long, depending on YubiKey configuration.
|
||||
* We settle for 63 bytes to have something that works with all configurations.
|
||||
*/
|
||||
#define CR_CHALLENGE_SIZE 63
|
||||
#define CR_RESPONSE_SIZE 20
|
||||
|
||||
struct chalresp_state {
|
||||
unsigned char challenge[CR_CHALLENGE_SIZE];
|
||||
uint8_t challenge_len;
|
||||
unsigned char response[CR_RESPONSE_SIZE];
|
||||
uint8_t response_len;
|
||||
uint8_t slot;
|
||||
};
|
||||
|
||||
typedef struct chalresp_state CR_STATE;
|
||||
|
||||
int generate_random(char *buf, int len);
|
||||
int get_user_cfgfile_path(const char *common_path, const char *filename, const char *username, char **fn);
|
||||
|
||||
int load_chalresp_state(FILE *f, CR_STATE *state);
|
||||
int write_chalresp_state(FILE *f, CR_STATE *state);
|
||||
|
||||
int init_yubikey(YK_KEY **yk);
|
||||
int check_firmware_version(YK_KEY *yk, bool verbose, bool quiet);
|
||||
int challenge_response(YK_KEY *yk, int slot,
|
||||
|
Loading…
Reference in New Issue
Block a user