| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #include "config.h" |
| |
| #include "conf-file.h" |
| #include "conf-parse.h" |
| |
| #include <guacamole/client.h> |
| |
| #include <errno.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| |
| /** |
| * Updates the configuration with the given parameter/value pair, flagging |
| * errors as necessary. |
| */ |
| static int guacd_conf_callback(const char* section, const char* param, const char* value, void* data) { |
| |
| guacd_config* config = (guacd_config*) data; |
| |
| /* Network server options */ |
| if (strcmp(section, "server") == 0) { |
| |
| /* Bind host */ |
| if (strcmp(param, "bind_host") == 0) { |
| free(config->bind_host); |
| config->bind_host = strdup(value); |
| return 0; |
| } |
| |
| /* Bind port */ |
| else if (strcmp(param, "bind_port") == 0) { |
| free(config->bind_port); |
| config->bind_port = strdup(value); |
| return 0; |
| } |
| |
| } |
| |
| /* Options related to daemon startup */ |
| else if (strcmp(section, "daemon") == 0) { |
| |
| /* PID file */ |
| if (strcmp(param, "pid_file") == 0) { |
| free(config->pidfile); |
| config->pidfile = strdup(value); |
| return 0; |
| } |
| |
| /* Max log level */ |
| else if (strcmp(param, "log_level") == 0) { |
| |
| int level = guacd_parse_log_level(value); |
| |
| /* Invalid log level */ |
| if (level < 0) { |
| guacd_conf_parse_error = "Invalid log level. Valid levels are: \"trace\", \"debug\", \"info\", \"warning\", and \"error\"."; |
| return 1; |
| } |
| |
| /* Valid log level */ |
| config->max_log_level = level; |
| return 0; |
| |
| } |
| |
| } |
| |
| /* SSL-specific options */ |
| else if (strcmp(section, "ssl") == 0) { |
| #ifdef ENABLE_SSL |
| /* SSL certificate */ |
| if (strcmp(param, "server_certificate") == 0) { |
| free(config->cert_file); |
| config->cert_file = strdup(value); |
| return 0; |
| } |
| |
| /* SSL key */ |
| else if (strcmp(param, "server_key") == 0) { |
| free(config->key_file); |
| config->key_file = strdup(value); |
| return 0; |
| } |
| #else |
| guacd_conf_parse_error = "SSL support not compiled in"; |
| return 1; |
| #endif |
| |
| } |
| |
| /* If still unhandled, the parameter/section is invalid */ |
| guacd_conf_parse_error = "Invalid parameter or section name"; |
| return 1; |
| |
| } |
| |
| int guacd_conf_parse_file(guacd_config* conf, int fd) { |
| |
| int chars_read; |
| |
| char buffer[8192]; |
| int length = 0; |
| |
| int line = 1; |
| char* line_start = buffer; |
| int parsed = 0; |
| |
| /* Attempt to fill remaining space in buffer */ |
| while ((chars_read = read(fd, buffer + length, sizeof(buffer) - length)) > 0) { |
| |
| length += chars_read; |
| |
| line_start = buffer; |
| |
| /* Attempt to parse entire buffer */ |
| while ((parsed = guacd_parse_conf(guacd_conf_callback, line_start, length, conf)) > 0) { |
| line_start += parsed; |
| length -= parsed; |
| line++; |
| } |
| |
| /* Shift contents to front */ |
| memmove(buffer, line_start, length); |
| |
| } |
| |
| /* Handle parse errors */ |
| if (parsed < 0) { |
| int column = guacd_conf_parse_error_location - line_start + 1; |
| fprintf(stderr, "Parse error at line %i, column %i: %s.\n", |
| line, column, guacd_conf_parse_error); |
| return 1; |
| } |
| |
| /* Check for error conditions */ |
| if (chars_read < 0) { |
| fprintf(stderr, "Error reading configuration: %s\n", strerror(errno)); |
| return 1; |
| } |
| |
| /* Read successfully */ |
| return 0; |
| |
| } |
| |
| guacd_config* guacd_conf_load() { |
| |
| guacd_config* conf = malloc(sizeof(guacd_config)); |
| if (conf == NULL) |
| return NULL; |
| |
| /* Load defaults */ |
| conf->bind_host = NULL; |
| conf->bind_port = strdup("4822"); |
| conf->pidfile = NULL; |
| conf->foreground = 0; |
| conf->max_log_level = GUAC_LOG_INFO; |
| |
| #ifdef ENABLE_SSL |
| conf->cert_file = NULL; |
| conf->key_file = NULL; |
| #endif |
| |
| /* Read configuration from file */ |
| int fd = open(GUACD_CONF_FILE, O_RDONLY); |
| if (fd > 0) { |
| |
| int retval = guacd_conf_parse_file(conf, fd); |
| close(fd); |
| |
| if (retval != 0) { |
| fprintf(stderr, "Unable to parse \"" GUACD_CONF_FILE "\".\n"); |
| free(conf); |
| return NULL; |
| } |
| |
| } |
| |
| /* Notify of errors preventing reading */ |
| else if (errno != ENOENT) { |
| fprintf(stderr, "Unable to open \"" GUACD_CONF_FILE "\": %s\n", strerror(errno)); |
| free(conf); |
| return NULL; |
| } |
| |
| return conf; |
| |
| } |
| |