Exemple #1
0
/**Allocate memory for Elektra.
 *
 * Memory will be set to 0.
 *
 * @param size the requested size
 * @see elektraMalloc
 */
void * elektraCalloc (size_t size)
{
	ELEKTRA_ASSERT (size, "Size to allocate is zero (implementation defined behavior)");
	void * ret = calloc (1, size);
	ELEKTRA_ASSERT (ret, "Memory allocation failed with size %zu", size);
	return ret;
}
Exemple #2
0
/**
 * @internal
 *
 * @brief Unescapes (a part of) a key name.
 *
 * As described in Syntax for Key Names, slashes are
 * prefixed with a \\ (or uneven number thereof). This method removes all \\ that are such
 * escape characters.
 *
 * The new string will be written to dest.
 * May only need half the storage than the source string.
 * It is not safe to use the same string for source and dest.
 *
 * @param source the source to read from
 * @param size the number of bytes to process from source
 * @param dest the destination to write to
 *
 * @return the destination pointer how far it was written to
 */
char * elektraUnescapeKeyNamePart (const char * source, size_t size, char * dest)
{
	const char * sp = source;
	char * dp = dest;
	size_t count = 0;

	ELEKTRA_ASSERT (sp != NULL && dp != NULL, "Got null pointer sp: %p dp: %p", (void *) sp, (void *) dp);

	while (size)
	{
		if (*sp == '\\')
		{
			++count;
		}
		else if (*sp == '/')
		{
			// we escape a part, so there had to be a backslash
			ELEKTRA_ASSERT (count > 0, "no backslash found, count is %zu", count);
			ELEKTRA_ASSERT ((count % 2) == 1, "counted uneven number of backslashes: %zu", count);

			count /= 2;
			while (count)
			{
				*dp = '\\';
				++dp;
				--count;
			}

			*dp = *sp;
			++dp;
		}
		else
		{
			// output delayed backslashes
			while (count)
			{
				*dp = '\\';
				++dp;
				--count;
			}

			*dp = *sp;
			++dp;
		}
		++sp;
		--size;
	}

	ELEKTRA_ASSERT ((count % 2) == 0, "uneven number of backslashes: %zu", count);
	count /= 2;
	while (count)
	{
		*dp = '\\';
		++dp;
		--count;
	}
	return dp;
}
Exemple #3
0
/**Copy string into new allocated memory.
 *
 * You need to free the memory yourself.
 *
 * @note that size is determined at runtime.
 *       So if you have a size information, don't use
 *       that function.
 *
 * @param s the null-terminated string to duplicate
 *
 * @ingroup internal
 * @return 0 if out of memory, a pointer otherwise
 * @pre s must be a c-string.
 * @see elektraFree
 * @see elektraStrLen
 * @see elektraStrNDup
 */
char * elektraStrDup (const char * s)
{
	void * tmp = 0;
	size_t l = 0;
	ELEKTRA_ASSERT (s, "Tried to duplicate null pointer");

	l = elektraStrLen (s);
	ELEKTRA_ASSERT (l, "Size of string to duplicate is zero");
	tmp = elektraMalloc (l);
	if (tmp) memcpy (tmp, s, l);

	return tmp;
}
Exemple #4
0
/**
 * @internal
 *
 * @brief Write number backslashes to dest
 *
 * @param dest where to write to, will be updated to position after
 *        the written backslashes
 * @param number of backslashes to write
 */
static void elektraWriteBackslashes (char ** dest, size_t number)
{
	ELEKTRA_ASSERT (dest, "Got null pointer");
	ELEKTRA_ASSERT (*dest, "Got null pointer (*dest)");

	char * dp = *dest;
	while (number)
	{
		*dp = '\\';
		++dp;
		--number;
	}
	*dest = dp;
}
/**
 * @brief derive the cryptographic key and IV for a given (Elektra) Key k
 * @param config KeySet holding the plugin/backend configuration
 * @param errorKey holds an error description in case of failure
 * @param masterKey holds the decrypted master password from the plugin configuration
 * @param k the (Elektra)-Key to be encrypted
 * @param cKey (Elektra)-Key holding the cryptographic material
 * @param cIv (Elektra)-Key holding the initialization vector
 * @retval -1 on failure. errorKey holds the error description.
 * @retval 1 on success
 */
