A small memory footprint AMQP implimentation

Dependents:   iothub_client_sample_amqp remote_monitoring simplesample_amqp

sasl_plain.c

Committer:
Azure.IoT Build
Date:
2016-04-08
Revision:
0:6ae2f7bca550
Child:
6:641a9672db08

File content as of revision 0:6ae2f7bca550:

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include <stdlib.h>
#ifdef _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include <string.h>
#include "azure_uamqp_c/sasl_plain.h"
#include "azure_uamqp_c/amqpalloc.h"

typedef struct SASL_PLAIN_INSTANCE_TAG
{
	unsigned char* init_bytes;
	size_t init_bytes_length;
} SASL_PLAIN_INSTANCE;

static const SASL_MECHANISM_INTERFACE_DESCRIPTION saslplain_interface =
{
	/* Codes_SRS_SASL_PLAIN_01_015: [**saslplain_get_interface shall return a pointer to a SASL_MECHANISM_INTERFACE_DESCRIPTION  structure that contains pointers to the functions: saslplain_create, saslplain_destroy, saslplain_get_init_bytes, saslplain_get_mechanism_name, saslplain_challenge.] */
	saslplain_create,
	saslplain_destroy,
	saslplain_get_init_bytes,
	saslplain_get_mechanism_name,
	saslplain_challenge
};

CONCRETE_SASL_MECHANISM_HANDLE saslplain_create(void* config)
{
	SASL_PLAIN_INSTANCE* result;

	if (config == NULL)
	{
		/* Codes_SRS_SASL_PLAIN_01_003: [If the config argument is NULL, then saslplain_create shall fail and return NULL.] */
		result = NULL;
	}
	else
	{
		SASL_PLAIN_CONFIG* sasl_plain_config = (SASL_PLAIN_CONFIG*)config;

		/* Codes_SRS_SASL_PLAIN_01_004: [If either the authcid or passwd member of the config structure is NULL, then saslplain_create shall fail and return NULL.] */
		if ((sasl_plain_config->authcid == NULL) ||
			(sasl_plain_config->passwd == NULL))
		{
			result = NULL;
		}
		else
		{
			size_t authzid_length = sasl_plain_config->authzid == NULL ? 0 : strlen(sasl_plain_config->authzid);
			size_t authcid_length = strlen(sasl_plain_config->authcid);
			size_t passwd_length = strlen(sasl_plain_config->passwd);

			/* Codes_SRS_SASL_PLAIN_01_020: [   authcid   = 1*SAFE ; MUST accept up to 255 octets] */
			if ((authcid_length > 255) || (authcid_length == 0) ||
				/* Codes_SRS_SASL_PLAIN_01_021: [   authzid   = 1*SAFE ; MUST accept up to 255 octets] */
				(authzid_length > 255) ||
				/* Codes_SRS_SASL_PLAIN_01_022: [   passwd    = 1*SAFE ; MUST accept up to 255 octets] */
				(passwd_length > 255) || (passwd_length == 0))
			{
				result = NULL;
			}
			else
			{
				/* Codes_SRS_SASL_PLAIN_01_001: [saslplain_create shall return on success a non-NULL handle to a new SASL plain mechanism.] */
				result = amqpalloc_malloc(sizeof(SASL_PLAIN_INSTANCE));
				/* Codes_SRS_SASL_PLAIN_01_002: [If allocating the memory needed for the saslplain instance fails then saslplain_create shall return NULL.] */
				if (result != NULL)
				{
					/* Ignore UTF8 for now */
					result->init_bytes = (unsigned char*)amqpalloc_malloc(authzid_length + authcid_length + passwd_length + 2);
					if (result->init_bytes == NULL)
					{
						/* Codes_SRS_SASL_PLAIN_01_002: [If allocating the memory needed for the saslplain instance fails then saslplain_create shall return NULL.] */
						amqpalloc_free(result);
						result = NULL;
					}
					else
					{
						/* Codes_SRS_SASL_PLAIN_01_016: [The mechanism consists of a single message, a string of [UTF-8] encoded [Unicode] characters, from the client to the server.] */
						/* Codes_SRS_SASL_PLAIN_01_017: [The client presents the authorization identity (identity to act as), followed by a NUL (U+0000) character, followed by the authentication identity (identity whose password will be used), followed by a NUL (U+0000) character, followed by the clear-text password.] */
						/* Codes_SRS_SASL_PLAIN_01_019: [   message   = [authzid] UTF8NUL authcid UTF8NUL passwd] */
						/* Codes_SRS_SASL_PLAIN_01_023: [The authorization identity (authzid), authentication identity (authcid), password (passwd), and NUL character deliminators SHALL be transferred as [UTF-8] encoded strings of [Unicode] characters.] */
						/* Codes_SRS_SASL_PLAIN_01_024: [As the NUL (U+0000) character is used as a deliminator, the NUL (U+0000) character MUST NOT appear in authzid, authcid, or passwd productions.] */

						/* Codes_SRS_SASL_PLAIN_01_018: [As with other SASL mechanisms, the client does not provide an authorization identity when it wishes the server to derive an identity from the credentials and use that as the authorization identity.] */
						if (authzid_length > 0)
						{
							(void)memcpy(result->init_bytes, sasl_plain_config->authzid, authzid_length);
						}

						result->init_bytes[authzid_length] = 0;
						(void)memcpy(result->init_bytes + authzid_length + 1, sasl_plain_config->authcid, authcid_length);
						result->init_bytes[authzid_length + authcid_length + 1] = 0;
						(void)memcpy(result->init_bytes + authzid_length + authcid_length + 2, sasl_plain_config->passwd, passwd_length);
						result->init_bytes_length = authzid_length + authcid_length + passwd_length + 2;
					}
				}
			}
		}
	}

	return result;
}

