[libfko] start on refactoring fko_decode_spa_data() to put SPA field parsing into dedicated functions

This commit is contained in:
Michael Rash 2014-03-14 19:21:33 -04:00
parent ad512ff6e7
commit 2eff0c01aa

View File

@ -34,13 +34,262 @@
#include "base64.h"
#include "digest.h"
static int
parse_msg(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
{
if((*t_size = strcspn(*ndx, ":")) < 1)
return(FKO_ERROR_INVALID_DATA_DECODE_MESSAGE_MISSING);
if (*t_size > MAX_SPA_MESSAGE_SIZE)
return(FKO_ERROR_INVALID_DATA_DECODE_MESSAGE_TOOBIG);
strlcpy(tbuf, *ndx, *t_size+1);
if(ctx->message != NULL)
free(ctx->message);
ctx->message = malloc(*t_size+1); /* Yes, more than we need */
if(ctx->message == NULL)
return(FKO_ERROR_MEMORY_ALLOCATION);
if(b64_decode(tbuf, (unsigned char*)ctx->message) < 0)
return(FKO_ERROR_INVALID_DATA_DECODE_MESSAGE_DECODEFAIL);
if(ctx->message_type == FKO_COMMAND_MSG)
{
/* Require a message similar to: 1.2.3.4,<command>
*/
if(validate_cmd_msg(ctx->message) != FKO_SUCCESS)
{
return(FKO_ERROR_INVALID_DATA_DECODE_MESSAGE_VALIDFAIL);
}
}
else
{
/* Require a message similar to: 1.2.3.4,tcp/22
*/
if(validate_access_msg(ctx->message) != FKO_SUCCESS)
{
return(FKO_ERROR_INVALID_DATA_DECODE_ACCESS_VALIDFAIL);
}
}
*ndx += *t_size + 1;
return FKO_SUCCESS;
}
static int
parse_nat_msg(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
{
if( ctx->message_type == FKO_NAT_ACCESS_MSG
|| ctx->message_type == FKO_LOCAL_NAT_ACCESS_MSG
|| ctx->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG
|| ctx->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG)
{
if((*t_size = strcspn(*ndx, ":")) < 1)
return(FKO_ERROR_INVALID_DATA_DECODE_NATACCESS_MISSING);
if (*t_size > MAX_SPA_MESSAGE_SIZE)
return(FKO_ERROR_INVALID_DATA_DECODE_NATACCESS_TOOBIG);
strlcpy(tbuf, *ndx, *t_size+1);
if(ctx->nat_access != NULL)
free(ctx->nat_access);
ctx->nat_access = malloc(*t_size+1); /* Yes, more than we need */
if(ctx->nat_access == NULL)
return(FKO_ERROR_MEMORY_ALLOCATION);
if(b64_decode(tbuf, (unsigned char*)ctx->nat_access) < 0)
return(FKO_ERROR_INVALID_DATA_DECODE_NATACCESS_DECODEFAIL);
if(validate_nat_access_msg(ctx->nat_access) != FKO_SUCCESS)
return(FKO_ERROR_INVALID_DATA_DECODE_NATACCESS_VALIDFAIL);
*ndx += *t_size + 1;
}
return FKO_SUCCESS;
}
static int
parse_server_auth(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
{
strlcpy(tbuf, *ndx, *t_size+1);
if(ctx->server_auth != NULL)
free(ctx->server_auth);
ctx->server_auth = malloc(*t_size+1); /* Yes, more than we need */
if(ctx->server_auth == NULL)
return(FKO_ERROR_MEMORY_ALLOCATION);
if(b64_decode(tbuf, (unsigned char*)ctx->server_auth) < 0)
return(FKO_ERROR_INVALID_DATA_DECODE_SRVAUTH_DECODEFAIL);
return FKO_SUCCESS;
}
static int
parse_client_timeout(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
{
int is_err;
if( ctx->message_type == FKO_CLIENT_TIMEOUT_ACCESS_MSG
|| ctx->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG
|| ctx->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG)
{
if((*t_size = strlen(*ndx)) < 1)
return(FKO_ERROR_INVALID_DATA_DECODE_TIMEOUT_MISSING);
if (*t_size > MAX_SPA_MESSAGE_SIZE)
return(FKO_ERROR_INVALID_DATA_DECODE_TIMEOUT_TOOBIG);
/* Should be a number only.
*/
if(strspn(*ndx, "0123456789") != *t_size)
return(FKO_ERROR_INVALID_DATA_DECODE_TIMEOUT_VALIDFAIL);
ctx->client_timeout = (unsigned int) strtol_wrapper(*ndx, 0,
(2 << 15), NO_EXIT_UPON_ERR, &is_err);
if(is_err != FKO_SUCCESS)
return(FKO_ERROR_INVALID_DATA_DECODE_TIMEOUT_DECODEFAIL);
}
return FKO_SUCCESS;
}
static int
parse_msg_type(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
{
int is_err;
if((*t_size = strcspn(*ndx, ":")) < 1)
return(FKO_ERROR_INVALID_DATA_DECODE_MSGTYPE_MISSING);
if(*t_size > MAX_SPA_MESSAGE_TYPE_SIZE)
return(FKO_ERROR_INVALID_DATA_DECODE_MSGTYPE_TOOBIG);
strlcpy(tbuf, *ndx, *t_size+1);
ctx->message_type = strtol_wrapper(tbuf, 0,
FKO_LAST_MSG_TYPE, NO_EXIT_UPON_ERR, &is_err);
if(is_err != FKO_SUCCESS)
return(FKO_ERROR_INVALID_DATA_DECODE_MSGTYPE_DECODEFAIL);
*ndx += *t_size + 1;
return FKO_SUCCESS;
}
static int
parse_version(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
{
if((*t_size = strcspn(*ndx, ":")) < 1)
return(FKO_ERROR_INVALID_DATA_DECODE_VERSION_MISSING);
if (*t_size > MAX_SPA_VERSION_SIZE)
return(FKO_ERROR_INVALID_DATA_DECODE_VERSION_TOOBIG);
if(ctx->version != NULL)
free(ctx->version);
ctx->version = malloc(*t_size+1);
if(ctx->version == NULL)
return(FKO_ERROR_MEMORY_ALLOCATION);
strlcpy(ctx->version, *ndx, *t_size+1);
*ndx += *t_size + 1;
return FKO_SUCCESS;
}
static int
parse_timestamp(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
{
int is_err;
if((*t_size = strcspn(*ndx, ":")) < 1)
return(FKO_ERROR_INVALID_DATA_DECODE_TIMESTAMP_MISSING);
if (*t_size > MAX_SPA_TIMESTAMP_SIZE)
return(FKO_ERROR_INVALID_DATA_DECODE_TIMESTAMP_TOOBIG);
strlcpy(tbuf, *ndx, *t_size+1);
ctx->timestamp = (unsigned int) strtol_wrapper(tbuf,
0, -1, NO_EXIT_UPON_ERR, &is_err);
if(is_err != FKO_SUCCESS)
return(FKO_ERROR_INVALID_DATA_DECODE_TIMESTAMP_DECODEFAIL);
*ndx += *t_size + 1;
return FKO_SUCCESS;
}
static int
parse_username(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
{
if((*t_size = strcspn(*ndx, ":")) < 1)
return(FKO_ERROR_INVALID_DATA_DECODE_USERNAME_MISSING);
if (*t_size > MAX_SPA_USERNAME_SIZE)
return(FKO_ERROR_INVALID_DATA_DECODE_USERNAME_TOOBIG);
strlcpy(tbuf, *ndx, *t_size+1);
if(ctx->username != NULL)
free(ctx->username);
ctx->username = malloc(*t_size+1); /* Yes, more than we need */
if(ctx->username == NULL)
return(FKO_ERROR_MEMORY_ALLOCATION);
if(b64_decode(tbuf, (unsigned char*)ctx->username) < 0)
return(FKO_ERROR_INVALID_DATA_DECODE_USERNAME_DECODEFAIL);
if(validate_username(ctx->username) != FKO_SUCCESS)
return(FKO_ERROR_INVALID_DATA_DECODE_USERNAME_VALIDFAIL);
*ndx += *t_size + 1;
return FKO_SUCCESS;
}
static int
parse_rand_val(char *tbuf, char **ndx, int *t_size, fko_ctx_t ctx)
{
if((*t_size = strcspn(*ndx, ":")) < FKO_RAND_VAL_SIZE)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_RAND_MISSING);
}
if(ctx->rand_val != NULL)
free(ctx->rand_val);
ctx->rand_val = calloc(1, FKO_RAND_VAL_SIZE+1);
if(ctx->rand_val == NULL)
{
free(tbuf);
return(FKO_ERROR_MEMORY_ALLOCATION);
}
ctx->rand_val = strncpy(ctx->rand_val, *ndx, FKO_RAND_VAL_SIZE);
*ndx += *t_size + 1;
return FKO_SUCCESS;
}
/* Decode the encoded SPA data.
*/
int
fko_decode_spa_data(fko_ctx_t ctx)
{
char *tbuf, *ndx, *tmp;
int t_size, i, is_err;
int t_size, i, res;
if (! is_valid_encoded_msg_len(ctx->encoded_msg_len))
return(FKO_ERROR_INVALID_DATA_DECODE_MSGLEN_VALIDFAIL);
@ -166,242 +415,73 @@ fko_decode_spa_data(fko_ctx_t ctx)
*/
ndx = ctx->encoded_msg;
/* The rand val data */
if((t_size = strcspn(ndx, ":")) < FKO_RAND_VAL_SIZE)
/* Extract the rand val data
*/
res = parse_rand_val(tbuf, &ndx, &t_size, ctx);
if(res != FKO_SUCCESS)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_RAND_MISSING);
return res;
}
if(ctx->rand_val != NULL)
free(ctx->rand_val);
ctx->rand_val = calloc(1, FKO_RAND_VAL_SIZE+1);
if(ctx->rand_val == NULL)
{
free(tbuf);
return(FKO_ERROR_MEMORY_ALLOCATION);
}
ctx->rand_val = strncpy(ctx->rand_val, ndx, FKO_RAND_VAL_SIZE);
/* Jump to the next field (username). We need to use the temp buffer
* for the base64 decode step.
*/
ndx += t_size + 1;
if((t_size = strcspn(ndx, ":")) < 1)
res = parse_username(tbuf, &ndx, &t_size, ctx);
if(res != FKO_SUCCESS)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_USERNAME_MISSING);
}
if (t_size > MAX_SPA_USERNAME_SIZE)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_USERNAME_TOOBIG);
}
strlcpy(tbuf, ndx, t_size+1);
if(ctx->username != NULL)
free(ctx->username);
ctx->username = malloc(t_size+1); /* Yes, more than we need */
if(ctx->username == NULL)
{
free(tbuf);
return(FKO_ERROR_MEMORY_ALLOCATION);
}
if(b64_decode(tbuf, (unsigned char*)ctx->username) < 0)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_USERNAME_DECODEFAIL);
}
if(validate_username(ctx->username) != FKO_SUCCESS)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_USERNAME_VALIDFAIL);
return res;
}
/* Extract the timestamp value.
*/
ndx += t_size + 1;
if((t_size = strcspn(ndx, ":")) < 1)
res = parse_timestamp(tbuf, &ndx, &t_size, ctx);
if(res != FKO_SUCCESS)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_TIMESTAMP_MISSING);
}
if (t_size > MAX_SPA_TIMESTAMP_SIZE)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_TIMESTAMP_TOOBIG);
}
strlcpy(tbuf, ndx, t_size+1);
ctx->timestamp = (unsigned int) strtol_wrapper(tbuf,
0, -1, NO_EXIT_UPON_ERR, &is_err);
if(is_err != FKO_SUCCESS)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_TIMESTAMP_DECODEFAIL);
return res;
}
/* Extract the version string.
*/
ndx += t_size + 1;
if((t_size = strcspn(ndx, ":")) < 1)
res = parse_version(tbuf, &ndx, &t_size, ctx);
if(res != FKO_SUCCESS)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_VERSION_MISSING);
return res;
}
if (t_size > MAX_SPA_VERSION_SIZE)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_VERSION_TOOBIG);
}
if(ctx->version != NULL)
free(ctx->version);
ctx->version = malloc(t_size+1);
if(ctx->version == NULL)
{
free(tbuf);
return(FKO_ERROR_MEMORY_ALLOCATION);
}
strlcpy(ctx->version, ndx, t_size+1);
/* Extract the message type value.
*/
ndx += t_size + 1;
if((t_size = strcspn(ndx, ":")) < 1)
res = parse_msg_type(tbuf, &ndx, &t_size, ctx);
if(res != FKO_SUCCESS)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_MSGTYPE_MISSING);
}
if (t_size > MAX_SPA_MESSAGE_TYPE_SIZE)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_MSGTYPE_TOOBIG);
}
strlcpy(tbuf, ndx, t_size+1);
ctx->message_type = strtol_wrapper(tbuf, 0,
FKO_LAST_MSG_TYPE, NO_EXIT_UPON_ERR, &is_err);
if(is_err != FKO_SUCCESS)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_MSGTYPE_DECODEFAIL);
return res;
}
/* Extract the SPA message string.
*/
ndx += t_size + 1;
if((t_size = strcspn(ndx, ":")) < 1)
res = parse_msg(tbuf, &ndx, &t_size, ctx);
if(res != FKO_SUCCESS)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_MESSAGE_MISSING);
return res;
}
if (t_size > MAX_SPA_MESSAGE_SIZE)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_MESSAGE_TOOBIG);
}
strlcpy(tbuf, ndx, t_size+1);
if(ctx->message != NULL)
free(ctx->message);
ctx->message = malloc(t_size+1); /* Yes, more than we need */
if(ctx->message == NULL)
{
free(tbuf);
return(FKO_ERROR_MEMORY_ALLOCATION);
}
if(b64_decode(tbuf, (unsigned char*)ctx->message) < 0)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_MESSAGE_DECODEFAIL);
}
if(ctx->message_type == FKO_COMMAND_MSG)
{
/* Require a message similar to: 1.2.3.4,<command>
*/
if(validate_cmd_msg(ctx->message) != FKO_SUCCESS)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_MESSAGE_VALIDFAIL);
}
}
else
{
/* Require a message similar to: 1.2.3.4,tcp/22
*/
if(validate_access_msg(ctx->message) != FKO_SUCCESS)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_ACCESS_VALIDFAIL);
}
}
/* Extract nat_access string if the message_type indicates so.
/* Extract nat_access string (a check is done against the
* message type)
*/
if( ctx->message_type == FKO_NAT_ACCESS_MSG
|| ctx->message_type == FKO_LOCAL_NAT_ACCESS_MSG
|| ctx->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG
|| ctx->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG)
res = parse_nat_msg(tbuf, &ndx, &t_size, ctx);
if(res != FKO_SUCCESS)
{
ndx += t_size + 1;
if((t_size = strcspn(ndx, ":")) < 1)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_NATACCESS_MISSING);
}
if (t_size > MAX_SPA_MESSAGE_SIZE)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_NATACCESS_TOOBIG);
}
strlcpy(tbuf, ndx, t_size+1);
if(ctx->nat_access != NULL)
free(ctx->nat_access);
ctx->nat_access = malloc(t_size+1); /* Yes, more than we need */
if(ctx->nat_access == NULL)
{
free(tbuf);
return(FKO_ERROR_MEMORY_ALLOCATION);
}
if(b64_decode(tbuf, (unsigned char*)ctx->nat_access) < 0)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_NATACCESS_DECODEFAIL);
}
if(validate_nat_access_msg(ctx->nat_access) != FKO_SUCCESS)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_NATACCESS_VALIDFAIL);
}
free(tbuf);
return res;
}
/* Now look for a server_auth string.
*/
ndx += t_size + 1;
if((t_size = strlen(ndx)) > 0)
{
if (t_size > MAX_SPA_MESSAGE_SIZE)
@ -418,34 +498,20 @@ fko_decode_spa_data(fko_ctx_t ctx)
&& ctx->message_type != FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG
&& ctx->message_type != FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG)
{
strlcpy(tbuf, ndx, t_size+1);
if(ctx->server_auth != NULL)
free(ctx->server_auth);
ctx->server_auth = malloc(t_size+1); /* Yes, more than we need */
if(ctx->server_auth == NULL)
{
free(tbuf);
return(FKO_ERROR_MEMORY_ALLOCATION);
}
if(b64_decode(tbuf, (unsigned char*)ctx->server_auth) < 0)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_SRVAUTH_DECODEFAIL);
}
res = parse_server_auth(tbuf, &ndx, &t_size, ctx);
/* At this point we should be done.
*/
free(tbuf);
/* Call the context initialized.
*/
ctx->initval = FKO_CTX_INITIALIZED;
FKO_SET_CTX_INITIALIZED(ctx);
return(FKO_SUCCESS);
if(res == FKO_SUCCESS)
{
/* Call the context initialized.
*/
ctx->initval = FKO_CTX_INITIALIZED;
FKO_SET_CTX_INITIALIZED(ctx);
}
return(res);
}
/* If we are here then we may still have a server_auth string,
@ -463,8 +529,6 @@ fko_decode_spa_data(fko_ctx_t ctx)
return(FKO_ERROR_INVALID_DATA_DECODE_EXTRA_TOOBIG);
}
/* Looks like we have both, so assume this is the
*/
strlcpy(tbuf, ndx, t_size+1);
if(ctx->server_auth != NULL)
@ -488,36 +552,11 @@ fko_decode_spa_data(fko_ctx_t ctx)
/* Now we look for a timeout value if one is supposed to be there.
*/
if( ctx->message_type == FKO_CLIENT_TIMEOUT_ACCESS_MSG
|| ctx->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG
|| ctx->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG)
res = parse_client_timeout(tbuf, &ndx, &t_size, ctx);
if(res != FKO_SUCCESS)
{
if((t_size = strlen(ndx)) < 1)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_TIMEOUT_MISSING);
}
if (t_size > MAX_SPA_MESSAGE_SIZE)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_TIMEOUT_TOOBIG);
}
/* Should be a number only.
*/
if(strspn(ndx, "0123456789") != t_size)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_TIMEOUT_VALIDFAIL);
}
ctx->client_timeout = (unsigned int) strtol_wrapper(ndx, 0,
(2 << 15), NO_EXIT_UPON_ERR, &is_err);
if(is_err != FKO_SUCCESS)
{
free(tbuf);
return(FKO_ERROR_INVALID_DATA_DECODE_TIMEOUT_DECODEFAIL);
}
free(tbuf);
return res;
}
}