static int getKeyIvForDecryption (KeySet * config, Key * errorKey, Key * masterKey, Key * k, Key * cKey, Key * cIv)
{
	gcry_error_t gcry_err;
	kdb_octet_t keyBuffer[KEY_BUFFER_SIZE];
	kdb_octet_t * saltBuffer = NULL;
	kdb_unsigned_long_t saltBufferLen = 0;

	ELEKTRA_ASSERT (masterKey != NULL, "Parameter `masterKey` must not be NULL");

	// get the salt
	if (CRYPTO_PLUGIN_FUNCTION (getSaltFromPayload) (errorKey, k, &saltBuffer, &saltBufferLen) != 1)
	{
		return -1; // error set by CRYPTO_PLUGIN_FUNCTION(getSaltFromPayload)()
	}

	// get the iteration count
	const kdb_unsigned_long_t iterations = CRYPTO_PLUGIN_FUNCTION (getIterationCount) (errorKey, config);

	// derive the cryptographic key and the IV
	if ((gcry_err = gcry_kdf_derive (keyValue (masterKey), keyGetValueSize (masterKey), GCRY_KDF_PBKDF2, GCRY_MD_SHA512, saltBuffer,
					 saltBufferLen, iterations, KEY_BUFFER_SIZE, keyBuffer)))
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_INTERNAL_ERROR, errorKey,
				    "Failed to restore the cryptographic key for decryption because: %s", gcry_strerror (gcry_err));
		return -1;
	}

	keySetBinary (cKey, keyBuffer, ELEKTRA_CRYPTO_GCRY_KEYSIZE);
	keySetBinary (cIv, keyBuffer + ELEKTRA_CRYPTO_GCRY_KEYSIZE, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE);
	return 1;
}
/**
 * @brief derive the cryptographic key and IV for a given (Elektra) Key k
 * @param config KeySet holding the plugin/backend configuration
 * @param errorKey holds an error description in case of failure
 * @param masterKey holds the decrypted master password from the plugin configuration
 * @param k the (Elektra)-Key to be encrypted
 * @param cKey (Elektra)-Key holding the cryptographic material
 * @param cIv (Elektra)-Key holding the initialization vector
 * @retval -1 on failure. errorKey holds the error description.
 * @retval 1 on success
 */
static int getKeyIvForDecryption (KeySet * config, Key * errorKey, Key * masterKey, Key * k, Key * cKey, Key * cIv)
{
	kdb_octet_t keyBuffer[KEY_BUFFER_SIZE];
	kdb_octet_t * saltBuffer = NULL;
	kdb_unsigned_long_t saltBufferLen = 0;

	ELEKTRA_ASSERT (masterKey != NULL, "Parameter `masterKey` must not be NULL");

	// get the salt
	if (CRYPTO_PLUGIN_FUNCTION (getSaltFromPayload) (errorKey, k, &saltBuffer, &saltBufferLen) != 1)
	{
		return -1; // error set by CRYPTO_PLUGIN_FUNCTION(getSaltFromPayload)()
	}

	// get the iteration count
	const kdb_unsigned_long_t iterations = CRYPTO_PLUGIN_FUNCTION (getIterationCount) (errorKey, config);

	// derive the cryptographic key and the IV
	pthread_mutex_lock (&mutex_ssl);
	if (!PKCS5_PBKDF2_HMAC_SHA1 (keyValue (masterKey), keyGetValueSize (masterKey), saltBuffer, saltBufferLen, iterations,
				     KEY_BUFFER_SIZE, keyBuffer))
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_INTERNAL_ERROR, errorKey,
				    "Failed to restore the cryptographic key for decryption. Libcrypto returned the error code: %lu",
				    ERR_get_error ());
		pthread_mutex_unlock (&mutex_ssl);
		return -1;
	}
	pthread_mutex_unlock (&mutex_ssl);

	keySetBinary (cKey, keyBuffer, ELEKTRA_CRYPTO_SSL_KEYSIZE);
	keySetBinary (cIv, keyBuffer + ELEKTRA_CRYPTO_SSL_KEYSIZE, ELEKTRA_CRYPTO_SSL_BLOCKSIZE);
	return 1;
}
Exemple #7
0
static resolverHandle * elektraGetResolverHandle (Plugin * handle, Key * parentKey)
{
	resolverHandles * pks = elektraPluginGetData (handle);
	ELEKTRA_ASSERT (pks != NULL, "Unable to retrieve plugin data for handle %p with parentKey %s", (void *) handle,
			keyName (parentKey));

	switch (keyGetNamespace (parentKey))
	{
	case KEY_NS_SPEC:
		return &pks->spec;
	case KEY_NS_DIR:
		return &pks->dir;
	case KEY_NS_USER:
		return &pks->user;
	case KEY_NS_SYSTEM:
		return &pks->system;
	case KEY_NS_PROC:
	case KEY_NS_EMPTY:
	case KEY_NS_NONE:
	case KEY_NS_META:
	case KEY_NS_CASCADING:
		return 0;
	}

	return 0;
}
Exemple #8
0
/**
 * @internal
 *
 * @brief Unescapes a key name.
 *
 * Writes a null terminated sequence of key name parts to dest.
 *
 * May only need half the storage than the source string.
 * It is not safe to use the same string for source and dest.
 **/
size_t elektraUnescapeKeyName (const char * source, char * dest)
{
	const char * sp = source;
	char * dp = dest;
	size_t size = 0;

	ELEKTRA_ASSERT (sp != NULL && dp != NULL, "Got null pointer sp: %p dp: %p", (void *) sp, (void *) dp);

	if (*sp == '/')
	{
		// handling for cascading names
		*dp = 0;
		++dp;
	}
	while (*(sp = keyNameGetOneLevel (sp + size, &size)))
	{
		if (!elektraUnescapeKeyNamePartBegin (sp, size, &dp))
		{
			dp = elektraUnescapeKeyNamePart (sp, size, dp);
		}
		*dp = 0;
		++dp;
	}
	return dp - dest;
}
Exemple #9
0
/**
 * Calculates the length in bytes of a string.
 *
 * This function differs from strlen() because it is Unicode and multibyte
 * chars safe. While strlen() counts characters and ignores the final NULL,
 * elektraStrLen() count bytes including the ending NULL.
 *
 * It must not be used to search for / in the name, because it does not
 * consider escaping. Instead use the unescaped name.
 *
 * @see keyUnescapedName()
 *
 * @ingroup internal
 * @param s the string to get the length from
 * @return number of bytes used by the string, including the final NULL.
 * @ingroup internal
 */
