Example #1
0
// elektra wildcard syntax to fnmatch syntax
static char * keyNameToMatchingString (const Key * key)
{
	uint8_t arrayCount = 0;
	char * name = strchr (keyName (key), '/');
	if (!name) return elektraStrDup (keyName (key));
	for (char * ptr = name; *ptr != '\0'; ++ptr)
		if (*ptr == '#') ++arrayCount;
	char * pattern = elektraMalloc (elektraStrLen (name) + arrayCount);
	char * dst = pattern;
	for (char * src = (name + 1); *src != '\0'; ++src)
	{
		if (*src == '_' && *(src - 1) == '/' && (*(src + 1) == '/' || *(src + 1) == '\0'))
		{
			*dst++ = '*';
		}
		else if (*src == '#' && *(src - 1) == '/' && (*(src + 1) == '/' || *(src + 1) == '\0'))
		{
			*dst++ = '#';
			*dst++ = '*';
		}
		else
		{
			*dst++ = *src;
		}
	}
	*dst = '\0';
	return pattern;
}
/**
 * Creates a new KeyRegistration structure and appends it at the end of the registration list
 * @internal
 *
 * @param pluginState   internal plugin data structure
 * @param key           key
 * @param callback      callback for changes
 * @param context       context for callback
 * @param freeContext   context needs to be freed on close
 *
 * @return pointer to created KeyRegistration structure or NULL if memory allocation failed
 */
static KeyRegistration * elektraInternalnotificationAddNewRegistration (PluginState * pluginState, Key * key,
									ElektraNotificationChangeCallback callback, void * context,
									int freeContext)
{
	KeyRegistration * item = elektraMalloc (sizeof *item);
	if (item == NULL)
	{
		return NULL;
	}
	item->next = NULL;
	item->lastValue = NULL;
	item->name = elektraStrDup (keyName (key));
	item->callback = callback;
	item->context = context;
	item->sameOrBelow = 0;
	item->freeContext = freeContext;

	if (pluginState->head == NULL)
	{
		// Initialize list
		pluginState->head = pluginState->last = item;
	}
	else
	{
		// Make new item end of list
		pluginState->last->next = item;
		pluginState->last = item;
	}

	return item;
}
Example #3
0
/**
 * @retval 0 if variant did not have a result
 * @retval 1 on success
 */
static int elektraResolveSystem (char variant, ElektraResolved * handle, ElektraResolveTempfile tmpDir, Key * warningsKey)
{
	// hardcoded path wins against variants for now
	if (handle->relPath[0] == '/')
	{
		/* Use absolute path */
		handle->fullPath = elektraStrDup (handle->relPath);
		elektraResolveFinishByFilename (handle, tmpDir);
		return 1;
	}
	if (handle->relPath[0] == '~')
	{
		if (elektraResolveSystemPasswd (handle, warningsKey) == -1)
		{
			return -1;
		}
		elektraResolveFinishByFilename (handle, tmpDir);
		return 1;
	}
	switch (variant)
	{
	case 'x':
		return elektraResolveSystemXDG (handle, tmpDir, warningsKey);
	case 'b':
		return elektraResolveSystemBuildin (handle, tmpDir, warningsKey);
		// TODO: also document in doc/COMPILE.md
	}
	return -1;
}
Example #4
0
int elektraGlobMatch (Key * key, const Key * match, const char * globFlags)
{
	char * tokenList = elektraStrDup (globFlags);
	char delimiter[] = ",";
	char * flagName = strtok (tokenList, delimiter);

	int flags = 0;
	while (flagName != NULL)
	{
		for (size_t i = 0; i < sizeof (flagMaps) / sizeof (struct GlobFlagMap); i++)
		{
			if (!strcmp (flagName, flagMaps[i].name))
			{
				flags |= flagMaps[i].flag;
			}
		}
		flagName = strtok (NULL, delimiter);
	}

	free (tokenList);

	if (!fnmatch (keyString (match), keyName (key), flags))
	{
		keyCopyAllMeta (key, match);
		return 1;
	}

	return 0;
}
Example #5
0
/**
 * @internal
 * Read placement list from plugin.
 *
 * The returned string needs to be freed.
 *
 * @param  plugin Plugin
 * @return        Space separated list of placement names
 */
