171 lines
5.5 KiB
C
171 lines
5.5 KiB
C
/**
|
|
* Copyright © 2019, 2020 William Brawner.
|
|
*
|
|
* This file is part of PiHelper.
|
|
*
|
|
* PiHelper is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* PiHelper is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with PiHelper. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <limits.h>
|
|
#include <pwd.h>
|
|
#include <unistd.h>
|
|
#include "config.h"
|
|
|
|
int mkdirs(char * path) {
|
|
char * curPos = strstr(path, "/") + 1;
|
|
char parents[strlen(path)];
|
|
int retval = 0;
|
|
while (curPos != NULL) {
|
|
snprintf(parents, strlen(path) - strlen(curPos) + 1, "%s", path);
|
|
curPos = strstr(curPos + 1, "/");
|
|
if (access(parents, F_OK)) {
|
|
if ((retval = mkdir(parents, 0755)) != 0) {
|
|
return retval;
|
|
}
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
int save_config(pihole_config * config, char * config_path) {
|
|
if (mkdirs(config_path)) {
|
|
perror(config_path);
|
|
return 1;
|
|
}
|
|
FILE * config_file = fopen(config_path, "w");
|
|
int config_len = strlen(config->host) + strlen(config->api_key) + 16;
|
|
char config_string[config_len + 1];
|
|
snprintf(config_string, config_len, "host=%s\napi-key=%s\n", config->host, config->api_key);
|
|
config_string[config_len + 1] = '\0';
|
|
fputs(config_string, config_file);
|
|
fclose(config_file);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Calculate the hash of the password
|
|
*/
|
|
static char * hash_string (char * raw_string) {
|
|
unsigned char bytes[SHA256_DIGEST_LENGTH];
|
|
SHA256((unsigned char *) raw_string, strlen(raw_string), bytes);
|
|
char * hash = malloc(MAX_PIHOLE_API_KEY + 1);
|
|
int i;
|
|
for(i = 0; i < SHA256_DIGEST_LENGTH; i++) {
|
|
sprintf(hash + (i * 2), "%02x", bytes[i]);
|
|
}
|
|
hash[MAX_PIHOLE_API_KEY] = '\0';
|
|
return hash;
|
|
}
|
|
|
|
pihole_config * read_config(char * config_path) {
|
|
if (access(config_path, F_OK)) {
|
|
write_log(PIHELPER_LOG_ERROR, "The specified config file doesn't exist: %s", config_path);
|
|
return NULL;
|
|
}
|
|
|
|
FILE * config_file = fopen(config_path, "r");
|
|
char * host = calloc(1, _POSIX_HOST_NAME_MAX + 7);
|
|
fgets(host, _POSIX_HOST_NAME_MAX + 7, config_file);
|
|
if (strstr(host, "host=") == NULL || strlen(host) < 7) {
|
|
write_log(PIHELPER_LOG_DEBUG, "Config file contains invalid host: %s", host);
|
|
write_log(PIHELPER_LOG_ERROR, "Invalid config file");
|
|
fclose(config_file);
|
|
return NULL;
|
|
}
|
|
pihole_config * config = pihole_config_new();
|
|
config_set_host(config, host + 5);
|
|
free(host);
|
|
char * api_key = calloc(1, 74);
|
|
fgets(api_key, 74, config_file);
|
|
fclose(config_file);
|
|
if (strstr(api_key, "api-key=") == NULL
|
|
|| strlen(api_key) < 9) {
|
|
write_log(PIHELPER_LOG_DEBUG, "Config file contains invalid api key: %s", api_key);
|
|
write_log(PIHELPER_LOG_WARN, "The config file is missing a valid API key. Authenticated operations won't work.");
|
|
free(api_key);
|
|
fclose(config_file);
|
|
return config;
|
|
}
|
|
config_set_api_key(config, api_key + 8);
|
|
free(api_key);
|
|
write_log(PIHELPER_LOG_DEBUG, "Using host %s and api key %s", config->host, config->api_key);
|
|
return config;
|
|
}
|
|
|
|
pihole_config * pihole_config_new() {
|
|
pihole_config * config;
|
|
if ((config = malloc(sizeof(pihole_config))) == NULL) {
|
|
write_log(PIHELPER_LOG_ERROR, "Failed to allocate memory for config");
|
|
free_config(config);
|
|
return NULL;
|
|
}
|
|
if ((config->host = calloc(1, _POSIX_HOST_NAME_MAX + 1)) == NULL) {
|
|
write_log(PIHELPER_LOG_ERROR, "Failed to allocate memory for config host");
|
|
free_config(config);
|
|
return NULL;
|
|
}
|
|
if ((config->api_key = calloc(1, MAX_PIHOLE_API_KEY + 1)) == NULL) {
|
|
write_log(PIHELPER_LOG_ERROR, "Failed to allocate memory for config API key");
|
|
free_config(config);
|
|
return NULL;
|
|
}
|
|
config->host[_POSIX_HOST_NAME_MAX] = '\0';
|
|
config->api_key[MAX_PIHOLE_API_KEY] = '\0';
|
|
return config;
|
|
}
|
|
|
|
void config_set_host(pihole_config * config, char * host) {
|
|
strncpy(config->host, host, _POSIX_HOST_NAME_MAX);
|
|
config->host[_POSIX_HOST_NAME_MAX] = '\0';
|
|
trim_string(config->host);
|
|
}
|
|
|
|
void config_set_password(pihole_config * config, char * password) {
|
|
trim_string(password);
|
|
// This is definitely not an API key, so hash it
|
|
// The Pi-hole hashes twice so we do the same here
|
|
char * first = hash_string(password);
|
|
char * hash = hash_string(first);
|
|
free(first);
|
|
config_set_api_key(config, hash);
|
|
free(hash);
|
|
}
|
|
|
|
void config_set_api_key(pihole_config * config, char * api_key) {
|
|
strncpy(config->api_key, api_key, MAX_PIHOLE_API_KEY);
|
|
config->api_key[MAX_PIHOLE_API_KEY] = '\0';
|
|
trim_string(config->api_key);
|
|
}
|
|
|
|
static void trim_string(char * raw_str) {
|
|
char * newline = strstr(raw_str, "\n");
|
|
if (newline != NULL) {
|
|
raw_str[strlen(raw_str) - strlen(newline)] = '\0';
|
|
}
|
|
}
|
|
|
|
void free_config(pihole_config * config) {
|
|
if (config == NULL) return;
|
|
if (config->host != NULL) {
|
|
free(config->host);
|
|
}
|
|
if (config->api_key != NULL) {
|
|
free(config->api_key);
|
|
}
|
|
free(config);
|
|
}
|
|
|