size_t elektraStrLen (const char * s)
{
	ELEKTRA_ASSERT (s, "Got null pointer");

	char * found = strchr (s, 0);
	if (found) return found - s + 1;
	return 0;
}
Exemple #10
0
/**
 * @brief Builds together a format string by the plugin's configuration
 *
 * @param handle to plugin
 * @param first format string for key
 * @param second format string for value
 *
 * @return newly allocated format (to be freed with elektraFree);
 */
static char * getFormat (Plugin * handle, const char * first, const char * second)
{
	char * format;
	Key * key = ksLookupByName (elektraPluginGetConfig (handle), "/format", 0);
	if (!key)
	{
		format = elektraStrDup ("%s = %s\n");
	}
	else
	{
		const size_t maxFactor = 2; // at maximum every char is a %, %% -> %%%%
		const size_t newLineAtEnd = 2;
		const size_t userFormatSize = keyGetValueSize (key);
		format = elektraMalloc (userFormatSize * maxFactor + newLineAtEnd);

		const char * userFormat = keyString (key);
		int gotPercent = 0;
		size_t j = 0;
		for (size_t i = 0; i < userFormatSize; ++i, ++j)
		{
			const char c = userFormat[i];
			if (gotPercent)
			{
				if (c == '%')
				{
					// escaped %% -> %%%%
					format[j++] = '%';
					format[j++] = '%';
					format[j] = '%';
				}
				else
				{
					// single % -> %s
					format[j++] = 's';
					format[j] = c;
				}
				gotPercent = 0;
			}
			else if (c == '%')
			{
				format[j] = c;
				gotPercent = 1;
			}
			else
			{
				format[j] = c;
			}
		}
		--j; // discard null byte that is already there
		ELEKTRA_ASSERT (format[j] == '\0', "should be null byte at end of string but was %c", format[j]);
		format[j++] = '\n';
		format[j] = '\0';
	}

	char * ret = elektraFormat (format, first, second);
	elektraFree (format);
	return ret;
}
Exemple #11
0
/**
 * Validates whether the supplied keyname is valid.
 *
 * The function looks for tangling escape characters in the end
 * and for a minimum length.
 *
 * Does not check for valid namespaces
 *
 * @pre size must be at least 2
 *
 * @param name the key name that is to be checked
 * @param size a elektraStrLen of the key name
 * @retval true if the supplied keyname part is valid
 * @retval false if its invalid
 */
int elektraValidateKeyName (const char * name, size_t size)
{
	ELEKTRA_ASSERT (name, "Got null pointer");
	ELEKTRA_ASSERT (size >= 2, "size too small %zu", size);

	size_t escapeCount = 0;

	size -= 2; // forward null character to last character

	// now do backwards iteration
	while (size && name[size] == '\\')
	{
		++escapeCount;
		--size;
	}

	return (escapeCount % 2) == 0; // only allow equal number of escapes in the end
}
Exemple #12
0
/**
 * @brief Does string formatting in fresh allocated memory
 *
 * @param format as in printf()
 * @param ... as in printf()
 *
 * @return new allocated memory (free with elektraFree)
 */
char * elektraFormat (const char * format, ...)
{
	ELEKTRA_ASSERT (format, "Got null pointer");

	va_list va;
	va_start (va, format);
	char * ret = elektraVFormat (format, va);
	va_end (va);
	return ret;
}
Exemple #13
0
/**Copy buffer into new allocated memory.
 *
 * You need to free the memory yourself.
 *
 * This function also works with \\0 characters
 * in the buffer. The length is taken as given,
 * it must be correct.
 *
 * @return 0 if out of memory, a pointer otherwise
 * @param s must be a allocated buffer
 * @param l the length of s
 * @ingroup internal
 */
char * elektraStrNDup (const char * s, size_t l)
{
	void * tmp = 0;
	ELEKTRA_ASSERT (l, "Size for string duplicate is zero");

	tmp = elektraMalloc (l);
	if (tmp) memcpy (tmp, s, l);

	return tmp;
}
Exemple #14
0
/**Reallocate Storage in a save way.
 *
 *@code
if (elektraRealloc ((void **) & buffer, new_length) < 0) {
	// here comes the failure handler
	// you can still use the old buffer
#if DEBUG
	fprintf (stderr, "Reallocation error\n");
#endif
	elektraFree (buffer);
	buffer = 0;
	// return with error
}
 *@endcode
 *
 * @param buffer is a pointer to a elektraMalloc
 * @param size is the new size for the memory
 * @retval -1 on failure
 * @retval 0 on success
 * @ingroup internal
 */
int elektraRealloc (void ** buffer, size_t size)
{
	ELEKTRA_ASSERT (size, "Size to allocate is zero (implementation defined behavior)");
	void * ptr;
	void * svr = *buffer;

	ptr = realloc (*buffer, size);
	ELEKTRA_ASSERT (ptr, "Memory (re)allocation failed with size %zu", size);
	if (ptr == NULL)
	{
		*buffer = svr; /* restore old buffer*/
		return -1;
	}
	else
	{
		*buffer = ptr;
		return 0;
	}
}
Exemple #15
0
/**
 * @brief Filter out keys not in the correct keyset
 *
 * @param split the split where to do it
 * @param i for which split
 * @param warningKey the key
 * @param handle where to do backend lookups
 *
 * @retval -1 on error (no backend, wrong namespace)
 * @retval 0 otherwise
 */
