#include "config.h" // Sets 'dest' to the value of the configuration option with name // 'confname' from configuration file 'filename'. // Returns 1 for success or 0 for error/failure. int getconfstr(char *confname, char *filename, char* dest) { FILE *fp; char *ret; char str[MAXCHAR]; int found = 0; // Have we found the configuration option? // Set strings to zero-length to begin dest[0] = '\0'; // Length of requested configuration option name long int namelen = strlen(confname); fp = fopen(filename, "r"); if (fp == NULL) { printf("error: could not open configuration file '%s'.\n", filename); debugprint(DEBUG_CRIT, "error: could not open configuration file '%s'.\n", filename); exit(1); } // Loop through the whole file, looking for the requested configuration option while (fgets(str, MAXCHAR, fp) != NULL) { char substr[MAXCHAR]; // Check if the next character after the length of the requested option // name is an equals sign, a space, or a tab if (str[namelen] != '=' && str[namelen] != ' ' && str[namelen] != '\t') { // If it isn't this can't have been our option continue; } // Copy the number of characters that the requested option name is long // to a temporary string strncpy(substr, str, namelen); substr[namelen] = '\0'; // If the resulting temporary string contains the requested option name, // we have found our configuration option and it is in the current 'str' if (!(ret = strstr(substr, confname)) == 0) { found = 1; break; } } // If we got here, then either we found the configuration option or we ran out of file if (!found) { debugprint(DEBUG_SOME, "Error reading configuration option '%s', did not find it in configuration file '%s'.\n", confname, filename); fclose(fp); return 0; } long int pos; char conf[MAXCHAR]; // Temporary string to build configuration value in // Starting from the end of the option name, find the position of the start of the configuration value // (including its double quotes) by skipping over everything that isn't an equals sign, a space, or a tab for (size_t i = namelen; i < strlen(str); i++) { if (str[i] == '=' || str[i] == ' ' || str[i] == '\t') { continue; } else { // Record current/final position in string pos = i; break; } } strncpy(conf, str + pos, strlen(str) - pos - 1); // Copy remainder to new string and lop off the newline conf[strlen(str) - pos - 1] = '\0'; // Null terminate // Check for start and end quotes if (conf[0] != '"' || conf[strlen(conf) - 1] != '"') { printf("Error reading configuration option '%s', not enclosed in double quotes in configuration file '%s'!\n", confname, filename); debugprint(DEBUG_CRIT, "Error reading configuration option '%s', not enclosed in double quotes in configuration file '%s'!\n", confname, filename); exit(1); } strncpy(dest, conf + 1, strlen(conf) - 2); // Copy result to destination string without quotes dest[strlen(conf) - 2] = '\0'; // Null terminate debugprint(DEBUG_FULL, "getconfstr(): returning '%s'.\n", dest); // Close fine and return success fclose(fp); return 1; } // Returns the value of the configuration option with name // 'confname' from configuration file 'filename'. // Sets errno to 0 on success, or ECONFINT if it fails, in which case the return value is undefined. int getconfint(char *confname, char *filename) { errno = 0; char result[MAXCHAR]; if (!getconfstr(confname, filename, result)) { debugprint(DEBUG_CRIT, "getconfint(): error getting configuration option '%s' from configuration file '%s'.\n", confname, filename); errno = ECONFINT; } return strtol(result, NULL, 10); // Convert resulting string to an integer, base 10 } // Check the password provided in the string 'str' against what is in // the configuration file 'filename'. // Return 0 for password mismatch, or 1 for password match. int checkpassword(char *password, char *filename) { char confpassword[MAXCHAR]; if (!getconfstr("password", filename, confpassword)) { debugprint(DEBUG_CRIT, "checkpassword(): error getting configuration option 'password' from configuration file '%s'.\n", filename); return 0; } // Ensure passwords are the same length if (strlen(password) != strlen(confpassword)) { debugprint(DEBUG_SOME, "Password length mismatch!\n"); return 0; } // Ensure passwords match if (strncmp(password, confpassword, strlen(password)) == 0) { debugprint(DEBUG_FULL, "confpassword matches password.\n"); return 1; } else { debugprint(DEBUG_SOME, "confpassword does NOT match password!\n"); return 0; } printf("checkpassword(): unexpectedly got to end of function, quitting.\n"); debugprint(DEBUG_CRIT, "checkpassword(): unexpectedly got to end of function, quitting.\n"); exit(1); } // Create the default configuration file. // Return 1 on success, 0 on failure. int createconfigfile(char *filename) { char *dirtmp; char *dir; dirtmp = strdup(filename); dir = strdup(dirname(dirtmp)); // Make sure the parent directory exists struct stat st = {0}; if (stat(dir, &st) == -1) { if (mkdir(dir, 0700)) { printf("Error creating config directory '%s'.\n", dir); debugprint(DEBUG_CRIT, "Error creating config directory '%s'.\n", dir); exit(1); } else { printf("Created config directory '%s'.\n", dir); } } FILE *fp; fp = fopen(filename, "a"); if (fp == NULL) { printf("error: could not open default configuration file '%s' for writing.\n", filename); debugprint(DEBUG_CRIT, "error: could not open default configuration file '%s' for writing.\n", filename); exit(1); } // Prepare the string char *string = "# blabouncer configuration file\n" "#\n" "# Entries must be in the form:\n" "# option name, space, equals sign, space, double quote, option value, double quote\n" "# e.g.\n" "# realname = \"Mr Bla Bouncer\"\n" "#\n" "# Shell expansion is not supported, so do not try and specify e.g.\n" "# \"~/.blabouncer/\" or \"$HOME/.blabouncer/\", instead use \"/home/foo/.blabouncer\"\n" "\n" "nick = \"blabounce\"\n" "nick2 = \"bbounce2\"\n" "nick3 = \"bbounce3\"\n" "username = \"bounceusr\"\n" "realname = \"Mr Bla Bouncer\"\n" "\n" "# Channels to automatically join (comma-separated list, defaults to none)\n" "# Put channel keywords/passwords after channel names following a space.\n" "#channels = \"#blabouncer keyword,#test\"\n" "\n" "# How many seconds of replay log should be sent to connecting clients\n" "replayseconds = \"600\"\n" "\n" "# Connect password clients must provided to connect\n" "password = \"bananas\"\n" "\n" "# Port the bouncer should listen on\n" "clientport = \"1234\"\n" "\n" "# Enable TLS for clients connecting to the bouncer (\"1\" for yes or \"0\" for no)\n" "# If \"0\" then certfile and keyfile need not be set\n" "clienttls = \"1\"\n" "\n" "# Enable TLS for the bouncer connecting to the IRC server (\"1\" for yes or \"0\" for no)\n" "servertls = \"1\"\n" "\n" "# Real IRC server the bouncer connects to\n" "ircserver = \"irc.blatech.net\"\n" "\n" "# Real IRC server port\n" "ircserverport = \"6697\"\n" "\n" "# Real IRC server password\n" "#ircserverpassword = \"apples\"\n" "\n" "# Command to send to the server upon completing registration (e.g. a NickServ password)\n" "#connectcommand \"PRIVMSG NickServ IDENTIFY bananas\"\n" "\n" "# Base directory (defaults to $HOME/.blabouncer/)\n" "# Things such as the logs directory will be placed below this\n" "#basedir = \"/home/foo/.blabouncer/\"\n" "\n" "# Certificate file (defaults to /cert.pem)\n" "# If clienttls = \"0\" then this need not be set\n" "#certfile = \"/home/foo/.blabouncer/cert.pem\"\n" "\n" "# Certificate key file (defaults to /key.pem)\n" "# If clienttls = \"0\" then this need not be set\n" "#keyfile = \"/home/foo/.blabouncer/key.pem\"\n" "\n" "# Enable logging (\"1\" for yes or \"0\" for no)\n" "# Logs go to basedir/logs/ with one file per channel/nick\n" "logging = \"1\"\n" "\n" "# Enable replay logging (\"1\" for yes or \"0\" for no)\n" "# Replay log goes to basedir/replay.log\n" "replaylogging = \"1\"\n" "\n" "# Debug verbosity (\"0\" for critical only, \"1\" for some extra info, \"2\" for full debug mode)\n" "# (All output goes to /debug.txt)\n" "debug = \"2\"\n" "\n" "# Number of debug logs to keep\n" "debugkeep = \"5\"\n"; // Write complete string to file if ((fprintf(fp, "%s", string)) < 0) { debugprint(DEBUG_CRIT, "error: could not write to replay log file.\n"); } fclose(fp); free(dirtmp); free(dir); return 0; }