notashelf /
74fed80a26f39bb04966d12c649a55150724965f
chroma
publicLightweight wallpaper daemon for Wayland
clone
ssh://git@git.notashelf.dev:33/notashelf/chroma.gitCommit 74fed80a26f3
tarballunverified3 files changed+202-28
@@ -67,20 +67,32 @@ static int add_output_mapping(chroma_config_t *config, const char *output_name, return CHROMA_ERROR_MEMORY; } - chroma_config_mapping_t *mapping = &config->mappings[config->mapping_count];+ // Validate string lengths to prevent buffer overflow+ size_t output_len = strlen(output_name);+ size_t path_len = strlen(image_path); - strncpy(mapping->output_name, output_name, sizeof(mapping->output_name) - 1);- mapping->output_name[sizeof(mapping->output_name) - 1] = '\0';+ if (output_len >= sizeof(config->mappings[0].output_name)) {+ chroma_log("ERROR", "Output name too long: %s (max %zu)", output_name,+ sizeof(config->mappings[0].output_name) - 1);+ return CHROMA_ERROR_CONFIG;+ } - strncpy(mapping->image_path, image_path, sizeof(mapping->image_path) - 1);- mapping->image_path[sizeof(mapping->image_path) - 1] = '\0';+ if (path_len >= sizeof(config->mappings[0].image_path)) {+ chroma_log("ERROR", "Image path too long: %s (max %zu)", image_path,+ sizeof(config->mappings[0].image_path) - 1);+ return CHROMA_ERROR_CONFIG;+ }++ chroma_config_mapping_t *mapping = &config->mappings[config->mapping_count];++ strcpy(mapping->output_name, output_name);+ strcpy(mapping->image_path, image_path); config->mapping_count++; chroma_log("DEBUG", "Added mapping: %s -> %s", output_name, image_path); chroma_log("TRACE", "Output mapping %d: '%s' -> '%s' (path length: %zu)",- config->mapping_count, output_name, image_path,- strlen(image_path));+ config->mapping_count, output_name, image_path, path_len); return CHROMA_OK; } @@ -138,11 +150,29 @@ static int parse_config_line(chroma_config_t *config, char *line, // Parse configuration options if (strcasecmp(key, "default_image") == 0) {- strncpy(config->default_image, value, sizeof(config->default_image) - 1);- config->default_image[sizeof(config->default_image) - 1] = '\0';- chroma_log("DEBUG", "Set default image: %s", value);- chroma_log("TRACE", "Default image path set: length=%zu, expanded='%s'",- strlen(value), value);+ char *expanded_path = chroma_expand_path(value);+ const char *path_to_use = expanded_path ? expanded_path : value;+ size_t path_len = strlen(path_to_use);++ if (path_len >= sizeof(config->default_image)) {+ chroma_log("ERROR", "Default image path too long: %s (max %zu)",+ path_to_use, sizeof(config->default_image) - 1);+ if (expanded_path) {+ free(expanded_path);+ }+ return CHROMA_ERROR_CONFIG;+ }++ strcpy(config->default_image, path_to_use);++ if (expanded_path) {+ chroma_log("DEBUG", "Set default image: %s -> %s", value, expanded_path);+ chroma_log("TRACE", "Default image path set: length=%zu, expanded='%s'",+ path_len, expanded_path);+ free(expanded_path);+ } else {+ chroma_log("WARN", "Failed to expand path, using original: %s", value);+ } } else if (strcasecmp(key, "daemon") == 0 || strcasecmp(key, "daemon_mode") == 0) { config->daemon_mode = parse_bool(value);@@ -160,18 +190,33 @@ static int parse_config_line(chroma_config_t *config, char *line, return CHROMA_OK; } + // Expand path before validation and storage+ char *expanded_path = chroma_expand_path(value);+ const char *path_to_validate = expanded_path ? expanded_path : value;+ // Validate image path- if (chroma_image_validate(value) != CHROMA_OK) {- chroma_log("WARN", "Invalid image path for output %s: %s", output_name,- value);+ if (chroma_image_validate(path_to_validate) != CHROMA_OK) {+ chroma_log("WARN", "Invalid image path for output %s: %s (expanded: %s)",+ output_name, value, path_to_validate);+ if (expanded_path) {+ free(expanded_path);+ } return CHROMA_OK; } - if (add_output_mapping(config, output_name, value) != CHROMA_OK) {+ if (add_output_mapping(config, output_name, path_to_validate) !=+ CHROMA_OK) { chroma_log("ERROR", "Failed to add output mapping: %s -> %s", output_name,- value);+ path_to_validate);+ if (expanded_path) {+ free(expanded_path);+ } return CHROMA_ERROR_CONFIG; }++ if (expanded_path) {+ free(expanded_path);+ } } else { chroma_log("WARN", "Unknown configuration key line %d: %s", line_number, key);@@ -4,6 +4,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h>+#include <strings.h> #include <sys/stat.h> #include "../include/chroma.h"@@ -94,18 +94,138 @@ void chroma_cleanup_signals(void) { g_config_file = NULL; } -// Expand tilde in path+// Expand environment variables in a string+static char *expand_env_vars(const char *str) {+ if (!str || strchr(str, '$') == NULL) {+ return strdup(str);+ }++ char *result = strdup("");+ if (!result) {+ return NULL;+ }++ const char *p = str;+ while (*p) {+ if (*p == '$') {+ p++;+ if (*p == '{') {+ // ${VAR} format+ p++;+ const char *end = strchr(p, '}');+ if (!end) {+ // No closing brace, treat as literal+ char *tmp = realloc(result, strlen(result) + 2);+ if (!tmp) {+ free(result);+ return NULL;+ }+ result = tmp;+ strcat(result, "${");+ break;+ }++ size_t var_len = end - p;+ char *var_name = malloc(var_len + 1);+ if (!var_name) {+ free(result);+ return NULL;+ }+ strncpy(var_name, p, var_len);+ var_name[var_len] = '\0';++ const char *var_value = getenv(var_name);+ if (var_value) {+ char *tmp = realloc(result, strlen(result) + strlen(var_value) + 1);+ if (!tmp) {+ free(var_name);+ free(result);+ return NULL;+ }+ result = tmp;+ strcat(result, var_value);+ }++ free(var_name);+ p = end + 1;+ } else {+ // $VAR format+ const char *start = p;+ while (*p && (isalnum((unsigned char)*p) || *p == '_')) {+ p++;+ }++ if (p == start) {+ // Not a valid variable name, treat $ as literal+ char *tmp = realloc(result, strlen(result) + 2);+ if (!tmp) {+ free(result);+ return NULL;+ }+ result = tmp;+ strcat(result, "$");+ } else {+ size_t var_len = p - start;+ char *var_name = malloc(var_len + 1);+ if (!var_name) {+ free(result);+ return NULL;+ }+ strncpy(var_name, start, var_len);+ var_name[var_len] = '\0';++ const char *var_value = getenv(var_name);+ if (var_value) {+ char *tmp = realloc(result, strlen(result) + strlen(var_value) + 1);+ if (!tmp) {+ free(var_name);+ free(result);+ return NULL;+ }+ result = tmp;+ strcat(result, var_value);+ }++ free(var_name);+ }+ }+ } else {+ // Regular character+ size_t len = strlen(result);+ char *tmp = realloc(result, len + 2);+ if (!tmp) {+ free(result);+ return NULL;+ }+ result = tmp;+ result[len] = *p;+ result[len + 1] = '\0';+ p++;+ }+ }++ return result;+}++// Expand tilde and environment variables in path char *chroma_expand_path(const char *path) { if (!path) { return NULL; } - if (path[0] != '~') {- return strdup(path);+ // First expand environment variables+ char *env_expanded = expand_env_vars(path);+ if (!env_expanded) {+ return NULL;+ }++ // Then expand tilde if present+ if (env_expanded[0] != '~') {+ return env_expanded; } const char *home;- if (path[1] == '/' || path[1] == '\0') {+ if (env_expanded[1] == '/' || env_expanded[1] == '\0') { // ~/... or just ~ home = getenv("HOME"); if (!home) {@@ -116,34 +236,39 @@ char *chroma_expand_path(const char *path) { } if (!home) { chroma_log("ERROR", "Could not determine home directory");+ free(env_expanded); return strdup(path); // Return original path as fallback } size_t home_len = strlen(home);- size_t path_len = strlen(path);+ size_t path_len = strlen(env_expanded); char *expanded = malloc(home_len + path_len); // -1 for ~ +1 for \0 if (!expanded) { chroma_log("ERROR", "Failed to allocate memory for path expansion");+ free(env_expanded); return strdup(path); } strcpy(expanded, home);- if (path[1] == '/') {- strcat(expanded, path + 1);+ if (env_expanded[1] == '/') {+ strcat(expanded, env_expanded + 1); } + free(env_expanded); return expanded; } else { // ~user/...- const char *slash = strchr(path, '/');- size_t user_len = slash ? (size_t)(slash - path - 1) : strlen(path) - 1;+ const char *slash = strchr(env_expanded, '/');+ size_t user_len =+ slash ? (size_t)(slash - env_expanded - 1) : strlen(env_expanded) - 1; char *username = malloc(user_len + 1); if (!username) {+ free(env_expanded); return strdup(path); } - strncpy(username, path + 1, user_len);+ strncpy(username, env_expanded + 1, user_len); username[user_len] = '\0'; struct passwd *pw = getpwnam(username);@@ -151,6 +276,7 @@ char *chroma_expand_path(const char *path) { if (!pw) { chroma_log("ERROR", "User not found: %s", username); free(username);+ free(env_expanded); return strdup(path); } @@ -160,6 +286,7 @@ char *chroma_expand_path(const char *path) { size_t remaining_len = slash ? strlen(slash) : 0; char *expanded = malloc(home_len + remaining_len + 1); if (!expanded) {+ free(env_expanded); return strdup(path); } @@ -168,6 +295,7 @@ char *chroma_expand_path(const char *path) { strcat(expanded, slash); } + free(env_expanded); return expanded; } }@@ -413,4 +541,4 @@ void chroma_format_memory_size(size_t bytes, char *buffer, size_t buffer_size) { } // Cleanup utility functions-void chroma_utils_cleanup(void) { chroma_cleanup_signals(); }\ No newline at end of file+void chroma_utils_cleanup(void) { chroma_cleanup_signals(); }