static int elektraSplitPostprocess (Split * split, int i, Key * warningKey, KDB * handle)
{
	Key * cur = 0;
	Backend * curHandle = 0;
	ksRewind (split->keysets[i]);
	while ((cur = ksNext (split->keysets[i])) != 0)
	{
		curHandle = elektraMountGetBackend (handle, cur);
		if (!curHandle) return -1;

		keyClearSync (cur);

		if (curHandle != split->handles[i])
		{
			elektraDropCurrentKey (split->keysets[i], warningKey, curHandle, "it is hidden by other mountpoint");
		}
		else
			switch (keyGetNamespace (cur))
			{
			case KEY_NS_SPEC:
				if (!keyIsSpec (split->parents[i]))
					elektraDropCurrentKey (split->keysets[i], warningKey, curHandle, "it is not spec");
				break;
			case KEY_NS_DIR:
				if (!keyIsDir (split->parents[i]))
					elektraDropCurrentKey (split->keysets[i], warningKey, curHandle, "it is not dir");
				break;
			case KEY_NS_USER:
				if (!keyIsUser (split->parents[i]))
					elektraDropCurrentKey (split->keysets[i], warningKey, curHandle, "it is not user");
				break;
			case KEY_NS_SYSTEM:
				if (!keyIsSystem (split->parents[i]))
					elektraDropCurrentKey (split->keysets[i], warningKey, curHandle, "it is not system");
				break;
			case KEY_NS_PROC:
				elektraDropCurrentKey (split->keysets[i], warningKey, curHandle, "it has a proc key name");
				break;
			case KEY_NS_EMPTY:
				elektraDropCurrentKey (split->keysets[i], warningKey, curHandle, "it has an empty name");
				break;
			case KEY_NS_META:
				elektraDropCurrentKey (split->keysets[i], warningKey, curHandle, "it has a meta name");
				break;
			case KEY_NS_CASCADING:
				elektraDropCurrentKey (split->keysets[i], warningKey, curHandle, "it has a cascading name");
				break;
			case KEY_NS_NONE:
				ELEKTRA_ASSERT (0 && "wrong key namespace, should not be none");
				return -1;
			}
	}
	return 0;
}
Exemple #16
0
/**
 * @brief Does string formatting in fresh allocated memory
 *
 * @param format as in vprintf()
 * @param arg_list as in vprintf()
 *
 * @return new allocated memory (free with elektraFree)
 */
char * elektraVFormat (const char * format, va_list arg_list)
{
	ELEKTRA_ASSERT (format, "Got null pointer");

	static int const default_size = 512;
	char * buffer = elektraMalloc (default_size);
	if (!buffer) return 0;

	va_list arg_list_adj;
	va_copy (arg_list_adj, arg_list);

	int const calculated_length = vsnprintf (buffer, default_size, format, arg_list);

	if (calculated_length == -1)
	{
		va_end (arg_list_adj);
		elektraFree (buffer);
		// before Glibc 2.0.6, always -1 is returned
		// we won't do Glibc job, please upgrade
		return 0;
	}

	if (calculated_length < default_size)
	{
		va_end (arg_list_adj);
		// content was written successfully into
		// default sized buffer
		return buffer;
	}

	// String is longer than default_size.
	// Allocate an intermediate buffer
	// according to the calculated length from our last try
	size_t const adjusted_buffer_size = calculated_length + 1;
	elektraRealloc ((void **) &buffer, adjusted_buffer_size);
	if (!buffer)
	{
		va_end (arg_list_adj);
		return 0;
	}

	int const ret = vsnprintf (buffer, adjusted_buffer_size, format, arg_list_adj);

	va_end (arg_list_adj);

	if (ret == -1)
	{
		elektraFree (buffer);
		return 0;
	}
	return buffer;
}
/**
 * @see kdbnotificationinternal.h ::ElektraNotificationPluginRegisterCallback
 */
int elektraInternalnotificationRegisterCallback (Plugin * handle, Key * key, ElektraNotificationChangeCallback callback, void * context)
{
	PluginState * pluginState = elektraPluginGetData (handle);
	ELEKTRA_ASSERT (pluginState != NULL, "plugin state was not initialized properly");

	KeyRegistration * registeredKey = elektraInternalnotificationAddNewRegistration (pluginState, key, callback, context, 0);
	if (registeredKey == NULL)
	{
		return 0;
	}

	return 1;
}
Exemple #18
0
/**
 * @internal
 *
 * @brief Escapes character in the part of a key name.
 *
 * As described in Syntax for Key Names, special characters will be
 * prefixed with a \\. No existing escaping is assumed. That means
 * that even sequences that look like escapings will be escaped again.
 * For example, \\/ will be escaped (or quoted) to \\\\\\/.
 *
 * The string will be written to dest.
 *
 * @note May need twice the storage than the source string.
 *       Do not use the source string as destination string.
 *
 * @param source the source pointer where escaping should start
 * @param dest the destination to write to (twice the size as sp)
 *
 * @return pointer to destination
 */
