static char *parseLine(char *origLine, char delim, unsigned long offset, Key *parentKey, unsigned long lineNr) { char *line = (origLine + offset); if(*line == '\0') return NULL; char *ptr = strchr(line, delim); if(ptr == NULL) { ssize_t len = elektraStrLen(line); if(line[len-2] == '\n') { line[len-2] = '\0'; } else if(line[len-1] == '\0') { ELEKTRA_ADD_WARNINGF(136, parentKey, "Unexpected end of line(%lu) , expected \\n, got \\0 \n %s\n", lineNr, origLine); } else if(line[len-2] == '\r') { ELEKTRA_ADD_WARNINGF(136, parentKey, "Unexpected end of line(%lu) , expected \\n, found \\r \n %s\n", lineNr, origLine); line[len-2] = '\0'; } else { ELEKTRA_ADD_WARNINGF(136, parentKey, "Unexpected end of line(%lu) , expected \\n, but got 0x%x \n %s\n", lineNr, line[len-2], origLine); } } else { *ptr = '\0'; } return line; }
static int elektraResolveMapperUser (ElektraResolved * handle, ElektraResolveTempfile tmpDir, Key * warningsKey) { int finished = 0; size_t i; for (i = 0; !finished && i < sizeof (ELEKTRA_VARIANT_USER); ++i) { finished = elektraResolveUser (ELEKTRA_VARIANT_USER[i], handle, warningsKey); } if (finished == -1) { ELEKTRA_ADD_WARNINGF (83, warningsKey, "user resolver failed at step %zu, the configuration is: %s", i, ELEKTRA_VARIANT_USER); return -1; } if (!(handle->dirname)) { ELEKTRA_ADD_WARNINGF (83, warningsKey, "no resolver set the user dirname, the configuration is: %s", ELEKTRA_VARIANT_USER); return -1; } elektraResolveFinishByDirname (handle, tmpDir); return finished; }
/** * @brief sets mountpoint * * @param backend where the mountpoint should be set * @param elektraConfig the config where the mountpoint can be found * @param [out] errorKey the name also has the mountpoint set * * @pre ksCurrent() is root key * @post ksCurrent() is root key * * @retval -1 if no mountpoint is found or memory allocation problem * @retval 0 on success */ int elektraBackendSetMountpoint(Backend *backend, KeySet *elektraConfig, Key *errorKey) { Key * root = ksCurrent(elektraConfig); Key * searchMountpoint = keyDup(root); keyAddBaseName(searchMountpoint, "mountpoint"); Key * foundMountpoint = ksLookup(elektraConfig, searchMountpoint, 0); keyDel (searchMountpoint); ksLookup(elektraConfig, root, 0); // reset ksCurrent() if (!foundMountpoint) { ELEKTRA_ADD_WARNINGF(14, errorKey, "Could not find mountpoint within root %s", keyName(root)); return -1; } backend->mountpoint = keyNew("", KEY_VALUE, keyBaseName(root), KEY_END); elektraKeySetName(backend->mountpoint, keyString(foundMountpoint), KEY_CASCADING_NAME | KEY_EMPTY_NAME); keySetName(errorKey, keyName(backend->mountpoint)); if (!backend->mountpoint) { ELEKTRA_ADD_WARNINGF(14, errorKey, "Could not create mountpoint with name %s and value %s", keyString(foundMountpoint), keyBaseName(root)); return -1; } keyIncRef(backend->mountpoint); return 0; }
static int handleMissingConflict (Key * parentKey, Key * key, Key * conflictMeta, OnConflict onConflict) { int ret = 0; const char * problemKeys = elektraMetaArrayToString (key, keyName (conflictMeta), ", "); switch (onConflict) { case ERROR: ELEKTRA_SET_ERRORF (142, parentKey, "%s has missing subkeys: %s\n", keyName (key), problemKeys); ret = -1; break; case WARNING: ELEKTRA_ADD_WARNINGF (143, parentKey, "%s has missing subkeys: %s\n", keyName (key), problemKeys); break; case INFO: { const char * infoString = "has missing subkeys:"; const size_t len = elektraStrLen (infoString) + elektraStrLen (problemKeys) + elektraStrLen (keyName (key)); char * buffer = elektraMalloc (len); snprintf (buffer, len, "%s %s %s", keyName (key), infoString, problemKeys); elektraMetaArrayAdd (key, "logs/spec/info", buffer); elektraFree (buffer); } break; case IGNORE: break; } if (problemKeys) { elektraFree ((void *) problemKeys); } return ret; }
static int handleOutOfRangeConflict (Key * parentKey, Key * key, Key * specKey, Key * conflictMeta, OnConflict onConflict) { int ret = 0; switch (onConflict) { case ERROR: ELEKTRA_SET_ERRORF (142, parentKey, "%s has invalid number of members: %s. Expected: %s\n", keyName (key), keyString (conflictMeta), keyString (keyGetMeta (specKey, "array"))); ret = -1; break; case WARNING: ELEKTRA_ADD_WARNINGF (143, parentKey, "%s has invalid number of members: %s. Expected: %s\n", keyName (key), keyString (conflictMeta), keyString (keyGetMeta (specKey, "array"))); break; case INFO: { const char * infoString = "%s has invalid number of member: %s. Expected: %s"; const size_t len = elektraStrLen (infoString) + elektraStrLen (keyName (key)) + MAX_CHARS_IN_LONG + keyGetValueSize (keyGetMeta (specKey, "array")) - 2; char * buffer = elektraMalloc (len); snprintf (buffer, len, infoString, keyName (key), keyString (conflictMeta), keyString (keyGetMeta (specKey, "array"))); elektraMetaArrayAdd (key, "logs/spec/info", buffer); elektraFree (buffer); } break; case IGNORE: break; } return ret; }
static int handleInvalidConflict (Key * parentKey, Key * key, OnConflict onConflict) { int ret = 0; switch (onConflict) { case ERROR: ELEKTRA_SET_ERRORF (142, parentKey, "Invalid key %s\n", keyName (key)); ret = -1; break; case WARNING: ELEKTRA_ADD_WARNINGF (143, parentKey, "Invalid key %s\n", keyName (key)); break; case INFO: { const char * infoString = "Invalid key "; const size_t len = elektraStrLen (infoString) + elektraStrLen (keyName (key)) - 1; char * buffer = elektraMalloc (len); snprintf (buffer, len, "Invalid key %s\n", keyName (key)); elektraMetaArrayAdd (key, "logs/spec/info", buffer); elektraFree (buffer); } break; case IGNORE: break; } return ret; }
static int fcryptGpgCallAndCleanup (Key * parentKey, KeySet * pluginConfig, char ** argv, int argc, int tmpFileFd, char * tmpFile) { int parentKeyFd = -1; int result = ELEKTRA_PLUGIN_FUNCTION (gpgCall) (pluginConfig, parentKey, NULL, argv, argc); if (result == 1) { parentKeyFd = open (keyString (parentKey), O_WRONLY); // gpg call returned success, overwrite the original file with the gpg payload data if (rename (tmpFile, keyString (parentKey)) != 0) { ELEKTRA_SET_ERRORF (31, parentKey, "Renaming file %s to %s failed.", tmpFile, keyString (parentKey)); result = -1; } } if (result == 1) { if (parentKeyFd >= 0) { shredTemporaryFile (parentKeyFd, parentKey); } } 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 (parentKeyFd >= 0 && close (parentKeyFd)) { ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_FCRYPT_CLOSE, parentKey, "%s", strerror (errno)); } if (close (tmpFileFd)) { ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_FCRYPT_CLOSE, parentKey, "%s", strerror (errno)); } elektraFree (tmpFile); return result; }
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; }
/** * @return freshly allocated buffer with current working directory * * @param warningsKey where warnings are added */ static char * elektraGetCwd (Key * warningsKey) { int size = 4096; char * cwd = elektraMalloc (size); if (cwd == NULL) { ELEKTRA_ADD_WARNING (83, warningsKey, "could not alloc for getcwd, defaulting to /"); return 0; } char * ret = NULL; while (ret == NULL) { ret = getcwd (cwd, size); if (ret == NULL) { if (errno != ERANGE) { // give up, we cannot handle the problem elektraFree (cwd); ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_NOCWD, warningsKey, "getcwd failed with errno %d \"%s\", defaulting to /", errno, strerror (errno)); return 0; } // try to double the space size *= 2; elektraRealloc ((void **) &cwd, size); if (cwd == NULL) { ELEKTRA_ADD_WARNINGF (83, warningsKey, "could not realloc for getcwd size %d, defaulting to /", size); return 0; } } } return ret; }
static void elektraResolveDir (resolverHandle * p, Key * warningsKey) { p->filename = elektraMalloc (KDB_MAX_PATH_LENGTH); #if defined(_WIN32) CHAR dir[MAX_PATH]; DWORD dwRet = GetCurrentDirectory (MAX_PATH, dir); if (dwRet == 0) { char buf[256]; FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError (), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 256, NULL); ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_NOCWD, warningsKey, "GetCurrentDirectory failed: %s, defaulting to /", buf); dir[0] = 0; } else if (dwRet > MAX_PATH) { ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_NOCWD, warningsKey, "GetCurrentDirectory failed, buffer size too small, needed: %ld", dwRet); dir[0] = 0; } escapePath (dir); #else char dir[KDB_MAX_PATH_LENGTH]; if (getcwd (dir, KDB_MAX_PATH_LENGTH) == 0) { ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_NOCWD, warningsKey, "getcwd failed: %s, defaulting to /", strerror (errno)); dir[0] = 0; } #endif strcpy (p->filename, dir); strcat (p->filename, "/"); strncat (p->filename, p->path, KDB_MAX_PATH_LENGTH - strlen (dir) - 3); p->filename[KDB_MAX_PATH_LENGTH - 1] = 0; return; }
static int elektraResolveMapperSystem (ElektraResolved * handle, ElektraResolveTempfile tmpDir, Key * warningsKey) { int finished = 0; size_t i; for (i = 0; !finished && i < sizeof (ELEKTRA_VARIANT_SYSTEM); ++i) { finished = elektraResolveSystem (ELEKTRA_VARIANT_SYSTEM[i], handle, tmpDir, warningsKey); } if (finished == -1) { ELEKTRA_ADD_WARNINGF (83, warningsKey, "no resolver set the user dirname, the configuration is: %s", ELEKTRA_VARIANT_USER); return -1; } if (!(handle->fullPath)) { ELEKTRA_ADD_WARNINGF (83, warningsKey, "no resolver set the system dirname, the configuration is: %s", ELEKTRA_VARIANT_SYSTEM); return -1; } return finished; }
static int elektraResolveEnvHome (ElektraResolved * handle, Key * warningsKey) { const char * home = getenv ("HOME"); if (!home || !strcmp (home, "")) { return 0; } if (home[0] != '/') { ELEKTRA_ADD_WARNINGF (100, warningsKey, "HOME contains a path that is " "not absolute and thus " "it was skipped: %s", home); return 0; } elektraResolveUsingHome (handle, home, 1); return 1; }
static int elektraResolveUserXDGHome (ElektraResolved * handle, Key * warningsKey) { const char * home = getenv ("XDG_CONFIG_HOME"); if (!home || !strcmp (home, "")) { return 0; } if (home[0] != '/') { ELEKTRA_ADD_WARNINGF (100, warningsKey, "XDG_CONFIG_HOME contains a path that is " "not absolute (violates XDG specification) and thus " "it was skipped: %s", home); return 0; } elektraResolveUsingHome (handle, home, 0); return 1; }
/**Builds a backend out of the configuration supplied * from: * @verbatim system/elektra/mountpoints/<name> @endverbatim * * The root key must be like the above example. You do * not need to rewind the keyset. But every key must be * below the root key. * * The internal consistency will be checked in this * function. If necessary parts are missing, like * no plugins, they cant be loaded or similar 0 * will be returned. * * ksCut() is perfectly suitable for cutting out the * configuration like needed. * * @note The given KeySet will be deleted within the function, * don't use it afterwards. * * @param elektraConfig the configuration to work with. * It is used to build up this backend. * @param modules used to load new modules or get references * to existing one * @return a pointer to a freshly allocated backend * this could be the requested backend or a so called * "missing backend". * @retval 0 if out of memory * @ingroup backend */ Backend* elektraBackendOpen(KeySet *elektraConfig, KeySet *modules, Key *errorKey) { Key * cur; Key * root; KeySet *referencePlugins = 0; KeySet *systemConfig = 0; int failure = 0; referencePlugins = ksNew(0, KS_END); ksRewind(elektraConfig); root = ksNext (elektraConfig); Backend *backend = elektraBackendAllocate(); while ((cur = ksNext(elektraConfig)) != 0) { if (keyRel (root, cur) == 1) { // direct below root key KeySet *cut = ksCut (elektraConfig, cur); if (!strcmp(keyBaseName(cur), "config")) { systemConfig = elektraRenameKeys(cut, "system"); ksDel (cut); } else if (!strcmp(keyBaseName(cur), "getplugins")) { if (elektraProcessPlugins(backend->getplugins, modules, referencePlugins, cut, systemConfig, errorKey) == -1) { if (!failure) ELEKTRA_ADD_WARNING(13, errorKey, "elektraProcessPlugins for get failed"); failure = 1; } } else if (!strcmp(keyBaseName(cur), "mountpoint")) { backend->mountpoint = keyNew("", KEY_VALUE, keyBaseName(root), KEY_END); elektraKeySetName(backend->mountpoint, keyString(cur), KEY_CASCADING_NAME | KEY_EMPTY_NAME); if (!backend->mountpoint) { if (!failure) ELEKTRA_ADD_WARNINGF(14, errorKey, "Could not create mountpoint with name %s and value %s", keyString(cur), keyBaseName(root)); failure = 1; } keyIncRef(backend->mountpoint); ksDel (cut); } else if (!strcmp(keyBaseName(cur), "setplugins")) { if (elektraProcessPlugins(backend->setplugins, modules, referencePlugins, cut, systemConfig, errorKey) == -1) { if (!failure) ELEKTRA_ADD_WARNING(15, errorKey, "elektraProcessPlugins for set failed"); failure = 1; } } else if (!strcmp(keyBaseName(cur), "errorplugins")) { if (elektraProcessPlugins(backend->errorplugins, modules, referencePlugins, cut, systemConfig, errorKey) == -1) { if (!failure) ELEKTRA_ADD_WARNING(15, errorKey, "elektraProcessPlugins for error failed"); failure = 1; } } else { // no one cares about that config if (!failure) ELEKTRA_ADD_WARNING(16, errorKey, keyBaseName(cur)); ksDel (cut); } } } if (failure) { Backend *tmpBackend = elektraBackendOpenMissing(backend->mountpoint); elektraBackendClose(backend, errorKey); backend = tmpBackend; } ksDel (systemConfig); ksDel (elektraConfig); ksDel (referencePlugins); return backend; }
/** * @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; }
static int csvRead(KeySet *returned, Key *parentKey, char delim, short useHeader, unsigned long fixColumnCount, const char **colNames) { const char *fileName; fileName = keyString(parentKey); FILE *fp = NULL; fp = fopen(fileName, "rb"); if(!fp) { ELEKTRA_SET_ERRORF(116, parentKey, "couldn't open file %s\n", fileName); return -1; } unsigned long length = 0; length = getLineLength(fp); if(length == 0) { ELEKTRA_ADD_WARNING(118, parentKey, "Empty file"); fclose(fp); return -2; } char *lineBuffer; lineBuffer = elektraMalloc((length * sizeof(char))+1); if(!lineBuffer) { ELEKTRA_SET_ERROR(87, parentKey, "Out of memory"); return -1; } if(!fgets(lineBuffer, length, fp)) { ELEKTRA_SET_ERROR(116, parentKey, "Cant read from file"); return -1; } unsigned long columns = 0; columns = getColumnCount(lineBuffer, delim); if(fixColumnCount) { if(columns != fixColumnCount) { ELEKTRA_SET_ERROR(117, parentKey, "illegal number of columns in Header line"); elektraFree(lineBuffer); fclose(fp); return -1; } } unsigned long colCounter = 0; unsigned long lineCounter = 0; unsigned long offset = 0; char *col; char buf[INTSTR_MAX]; int nr_keys = 1; KeySet *header = ksNew(0, KS_END); Key *key; if(useHeader == 1) { colCounter = 0; offset = 0; while((col = parseLine(lineBuffer, delim, offset, parentKey, lineCounter)) != NULL) { offset += elektraStrLen(col); key = keyDup(parentKey); if(colNames && (colNames+colCounter)) { keyAddBaseName(key, colNames[colCounter]); } else { keyAddBaseName(key, col); } keySetMeta(key, "csv/order", itostr(buf, colCounter, sizeof(buf)-1)); ksAppendKey(header, key); ++colCounter; } fseek(fp, 0, SEEK_SET); } else { colCounter = 0; //if no headerline exists name the columns 0..N where N is the number of columns key = keyDup(parentKey); keyAddName(key, "#"); while(colCounter < columns) { if(elektraArrayIncName(key) == -1) { elektraFree(lineBuffer); keyDel(key); ksDel(header); fclose(fp); return -1; } keySetMeta(key, "csv/order", itostr(buf, colCounter, sizeof(buf)-1)); if(colNames && (colNames+colCounter)) keySetBaseName(key, colNames[colCounter]); ksAppendKey(header, keyDup(key)); ++colCounter; } keyDel(key); if(useHeader == 0) fseek(fp, 0, SEEK_SET); } Key *dirKey; Key *cur; dirKey = keyDup(parentKey); keyAddName(dirKey, "#"); while(!feof(fp)) { length = getLineLength(fp); if(length == 0) break; if(elektraRealloc((void **)&lineBuffer, (length * sizeof(char))+1) < 0) { fclose(fp); elektraFree(lineBuffer); ksDel(header); keyDel(dirKey); ELEKTRA_SET_ERROR(87, parentKey, "Out of memory"); return -1; } fgets(lineBuffer, length, fp); if(elektraArrayIncName(dirKey) == -1) { elektraFree(lineBuffer); keyDel(dirKey); ksDel(header); fclose(fp); return -1; } ++nr_keys; offset = 0; colCounter = 0; char *lastIndex = "#0"; while((col = parseLine(lineBuffer, delim, offset, parentKey, lineCounter)) != NULL) { cur = getKeyByOrderNr(header, colCounter); offset += elektraStrLen(col); key = keyDup(dirKey); keyAddBaseName(key, keyBaseName(cur)); keySetString(key, col); keySetMeta(key, "csv/order", itostr(buf, colCounter, sizeof(buf)-1)); ksAppendKey(returned, key); lastIndex = (char *)keyBaseName(key); ++nr_keys; ++colCounter; } keySetString(dirKey, lastIndex); ksAppendKey(returned, keyDup(dirKey)); if(colCounter != columns) { if(fixColumnCount) { ELEKTRA_SET_ERRORF(117, parentKey, "illegal number of columns in line %lu", lineCounter); elektraFree(lineBuffer); fclose(fp); keyDel(dirKey); ksDel(header); return -1; } ELEKTRA_ADD_WARNINGF(118, parentKey, "illegal number of columns in line %lu", lineCounter); } ++lineCounter; } key = keyDup(parentKey); keySetString(key, keyBaseName(dirKey)); ksAppendKey(returned, key); keyDel(dirKey); fclose(fp); elektraFree(lineBuffer); ksDel(header); return 1; }