static char * getPluginPlacementList (Plugin * plugin)
{
	ELEKTRA_NOT_NULL (plugin);

	// Get placements from plugin
	Key * pluginInfo = keyNew ("system/elektra/modules/", KEY_END);
	keyAddBaseName (pluginInfo, plugin->name);
	KeySet * ksResult = ksNew (0, KS_END);
	plugin->kdbGet (plugin, ksResult, pluginInfo);

	Key * placementsKey = keyDup (pluginInfo);
	keyAddBaseName (placementsKey, "infos");
	keyAddBaseName (placementsKey, "placements");
	Key * placements = ksLookup (ksResult, placementsKey, 0);
	if (placements == NULL)
	{
		ELEKTRA_LOG_WARNING ("could not read placements from plugin");
		return 0;
	}
	char * placementList = elektraStrDup (keyString (placements));

	keyDel (pluginInfo);
	keyDel (placementsKey);
	ksDel (ksResult);

	return placementList;
}
Example #6
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;
}
Example #7
0
static int elektraResolveSystemXDG(resolverHandle *p,
		Key *warningsKey)
{
	const char * configDir = getenv("XDG_CONFIG_DIRS");
	const char *defaultDir = "/etc/xdg";

	if (!configDir || !strcmp(configDir, ""))
	{
		elektraResolveSystemXDGHelper(p, defaultDir);
		elektraResolveFinishByFilename(p);
		return 1;
	}

	char *saveptr = 0;
	char *str = elektraStrDup(configDir);
	char *result = strtok_r (str, ":", &saveptr);
	struct stat buf;
	int errnoSave = errno;
	int success = 0;
	while (result)
	{
		if (result[0] != '/')
		{
			ELEKTRA_ADD_WARNINGF(100,
				warningsKey,
				"XDG_CONFIG_DIRS contains a path that is "
				"not absolute (violates XDG specification) and thus "
			 	"it was skipped: %s",
				result);

			result = strtok_r (0, ":", &saveptr);
			continue;
		}

		success = 1; // at least once we got a valid path

		elektraResolveSystemXDGHelper(p, result);

		if (stat(p->filename, &buf) == 0)
		{
			// we found a file!
			break;
		}

		result = strtok_r (0, ":", &saveptr);
	}
	elektraFree(str);
	errno = errnoSave;

	if (!success)
	{
		elektraResolveSystemXDGHelper(p, defaultDir);
	}

	elektraResolveFinishByFilename(p);
	return 1;
}
Example #8
0
/**
 * Creates a new ElektraError using the provided values.
 * The returned value will be allocated with elektraCalloc().
 *
 * @param code        The error code of the error.
 * @param description The description of the error.
 * @param severity    The severity of the error. Only use ELEKTRA_ERROR_SEVERITY_FATAL,
 *                    if the error will be raised with elektraFatalError().
 * @param group       The group to which this error belongs.
 * @param module      The module from which this error originates.
 * @return A newly allocated ElektraError (free with elektraFree()).
 */