char * elektraEscapeKeyNamePart (const char * source, char * dest)
{
	if (elektraEscapeKeyNamePartBegin (source, dest))
	{
		return dest;
	}

	size_t count = 0;

	const char * sp = source;
	char * dp = dest;

	ELEKTRA_ASSERT (sp != NULL && dp != NULL, "Got null pointer sp: %p dp: %p", (void *) sp, (void *) dp);

	while (*sp)
	{
		if (*sp == '\\')
		{
			++count;
		}
		else if (*sp == '/')
		{
			// escape every slash
			*dp = '\\';
			++dp;
			// and print escaped slashes
			while (count)
			{
				*dp = '\\';
				++dp;
				--count;
			}
		}
		else
		{
			count = 0;
		}
		*dp = *sp;
		++dp;
		++sp;
	}
	// print other escaped backslashes at end of part
	while (count)
	{
		*dp = '\\';
		++dp;
		--count;
	}
	*dp = 0;
	return dest;
}
Exemple #19
0
/**
 * @brief Remove one part of split.
 *
 * @param split the split object to work with
 * @param where the position to cut away
 *
 * @pre where must be within the size of the split
 * @post split will be removed
 *
 * @ingroup split
 */
void elektraSplitRemove (Split * split, size_t where)
{
	ELEKTRA_ASSERT (where < split->size && "cannot remove behind size");
	ksDel (split->keysets[where]);
	keyDel (split->parents[where]);
	--split->size; // reduce size
	for (size_t i = where; i < split->size; ++i)
	{
		split->keysets[i] = split->keysets[i + 1];
		split->handles[i] = split->handles[i + 1];
		split->parents[i] = split->parents[i + 1];
		split->syncbits[i] = split->syncbits[i + 1];
	}
}
Exemple #20
0
ssize_t elektraKeySetName(Key *key, const char *newName,
		option_t options)
{
	if (!key) return -1;
	if (test_bit(key->flags,  KEY_FLAG_RO_NAME)) return -1;

	elektraRemoveKeyName(key);
	if (!(options & KEY_META_NAME)) keySetOwner (key, NULL);

	switch (keyGetNameNamespace(newName))
	{
	case KEY_NS_NONE: ELEKTRA_ASSERT(0);
	case KEY_NS_EMPTY:
		elektraFinalizeEmptyName(key);
		return 0; // as documented
	case KEY_NS_CASCADING: key->keyUSize=1;key->keySize=sizeof("/"); break;
	case KEY_NS_SPEC: key->keyUSize=key->keySize=sizeof("spec"); break;
	case KEY_NS_PROC: key->keyUSize=key->keySize=sizeof("proc"); break;
	case KEY_NS_DIR: key->keyUSize=key->keySize=sizeof("dir"); break;
	case KEY_NS_USER: elektraHandleUserName(key, newName); break;
	case KEY_NS_SYSTEM: key->keyUSize=key->keySize=sizeof("system"); break;
	case KEY_NS_META:
		if (!(options & KEY_META_NAME)) return -1;
		keyNameGetOneLevel(newName,&key->keySize);
		key->keyUSize = ++ key->keySize; // for null
		break;
	} // Note that we abused keyUSize for cascading and user:owner

	const size_t length = elektraStrLen(newName);
	key->key=elektraMalloc(key->keySize*2);
	memcpy(key->key, newName, key->keySize);
	if (length == key->keyUSize || length == key->keySize)
	{	// use || because full length is keyUSize in user, but keySize for /
		// newName consisted of root only
		elektraFinalizeName(key);
		return key->keyUSize;
	}

	if (elektraOnlySlashes(newName+key->keyUSize-1))
	{
		elektraFinalizeName(key);
		return key->keySize;
	}

	key->key[key->keySize-1] = '\0';
	const ssize_t ret = keyAddName(key, newName+key->keyUSize);
	if (ret == -1) elektraRemoveKeyName(key);
	else return key->keySize;
	return ret;
}
Exemple #21
0
/**
 * @brief Compare two memory regions but make cmp chars uppercase before
 * comparison.
 *
 * @param s1 The first string to be compared
 * @param s2 The second string to be compared
 * @param size to be compared
 *
 * @ingroup internal
 * @return a negative number if s1 is less than s2
 * @retval 0 if s1 matches s2
 * @return a positive number if s1 is greater than s2
 */
int elektraMemCaseCmp (const char * s1, const char * s2, size_t size)
{
	size_t i;
	ELEKTRA_ASSERT (s1 != NULL && s2 != NULL, "Got null pointer s1: %p s2: %p", (void *) s1, (void *) s2);
	for (i = 0; i < size; i++)
	{
		const unsigned char cmp1 = s1[i];
		const unsigned char cmp2 = s2[i];
		const int CMP1 = toupper (cmp1);
		const int CMP2 = toupper (cmp2);
		const int diff = CMP1 - CMP2;
		if (diff) return diff;
	}
	return 0;
}
/**
 * @brief derive the cryptographic key and IV for a given (Elektra) Key k
 * @param config KeySet holding the plugin/backend configuration
 * @param errorKey holds an error description in case of failure
 * @param masterKey holds the decrypted master password from the plugin configuration
 * @param k the (Elektra)-Key to be encrypted
 * @param cKey (Elektra)-Key holding the cryptographic material
 * @param cIv (Elektra)-Key holding the initialization vector
 * @retval -1 on failure. errorKey holds the error description.
 * @retval 1 on success
 */