void saslplain_destroy(CONCRETE_SASL_MECHANISM_HANDLE sasl_mechanism_concrete_handle)
{
	if (sasl_mechanism_concrete_handle != NULL)
	{
		/* Codes_SRS_SASL_PLAIN_01_005: [saslplain_destroy shall free all resources associated with the SASL mechanism.] */
		SASL_PLAIN_INSTANCE* sasl_plain_instance = (SASL_PLAIN_INSTANCE*)sasl_mechanism_concrete_handle;
		if (sasl_plain_instance->init_bytes != NULL)
		{
			amqpalloc_free(sasl_plain_instance->init_bytes);
		}

		amqpalloc_free(sasl_plain_instance);
	}
}

int saslplain_get_init_bytes(CONCRETE_SASL_MECHANISM_HANDLE sasl_mechanism_concrete_handle, SASL_MECHANISM_BYTES* init_bytes)
{
	int result;

	if ((sasl_mechanism_concrete_handle == NULL) ||
		(init_bytes == NULL))
	{
		result = __LINE__;
	}
	else
	{
		SASL_PLAIN_INSTANCE* sasl_plain_instance = (SASL_PLAIN_INSTANCE*)sasl_mechanism_concrete_handle;

		init_bytes->bytes = sasl_plain_instance->init_bytes;
		init_bytes->length = sasl_plain_instance->init_bytes_length;

		/* Codes_SRS_SASL_PLAIN_01_008: [On success saslplain_get_init_bytes shall return zero.] */
		result = 0;
	}

	return result;
}

const char* saslplain_get_mechanism_name(CONCRETE_SASL_MECHANISM_HANDLE sasl_mechanism)
{
	const char* result;

	if (sasl_mechanism == NULL)
	{
		/* Codes_SRS_SASL_PLAIN_01_011: [If the argument concrete_sasl_mechanism is NULL, saslplain_get_mechanism_name shall return NULL.] */
		result = NULL;
	}
	else
	{
		/* Codes_SRS_SASL_PLAIN_01_010: [saslplain_get_mechanism_name shall validate the argument concrete_sasl_mechanism and on success it shall return a pointer to the string "PLAIN".] */
		result = "PLAIN";
	}

	return result;
}

int saslplain_challenge(CONCRETE_SASL_MECHANISM_HANDLE concrete_sasl_mechanism, const SASL_MECHANISM_BYTES* challenge_bytes, SASL_MECHANISM_BYTES* response_bytes)
{
	int result;

	(void)challenge_bytes;

	/* Codes_SRS_SASL_PLAIN_01_014: [If the concrete_sasl_mechanism or response_bytes argument is NULL then saslplain_challenge shall fail and return a non-zero value.] */
	if ((concrete_sasl_mechanism == NULL) ||
		(response_bytes == NULL))
	{
		result = __LINE__;
	}
	else
	{
		/* Codes_SRS_SASL_PLAIN_01_012: [saslplain_challenge shall set the response_bytes buffer to NULL and 0 size as the PLAIN SASL mechanism does not implement challenge/response.] */
		response_bytes->bytes = NULL;
		response_bytes->length = 0;

		/* Codes_SRS_SASL_PLAIN_01_013: [On success, saslplain_challenge shall return 0.] */
		result = 0;
	}

	return result;
}

const SASL_MECHANISM_INTERFACE_DESCRIPTION* saslplain_get_interface(void)
{
	return &saslplain_interface;
}