ElektraError * elektraErrorCreate (ElektraErrorCode code, const char * description, ElektraErrorSeverity severity)
{
	ElektraError * const error = elektraCalloc (sizeof (struct _ElektraError));
	error->code = code;
	error->description = elektraStrDup (description);
	error->severity = severity;

	return error;
}
Example #9
0
static Key * prefToKey (Key * parentKey, PrefType type, const char * pref)
{
	Key * key = keyNew (keyName (parentKey), KEY_END);
	keyAddBaseName (key, prefix[type]);
	char * localString = elektraStrDup (pref);
	char * cPtr = strstr (localString, ",");
	*cPtr = '\0';
	char * sPtr = localString;
	++sPtr;
	*sPtr++ = '\0';
	char * ePtr = cPtr - 1;
	elektraRstrip (sPtr, &ePtr);
	size_t keyLen = ePtr - sPtr;
	char * prefKey = elektraMalloc (keyLen + 1);
	snprintf (prefKey, keyLen + 1, "%s", sPtr);
	char * tPtr = strtok (prefKey, ".");
	if (tPtr) keyAddBaseName (key, tPtr);
	while ((tPtr = strtok (NULL, ".")) != NULL)
	{
		keyAddBaseName (key, tPtr);
	}
	elektraFree (prefKey);
	sPtr = cPtr + 1;
	sPtr = elektraLskip (sPtr);
	ePtr = strrchr (sPtr, ')');
	*ePtr-- = '\0';
	elektraRstrip (sPtr, &ePtr);
	size_t argLen = ePtr - sPtr + 1;
	char * prefArg = elektraMalloc (argLen + 1);
	snprintf (prefArg, argLen + 1, "%s", sPtr);
	if (!strcmp (prefArg, "true") || !(strcmp (prefArg, "false")))
	{
		keySetMeta (key, "type", "boolean");
		keySetString (key, prefArg);
	}
	else if (prefArg[0] == '"' && prefArg[strlen (prefArg) - 1] == '"')
	{
		// TODO: else if list
		keySetMeta (key, "type", "string");
		*prefArg = '\0';
		*(prefArg + (strlen (prefArg + 1))) = '\0';
		keySetString (key, (prefArg + 1));
	}
	else
	{
		keySetMeta (key, "type", "integer");
		keySetString (key, prefArg);
	}
	elektraFree (prefArg);
	elektraFree (localString);
	return key;
}
static CondResult parseCondition (Key * key, const char * condition, const Key * suffixList, KeySet * ks, Key * parentKey)
{
	CondResult result = FALSE;
	const char * regexString = "((\\(([^\\(\\)]*)\\)))";
	regex_t regex;

	if ((regcomp (&regex, regexString, REG_EXTENDED | REG_NEWLINE)))
	{
		ELEKTRA_SET_ERROR (87, parentKey, "Couldn't compile regex: most likely out of memory"); // the regex compiles so the only
		// possible error would be out of
		// memory
		ksDel (ks);
		return ERROR;
	}

	char * localCondition = elektraStrDup (condition);
	int subMatches = 4;
	regmatch_t m[subMatches];
	char * ptr = localCondition;
	while (1)
	{
		int nomatch = regexec (&regex, ptr, subMatches, m, 0);
		if (nomatch)
		{
			break;
		}
		if (m[3].rm_so == -1)
		{
			result = -1;
			break;
		}
		int startPos;
		int endPos;
		startPos = m[3].rm_so + (ptr - localCondition);
		endPos = m[3].rm_eo + (ptr - localCondition);
		char * singleCondition = elektraMalloc (endPos - startPos + 1);
		strncpy (singleCondition, localCondition + startPos, endPos - startPos);
		singleCondition[endPos - startPos] = '\0';
		result = parseSingleCondition (key, singleCondition, suffixList, ks, parentKey);
		for (int i = startPos - 1; i < endPos + 1; ++i)
			localCondition[i] = ' ';
		localCondition[startPos - 1] = '\'';
		localCondition[startPos] = (result == TRUE) ? '1' : '0';
		localCondition[startPos + 1] = '\'';
		elektraFree (singleCondition);
	}
	elektraFree (localCondition);
	regfree (&regex);
	return result;
}
Example #11
0
/**
 * @brief Allocates a new string holding the name of the temporary file.
 * This method makes use of the "fcrypt/tmpdir" plugin configuration option.
 * @param conf holds the plugin configuration
 * @param file holds the path to the original file
 * @param fd will hold the file descriptor to the temporary file in case of success
 * @returns an allocated string holding the name of the encrypted file. Must be freed by the caller.
 */