static int getKeyIvForEncryption (KeySet * config, Key * errorKey, Key * masterKey, Key * k, Key * cKey, Key * cIv)
{
	kdb_octet_t salt[ELEKTRA_CRYPTO_DEFAULT_SALT_LEN] = { 0 };
	kdb_octet_t keyBuffer[KEY_BUFFER_SIZE] = { 0 };
	char * saltHexString = NULL;

	ELEKTRA_ASSERT (masterKey != NULL, "Parameter `masterKey` must not be NULL");

	// generate the salt
	pthread_mutex_lock (&mutex_ssl);
	if (!RAND_bytes (salt, ELEKTRA_CRYPTO_DEFAULT_SALT_LEN - 1))
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_INTERNAL_ERROR, errorKey, "failed to generate random salt with error code %lu",
				    ERR_get_error ());
		pthread_mutex_unlock (&mutex_ssl);
		return -1;
	}
	pthread_mutex_unlock (&mutex_ssl);
	saltHexString = ELEKTRA_PLUGIN_FUNCTION (ELEKTRA_PLUGIN_NAME_C, base64Encode) (salt, sizeof (salt));
	if (!saltHexString)
	{
		ELEKTRA_SET_ERROR (87, errorKey, "Memory allocation failed");
		return -1;
	}
	keySetMeta (k, ELEKTRA_CRYPTO_META_SALT, saltHexString);
	elektraFree (saltHexString);

	// read iteration count
	const kdb_unsigned_long_t iterations = CRYPTO_PLUGIN_FUNCTION (getIterationCount) (errorKey, config);

	// generate/derive the cryptographic key and the IV
	pthread_mutex_lock (&mutex_ssl);
	if (!PKCS5_PBKDF2_HMAC_SHA1 (keyValue (masterKey), keyGetValueSize (masterKey), salt, sizeof (salt), iterations, KEY_BUFFER_SIZE,
				     keyBuffer))
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_INTERNAL_ERROR, errorKey,
				    "Failed to create a cryptographic key for encryption. Libcrypto returned error code: %lu",
				    ERR_get_error ());
		pthread_mutex_unlock (&mutex_ssl);
		return -1;
	}
	pthread_mutex_unlock (&mutex_ssl);

	keySetBinary (cKey, keyBuffer, ELEKTRA_CRYPTO_SSL_KEYSIZE);
	keySetBinary (cIv, keyBuffer + ELEKTRA_CRYPTO_SSL_KEYSIZE, ELEKTRA_CRYPTO_SSL_BLOCKSIZE);
	return 1;
}
Exemple #23
0
/**
 * Copies the key array2 into where array1 points.
 * It copies size elements.
 *
 * Overlapping is prohibited, use elektraMemmove() instead.
 *
 * @param array1 the destination
 * @param array2 the source
 * @param size how many pointer to Keys to copy
 * @retval -1 on null pointers
 * @retval 0 if nothing was done
 * @return size how many keys were copied
 */
ssize_t elektraMemcpy (Key ** array1, Key ** array2, size_t size)
{
	if (!array1) return -1;
	if (!array2) return -1;
	if (size > SSIZE_MAX) return -1;
	if (size == 0) return 0;
#if DEBUG
	char * a = (char *) array1;
	char * b = (char *) array2;
	for (size_t i = 0; i < size; i++)
	{
		ELEKTRA_ASSERT (a + i != b && b + i != a, "memcpy overlap: %p and %p with size %zu", (void *) a, (void *) b, size);
	}
#endif
	memcpy (array1, array2, size * sizeof (Key *));
	return size;
}
Exemple #24
0
/**
 * @internal
 *
 * Escapes (a part of) a key name.
 */
int elektraEscapeKeyNamePartBegin (const char * source, char * dest)
{
	const char * sp = source;
	char * dp = dest;

	ELEKTRA_ASSERT (sp != NULL && dp != NULL, "Got null pointer sp: %p dp: %p", (void *) sp, (void *) dp);

	if (!strcmp ("", sp))
	{
		strcpy (dp, "%");
		return 1;
	}

	size_t skippedBackslashes = 0;
	// skip all backslashes at start of a name
	while (*sp == '\\')
	{
		++sp;
		++skippedBackslashes;
	}

	if (!strcmp ("%", sp))
	{
		elektraWriteBackslashes (&dp, skippedBackslashes);
		strcpy (dp, "\\%");
		return 1;
	}

	if (!strcmp (".", sp))
	{
		elektraWriteBackslashes (&dp, skippedBackslashes);
		strcpy (dp, "\\.");
		return 1;
	}

	if (!strcmp ("..", sp))
	{
		elektraWriteBackslashes (&dp, skippedBackslashes);
		strcpy (dp, "\\..");
		return 1;
	}

	return 0;
}
Exemple #25
0
/**
 * @internal
 *
 * @brief Check if an update is needed at all
 *
 * @retval -1 an error occurred
 * @retval 0 no update needed
 * @retval number of plugins which need update
 */
static int elektraGetCheckUpdateNeeded (Split * split, Key * parentKey)
{
	int updateNeededOccurred = 0;
	for (size_t i = 0; i < split->size; i++)
	{
		int ret = -1;
		Backend * backend = split->handles[i];
		clear_bit (split->syncbits[i], 1);

		if (backend->getplugins[RESOLVER_PLUGIN] && backend->getplugins[RESOLVER_PLUGIN]->kdbGet)
		{
			ksRewind (split->keysets[i]);
			keySetName (parentKey, keyName (split->parents[i]));
			keySetString (parentKey, "");
			ret = backend->getplugins[RESOLVER_PLUGIN]->kdbGet (backend->getplugins[RESOLVER_PLUGIN], split->keysets[i],
									    parentKey);
			// store resolved filename
			keySetString (split->parents[i], keyString (parentKey));
			// no keys in that backend
			backendUpdateSize (backend, split->parents[i], 0);
		}
		// TODO: set error in else case!

		switch (ret)
		{
		case 1:
			// Seems like we need to sync that
			set_bit (split->syncbits[i], SPLIT_FLAG_SYNC);
			++updateNeededOccurred;
			break;
		case 0:
			// Nothing to do here
			break;
		default:
			ELEKTRA_ASSERT (0, "resolver did not return 1 0 -1, but %d", ret);
		case -1:
			// Ohh, an error occurred, lets stop the
			// process.
			return -1;
		}
	}
	return updateNeededOccurred;
}
Exemple #26
0
/**
 * @brief Allows one to Export Methods for a Plugin.
 *
 * This function must be called within ELEKTRA_PLUGIN_EXPORT.
 * It define the plugin's methods that will be exported.
 *
 * All KDB methods implemented by the plugin basically could
 * have random names (convention is elektraName*), except
 * ELEKTRA_PLUGIN_EXPORT.
 *
 * This is the single symbol that will be looked up
 * when loading the plugin, and the first method of the backend
 * implementation that will be called.
 *
 * You need to use a macro so that both dynamic and static loading
 * of the plugin works. For example for the doc plugin:
 * @snippet doc.c export
 *
 * The first parameter is the name of the plugin.
 * Then every plugin should have:
 * @c ELEKTRA_PLUGIN_OPEN,
 * @c ELEKTRA_PLUGIN_CLOSE,
 * @c ELEKTRA_PLUGIN_GET,
 * @c ELEKTRA_PLUGIN_SET and optionally
 * @c ELEKTRA_PLUGIN_ERROR.
 *
 * The list is terminated with
 * @c ELEKTRA_PLUGIN_END.
 *
 * You must use static "char arrays" in a read only segment.
 * Don't allocate storage, it won't be freed.
 *
 * @param pluginName the name of this plugin
 * @return an object that contains all plugin information needed by
 * 	libelektra.so
 * @ingroup plugin
 */
Plugin * elektraPluginExport (const char * pluginName, ...)
{
	va_list va;
	Plugin * returned;
	plugin_t method = 0;

	if (pluginName == 0) return 0;

	returned = elektraCalloc (sizeof (struct _Plugin));

	/* Start processing parameters */
	va_start (va, pluginName);
	returned->name = pluginName;

	while ((method = va_arg (va, plugin_t)))
	{
		switch (method)
		{
		case ELEKTRA_PLUGIN_OPEN:
			returned->kdbOpen = va_arg (va, kdbOpenPtr);
			break;
		case ELEKTRA_PLUGIN_CLOSE:
			returned->kdbClose = va_arg (va, kdbClosePtr);
			break;
		case ELEKTRA_PLUGIN_GET:
			returned->kdbGet = va_arg (va, kdbGetPtr);
			break;
		case ELEKTRA_PLUGIN_SET:
			returned->kdbSet = va_arg (va, kdbSetPtr);
			break;
		case ELEKTRA_PLUGIN_ERROR:
			returned->kdbError = va_arg (va, kdbErrorPtr);
			break;
		default:
			ELEKTRA_ASSERT (0, "plugin passed something unexpected");
		// fallthrough, will end here
		case ELEKTRA_PLUGIN_END:
			va_end (va);
			return returned;
		}
	}
	return returned;
}
/**
 * @brief derive the cryptographic key and IV for a given (Elektra) Key k
 * @param config KeySet holding the plugin/backend configuration
 * @param errorKey holds an error description in case of failure
 * @param masterKey holds the decrypted master password from the plugin configuration
 * @param k the (Elektra)-Key to be encrypted
 * @param cKey (Elektra)-Key holding the cryptographic material
 * @param cIv (Elektra)-Key holding the initialization vector
 * @retval -1 on failure. errorKey holds the error description.
 * @retval 1 on success
 */