static char * getTemporaryFileName (KeySet * conf, const char * file, int * fd)
{
	// read the temporary directory to use from the plugin configuration
	// NOTE the string contained in tmpDir must not be modified!
	const char * tmpDir = NULL;
	Key * k = ksLookupByName (conf, ELEKTRA_FCRYPT_CONFIG_TMPDIR, 0);
	if (k)
	{
		tmpDir = keyString (k);
	}

	if (!tmpDir)
	{
		// check the environment; returns NULL if no match is found
		tmpDir = getenv ("TMPDIR");
	}

	if (!tmpDir)
	{
		// fallback
		tmpDir = ELEKTRA_FCRYPT_DEFAULT_TMPDIR;
	}

	// extract the file name (base name) from the path
	char * fileDup = elektraStrDup (file);
	if (!fileDup) goto error;
	const char * baseName = basename (fileDup);

	// + 1 to add an additional '/' as path separator
	// + 1 to reserve space for the NULL terminator
	// ----------------------------------------------
	// + 2 characters in total
	const size_t newFileAllocated = strlen (tmpDir) + strlen (baseName) + strlen (ELEKTRA_FCRYPT_TMP_FILE_SUFFIX) + 2;
	char * newFile = elektraMalloc (newFileAllocated);
	if (!newFile) goto error;
	snprintf (newFile, newFileAllocated, "%s/%s" ELEKTRA_FCRYPT_TMP_FILE_SUFFIX, tmpDir, baseName);
	*fd = mkstemp (newFile);
	if (*fd < 0)
	{
		elektraFree (newFile);
		goto error;
	}

	elektraFree (fileDup);
	return newFile;

error:
	elektraFree (fileDup);
	return NULL;
}
Example #12
0
static void elektraResolveFinishByFilename (ElektraResolved * handle, ElektraResolveTempfile tmpDir)
{
	size_t filenameSize = strlen (handle->fullPath);
	char * dir = elektraMalloc (filenameSize);
	char * dup = elektraStrDup (handle->fullPath);
	strcpy (dir, dirname (dup));
	elektraFree (dup);
	handle->dirname = dir;

	switch (tmpDir)
	{
	case ELEKTRA_RESOLVER_TEMPFILE_NONE:
		return;
	case ELEKTRA_RESOLVER_TEMPFILE_SAMEDIR:
		elektraGenTempFilename (handle, tmpDir);
		return;
	case ELEKTRA_RESOLVER_TEMPFILE_TMPDIR:
		elektraGenTempFilename (handle, tmpDir);
		return;
	}
}
Example #13
0
static char * elektraResolvePasswd (Key * warningsKey)
{
	ssize_t bufSize = sysconf (_SC_GETPW_R_SIZE_MAX);
	if (bufSize == -1) bufSize = 16384; // man 3 getpwuid

	char * buf = elektraMalloc (bufSize);
	if (!buf) return NULL;
	struct passwd pwd;
	struct passwd * result;

	int s = getpwuid_r (getuid (), &pwd, buf, bufSize, &result);
	if (result == NULL)
	{
		elektraFree (buf);
		if (s != 0)
		{
			ELEKTRA_ADD_WARNING (90, warningsKey, strerror (s));
		}
		return NULL;
	}
	char * resolved = elektraStrDup (pwd.pw_dir);
	elektraFree (buf);
	return resolved;
}
Example #14
0
Trie* elektraTrieInsert(Trie *trie, const char *name, Backend *value)
{
	char* p;
	unsigned char idx;

	if (name==0) name="";
	idx=(unsigned char)name[0];

	if (trie==NULL)
	{
		trie=elektraCalloc(sizeof(Trie));

		if (!strcmp("",name))
		{
			trie->empty_value=value;
			return trie;
		}

		trie->textlen[idx]=strlen(name);

		trie->text[idx]=elektraStrDup(name);

		trie->value[idx]=value;
		return trie;
	}

	if (!strcmp("",name))
	{
		trie->empty_value=value;
		return trie;
	}

	if (trie->text[idx]) {
		/* there exists an entry with the same first character */
		if ((p=elektraTrieStartsWith(name, trie->text[idx]))==0)
		{
			/* the name in the trie is part of the searched name --> continue search */
			trie->children[idx]=elektraTrieInsert(trie->children[idx],name+trie->textlen[idx],value);
		} else {
			/* name in trie doesn't match name --> split trie */
			char *newname;
			Trie *child;
			unsigned char idx2;

			newname=elektraStrDup(p);
			*p=0; /* shorten the old name in the trie */
			trie->textlen[idx]=strlen(trie->text[idx]);

			child=trie->children[idx];

			/* insert the name given as a parameter into the new trie entry */
			trie->children[idx]=elektraTrieInsert(NULL, name+(p-trie->text[idx]), value);

			/* insert the split try into the new trie entry */

			idx2 = (unsigned char) newname[0];
			trie->children[idx]->text[idx2]=newname;
			trie->children[idx]->textlen[idx2]=strlen(newname);
			trie->children[idx]->value[idx2]=trie->value[idx];
			trie->children[idx]->children[idx2]=child;

			trie->value[idx]=0;

		}
	} else {
		/* there doesn't exist an entry with the same first character */
		trie->text[idx]=elektraStrDup(name);
		trie->value[idx]=(void*)value;
		trie->textlen[idx]=strlen(name);
	}

	return trie;
}
Example #15
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;
	}
}
Example #16
0
/**
 * @brief decrypt the file specified at parentKey
 * @param pluginConfig holds the plugin configuration
 * @param parentKey holds the path to the file to be encrypted. Will hold an error description in case of failure.
 * @param state holds the plugin state
 * @retval 1 on success
 * @retval -1 on error, errorKey holds an error description
 */