static int getKeyIvForEncryption (KeySet * config, Key * errorKey, Key * masterKey, Key * k, Key * cKey, Key * cIv)
{
	gcry_error_t gcry_err;
	kdb_octet_t salt[ELEKTRA_CRYPTO_DEFAULT_SALT_LEN];
	kdb_octet_t keyBuffer[KEY_BUFFER_SIZE];
	char * saltHexString = NULL;

	ELEKTRA_ASSERT (masterKey != NULL, "Parameter `masterKey` must not be NULL");

	// generate the salt
	gcry_create_nonce (salt, sizeof (salt));
	const int encodingResult = CRYPTO_PLUGIN_FUNCTION (base64Encode) (errorKey, salt, sizeof (salt), &saltHexString);
	if (encodingResult < 0)
	{
		// error in libinvoke - errorKey has been set by base64Encode
		return -1;
	}
	if (!saltHexString)
	{
		ELEKTRA_SET_ERROR (87, errorKey, "Memory allocation failed");
		return -1;
	}
	keySetMeta (k, ELEKTRA_CRYPTO_META_SALT, saltHexString);
	elektraFree (saltHexString);

	// read iteration count
	const kdb_unsigned_long_t iterations = CRYPTO_PLUGIN_FUNCTION (getIterationCount) (errorKey, config);

	// generate/derive the cryptographic key and the IV
	if ((gcry_err = gcry_kdf_derive (keyValue (masterKey), keyGetValueSize (masterKey), GCRY_KDF_PBKDF2, GCRY_MD_SHA512, salt,
					 sizeof (salt), iterations, KEY_BUFFER_SIZE, keyBuffer)))
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_INTERNAL_ERROR, errorKey,
				    "Failed to create a cryptographic key for encryption because: %s", gcry_strerror (gcry_err));
		return -1;
	}

	keySetBinary (cKey, keyBuffer, ELEKTRA_CRYPTO_GCRY_KEYSIZE);
	keySetBinary (cIv, keyBuffer + ELEKTRA_CRYPTO_GCRY_KEYSIZE, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE);
	return 1;
}
Exemple #28
0
static void elektraHandleUserName (Key * key, const char * newName)
{
	const size_t userLength = sizeof ("user");
	key->keyUSize = key->keySize = userLength;

	const char delim = newName[userLength - 1];
	// no owner, we are finished
	if (delim == '/' || delim == '\0') return;
	ELEKTRA_ASSERT (delim == ':');

	// handle owner (compatibility, to be removed)
	keyNameGetOneLevel (newName, &key->keyUSize);
	const size_t ownerLength = key->keyUSize - userLength;
	++key->keyUSize;
	char * owner = elektraMalloc (ownerLength + 1);
	if (!owner) return; // out of memory, ok for owner
	strncpy (owner, newName + userLength, ownerLength);
	owner[ownerLength] = 0;
	keySetOwner (key, owner);
	elektraFree (owner);
}
Exemple #29
0
static resolverHandle * elektraGetResolverHandle (Plugin * handle, Key * parentKey)
{
	resolverHandles * pks = elektraPluginGetData (handle);
	switch (keyGetNamespace (parentKey))
	{
	case KEY_NS_SPEC:
		return &pks->spec;
	case KEY_NS_DIR:
		return &pks->dir;
	case KEY_NS_USER:
		return &pks->user;
	case KEY_NS_SYSTEM:
		return &pks->system;
	case KEY_NS_PROC:
	case KEY_NS_EMPTY:
	case KEY_NS_NONE:
	case KEY_NS_META:
	case KEY_NS_CASCADING:
		break;
	}
	ELEKTRA_ASSERT (0, "namespace %d not valid for resolving", keyGetNamespace (parentKey));
	return 0;
}
/**
 * Updates all KeyRegistrations according to data from the given KeySet
 * @internal
 *
 * @param plugin    internal plugin handle
 * @param keySet    key set retrieved from hooks
 *                  e.g. elektraInternalnotificationGet or elektraInternalnotificationSet)
 *
 */
void elektraInternalnotificationUpdateRegisteredKeys (Plugin * plugin, KeySet * keySet)
{
	PluginState * pluginState = elektraPluginGetData (plugin);
	ELEKTRA_ASSERT (pluginState != NULL, "plugin state was not initialized properly");

	KeyRegistration * registeredKey = pluginState->head;
	while (registeredKey != NULL)
	{
		int changed = 0;
		Key * key;
		if (registeredKey->sameOrBelow)
		{
			Key * checkKey = keyNew (registeredKey->name, KEY_END);
			if (keySetContainsSameOrBelow (checkKey, keySet))
			{
				changed = 1;
				key = checkKey;
			}
			else
			{
				keyDel (checkKey);
			}
		}
		else
		{
			key = ksLookupByName (keySet, registeredKey->name, 0);
			if (key != NULL)
			{
				// Detect changes for string keys
				if (!keyIsString (key))
				{
					// always notify for binary keys
					changed = 1;
				}
				else
				{
					const char * currentValue = keyString (key);
					changed = registeredKey->lastValue == NULL || strcmp (currentValue, registeredKey->lastValue) != 0;

					if (changed)
					{
						// Save last value
						char * buffer = elektraStrDup (currentValue);
						if (buffer)
						{
							if (registeredKey->lastValue != NULL)
							{
								// Free previous value
								elektraFree (registeredKey->lastValue);
							}
							registeredKey->lastValue = buffer;
						}
					}
				}
			}
		}

		if (changed)
		{
			ELEKTRA_LOG_DEBUG ("found changed registeredKey=%s with string value \"%s\". using context or variable=%p",
					   registeredKey->name, keyString (key), registeredKey->context);

			// Invoke callback
			ElektraNotificationChangeCallback callback = *(ElektraNotificationChangeCallback) registeredKey->callback;
			callback (key, registeredKey->context);
			if (registeredKey->sameOrBelow)
			{
				keyDel (key);
			}
		}

		// proceed with next registered key
		registeredKey = registeredKey->next;
	}
}