static int fcryptDecrypt (KeySet * pluginConfig, Key * parentKey, fcryptState * state)
{
	int tmpFileFd = -1;
	char * tmpFile = getTemporaryFileName (pluginConfig, keyString (parentKey), &tmpFileFd);
	if (!tmpFile)
	{
		ELEKTRA_SET_ERROR (87, parentKey, "Memory allocation failed");
		return -1;
	}

	const size_t testMode = inTestMode (pluginConfig);

	// prepare argument vector for gpg call
	// 8 static arguments (magic number below) are:
	//   1. path to the binary
	//   2. --batch
	//   3. -o
	//   4. path to tmp file
	//   5. yes
	//   6. -d
	//   7. file to be encrypted
	//   8. NULL terminator
	int argc = 8 + (2 * testMode);
	char * argv[argc];
	int i = 0;

	argv[i++] = NULL;
	argv[i++] = "--batch";
	argv[i++] = "--yes";

	// if we are in test mode we add the trust model
	if (testMode)
	{
		argv[i++] = "--trust-model";
		argv[i++] = "always";
	}

	argv[i++] = "-o";
	argv[i++] = tmpFile;
	argv[i++] = "-d";
	// safely discarding const from keyString() return value
	argv[i++] = (char *) keyString (parentKey);
	argv[i++] = NULL;

	// NOTE the decryption process works like this:
	// gpg2 --batch --yes -o tmpfile -d configFile
	int result = ELEKTRA_PLUGIN_FUNCTION (gpgCall) (pluginConfig, parentKey, NULL, argv, argc);
	if (result == 1)
	{
		state->originalFilePath = elektraStrDup (keyString (parentKey));
		state->tmpFilePath = tmpFile;
		state->tmpFileFd = tmpFileFd;
		keySetString (parentKey, tmpFile);
	}
	else
	{
		// if anything went wrong above the temporary file is shredded and removed
		shredTemporaryFile (tmpFileFd, parentKey);
		if (unlink (tmpFile))
		{
			ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_FCRYPT_UNLINK, parentKey, "Affected file: %s, error description: %s", tmpFile,
					      strerror (errno));
		}
		if (close (tmpFileFd))
		{
			ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_FCRYPT_CLOSE, parentKey, "%s", strerror (errno));
		}
		elektraFree (tmpFile);
	}
	return result;
}