#include "settings.h"extern int errno;#include <time.h>/* private interface methods start*/static gboolean copy_file(const gchar* source, const gchar* destination) ;static gboolean jail_new_from_file(const gchar* dir, gchar* canonical_name, struct jail** out) ;static gboolean jail_is_assigned(GKeyFile* settings, int uid);static int settings_get_free_jail(GKeyFile* settings);static gboolean settings_set_jail_uid(GKeyFile* settings, const gchar* jail_name, int uid);/* private interface methods end */// convert from host:ip:port to ip:portstatic gchar* get_host(gchar* group_host) { return group_host+strlen("host:");}// convert from enum to charenum hostaction char2enum(gchar* action) { if (strcasecmp(action, "deny") == 0) return DENY; else if(strcasecmp(action, "allow") == 0) return ALLOW; else if(strcasecmp(action, "ask") == 0) return ASK; else if(strcasecmp(action, "allowentry") == 0) return ALLOWENTRY; else return ERROR;}// convert from char to enum gchar* enum2char(enum hostaction action) { if (action == DENY) return "deny"; else if(action == ALLOW) return "allow"; else if(action == ASK) return "ask"; else if(action == ALLOWENTRY) return "allowentry"; else return "error";}/* taken from gnucash and slightly modified */GKeyFile *settings_load_from_file (const gchar * filename, gboolean ignore_error, gboolean return_empty_struct){ GKeyFile *key_file; GError *error = NULL; g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "settings_load_from_file ENTER\n"); if (!filename) return FALSE; if (!g_file_test (filename, G_FILE_TEST_EXISTS)) return NULL; key_file = g_key_file_new (); if (!key_file) return NULL; if (g_key_file_load_from_file(key_file, filename, G_KEY_FILE_KEEP_COMMENTS, &error)) { g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "settings_load_from_file LEAVE SUCCESS\n"); return key_file; } /* An error occurred */ if (!return_empty_struct) { g_key_file_free (key_file); key_file = NULL; } if (!ignore_error) g_warning ("Unable to read file %s: %s\n", filename, error->message); g_error_free (error); g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "settings_load_from_file LEAVE FAILURE\n"); return key_file;}/* taken from gnucash and slightly modified */gboolean settings_save_to_file (const gchar * filename, GKeyFile * key_file, GError ** error){ gchar *contents; gint fd; gint length; ssize_t written; gboolean success = TRUE; if (filename == NULL || key_file == NULL) return FALSE; contents = g_key_file_to_data (key_file, NULL, NULL); length = strlen (contents); fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (fd == -1) { if (error) { *error = g_error_new (G_FILE_ERROR, g_file_error_from_errno (errno), "Cannot open file %s: %s", filename, strerror (errno)); } else { g_critical ("Cannot open file %s: %s\n", filename, strerror (errno)); } g_free (contents); return FALSE; } written = write (fd, contents, length); if (written == -1) { success = FALSE; if (error) { *error = g_error_new (G_FILE_ERROR, g_file_error_from_errno (errno), "Cannot write to file %s: %s", filename, strerror (errno)); } else { g_critical ("Cannot write to file %s: %s\n", filename, strerror (errno)); } close (fd); } else if (written != length) { success = FALSE; if (error) { *error = g_error_new (G_FILE_ERROR, g_file_error_from_errno (errno), "File %s truncated (provided %d, written %d)", filename, length, (int) written); } else { g_critical ("File %s truncated (provided %d, written %d)", filename, length, (int) written); } /* Ignore any error */ close (fd); } else if (close (fd) == -1) { if (error) { *error = g_error_new (G_FILE_ERROR, g_file_error_from_errno (errno), "Close failed for file %s: %s", filename, strerror (errno)); } else { g_warning ("Close failed for file %s: %s", filename, strerror (errno)); } } g_free (contents); return success;}// print the host structure in human readable formvoid host_print(struct host* h) { g_assert(h != NULL); gchar** execve = h->execve; g_print("host_addr:\t%s\n", h->host_addr); g_print("action:\t%s\n", enum2char(h->action)); g_print("cmd:\t%s\n", h->cmd); g_print("execve:{"); while (execve && *execve) { g_print("%s ",*execve); execve++; } g_print("}\n"); g_print("keys:{"); FOREACH_LIST(h->keys, key) { g_print("%s ", (char*)key->data); } g_print("}\n");}struct host* host_dup(struct host* old) { struct host* ret = malloc(sizeof (struct host)); if (ret == NULL) g_error("no memory left\n"); memset(ret, 0, sizeof(struct host)); // make the new rule COPY OVER ret->action = old->action; SAFE_STRNCPY(ret->host_addr, old->host_addr, MAX_HOST); SAFE_STRNCPY(ret->cmd, old->cmd, MAX_PATH); if (ret->execve) ret->execve = g_strdupv(old->execve); FOREACH_LIST(ret->keys, key) { ret->keys = g_list_append(ret->keys, key->data); } return ret;}// load policiesvoid policy_new(int main_uid, struct policies* out) { DIR* proc; struct dirent* dirp; struct jail* new_jail; char default_path[MAX_PATH+1]; int uid = -1; GError *err = NULL; out->uid2jailstruct = g_hash_table_new(NULL, NULL); proc = opendir(out->policy_path); if (proc == NULL) g_error("load_policy:could not open policy dir %s:%s\n", out->policy_path, g_strerror(errno)); if (!SAFE_SNPRINTF(default_path, MAX_PATH, "%s/%s", out->policy_path, "default")) { g_error("policy_new:failure to concatenate paths\n"); } if (access(default_path, R_OK)) { g_error("policy_new:could not find the default policy in %s\n", default_path); } // try to load the main policy// if (jail_new_from_file(out->policy_path, "main", &new_jail)==FALSE)// g_error("load_policy:could not main policy dir:%s\n", g_strerror(errno));// out->main = new_jail;// g_hash_table_insert(out->uid2jailstruct, GINT_TO_POINTER(main_uid), new_jail); while ( (dirp = readdir(proc)) ) { // load the policy but ignore main and default policies if (strcmp(dirp->d_name, "..")==0 || strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "default") == 0) continue; if (jail_new_from_file(out->policy_path, dirp->d_name, &new_jail)) { g_print("loaded jail with canonical namd %s\n", dirp->d_name); // find which uid this jail is associated with uid = settings_get_jail_uid(out->settings, dirp->d_name); if (uid == -1) { uid = settings_get_free_jail(out->settings); if (uid == -1) { g_print("policy_new:there are no free slots for this new jail\n"); continue; } g_print("no associate for jail %s will associate with uid %d\n", new_jail->name, uid); settings_set_jail_uid(out->settings, new_jail->name, uid); // update the settings file settings_save_to_file(out->settings_file, out->settings, &err); if (err) g_error("policy_new: failed to update settings file\n"); } g_hash_table_insert(out->uid2jailstruct, GINT_TO_POINTER(uid), new_jail); } } if (proc) closedir(proc); return;}// NOT FINISHED AT ALLvoid policy_free(struct policies* in) { if (in) { free(in); } // clear up the hash table and all the jails}// match the host wildcard with a given uid. if we find it, we return the pointer to the host structure// that describes the policy for that hostgboolean jail_match_policy(const gchar* hostregex, struct jail* jail_in, struct host** host_out) { pcre* re = NULL; const char *error = NULL; gint erroffset; int rc; int ovector[30]; struct host* host; g_assert(jail_in != NULL); g_assert(hostregex != NULL); // iterate over all sequentially, and try to match the host via regex FOREACH_LIST(jail_in->hosts, host_key) { host = (struct host*)host_key->data; // compile regex re = pcre_compile(host->host_addr, 0, &error, &erroffset, NULL); if (re == NULL) { g_warning("jail_match_policy:%s\n", error?error:""); return FALSE; } rc = pcre_exec(re, NULL, hostregex, strlen(hostregex), 0, 0, ovector, 30); if (rc >= 0) { pcre_free(re); *host_out = host; return TRUE; } else if (re) pcre_free(re); } return FALSE;}// free the hostvoid host_free(struct host* h) { g_assert(h != NULL); if (h->execve) g_strfreev(h->execve); while (h->keys) { if (h->keys->data) { free(h->keys->data); } h->keys = h->keys->next; } free(h);}// clean up the linked list of host structuresvoid jail_free(struct jail* in){ g_assert(in != NULL); while (in->hosts) { if (in->hosts->data) { host_free((struct host*)in->hosts->data); } in->hosts = in->hosts->next; } free(in);} struct policy_search_result {struct jail* jail_result; struct host* host_result; gchar* host_addr;} srch;// callback for g_hash_table_foreach. pretty uglyvoid has_primary_host(gpointer key, gpointer value, gpointer user_data) { struct jail* haystack = (struct jail*)value; // current jail that we are lokoing at struct host* host_result; // resultant which will point to the host structure found // we already found it if (srch.jail_result != NULL) // this will be called many times return; // if search->ret is already filled in, somebody found it before us if (jail_match_policy(srch.host_addr, haystack, &host_result)) { srch.jail_result = (host_result->action==ALLOWENTRY)?(haystack):(NULL); // this will pass the result back to the caller srch.host_result = host_result; return; } }// given a certain policy, find in which jail resides the primary host addr host_addr// and return the pointer to itgboolean policy_search_entry_point( struct policies* policy, gchar* host_regex, struct jail** jail_result, struct host** host_result) { srch.jail_result = NULL; srch.host_result = NULL; srch.host_addr = host_regex; g_hash_table_foreach(policy->uid2jailstruct, has_primary_host, &srch); *host_result = srch.host_result; *jail_result = srch.jail_result; return *jail_result != NULL && *host_result != NULL;}struct jail* policy_get_jail_by_uid(struct policies* policy, int uid) { return (struct jail*) g_hash_table_lookup(policy->uid2jailstruct, GINT_TO_POINTER(uid)); }// send the host structure in text format to the data stream pointed to by outgboolean host_write_struct(FILE* fout, struct host* target_host) { GList* key = NULL; // dump the host params fprintf(fout, "[host#%s]\n", target_host->host_addr); fprintf(fout, "action=%s\n", enum2char(target_host->action)); if (target_host->cmd) fprintf(fout, "cmd=%s\n", target_host->cmd); if (target_host->execve) fprintf(fout, "execve=%s\n", g_strjoinv(";", target_host->execve)); key = target_host->keys; while (key && key->data) { fprintf(fout, "%s\n", (char*)key->data); key = key->next; } return TRUE;}// take the command field in target_host and substitute away any string of type {key with}// the actual value of the key if it is defined. if not defined, null will be placedgboolean host_cmd_substition(struct host* target_host, gchar** resultant_cmd, ...) { GList *key_node = target_host->keys; gchar* s; gchar* key = NULL; gchar* value = NULL; gchar* ret = g_strdup(target_host->cmd); va_list ap; // FIRST WE DO SUBSTITUTION ON THE VARGS va_start(ap, resultant_cmd); while (s) { gchar *temp; s = va_arg(ap, gchar *); if (!s) break; key = str_unpack_key(s); value = str_unpack_value(s); if (key == NULL || value == NULL) { if (key) free(key); if (value) free(value); g_warning("host_cmd_substition:malformed substition\n"); continue; } // case sensitive string replace temp = str_replace(ret, key, value); g_assert(temp != NULL); // dump the old return string and replace it with the replaced string free(ret); free(key); free(value); ret = temp; } va_end(ap); // SECOND WE DO SUBSTITUTION ON THE POLICY FILE PARAMETERS while (key_node && key_node->data) { gchar *temp; key = str_unpack_key(key_node->data); value = str_unpack_value(key_node->data); if (key == NULL || value == NULL) { if (key) free(key); if (value) free(value); g_warning("host_cmd_substition:malformed substition\n"); continue; } // case sensitive string replace temp = str_replace(ret, key, value); g_assert(temp != NULL); // dump the old return string and replace it with the replaced string free(ret); free(key); free(value); ret = temp; key_node = key_node->next; } *resultant_cmd = ret; return TRUE; }struct host* host_new() { struct host* ret = malloc(sizeof(struct host)); memset(ret, 0, sizeof(struct host)); return ret;}gboolean host_new_from_settings(GKeyFile* jail_settings, gchar* host_string, struct host** host_out) { gchar** keys = NULL, **keys_iter = NULL; gsize size; GError* err = NULL; gchar* string_key = NULL; gchar** string_list = NULL; gboolean error_free = TRUE; g_assert(host_out != NULL); // we will iterate over all the keys to get and save the mapping keys = keys_iter = g_key_file_get_keys(jail_settings, host_string, &size, &err); if (keys == NULL) { g_warning("get_jail_struct:error during g_key_file_get_keys for %s\n", host_string); return FALSE; } // allocate a host structure to hold the resultant *host_out = (struct host*)malloc(sizeof(struct host)); if (*host_out == NULL) return FALSE; memset(*host_out, 0, sizeof(struct host)); // null it // get the host address if (!SAFE_STRNCPY((*host_out)->host_addr, get_host(host_string), MAX_HOST)) error_free = FALSE; while (*keys_iter && error_free == TRUE) { error_free = FALSE; // we are not error free until we extract the key string_key = NULL; string_key = NULL; if (strcmp(*keys_iter, "cmd") == 0) { string_key = g_key_file_get_string(jail_settings, host_string, "cmd", &err); if (err) break; if (!SAFE_STRNCPY((*host_out)->cmd, string_key?string_key:"", MAX_HOST)) { g_free(string_key); break; } g_free(string_key); } else if (strcmp(*keys_iter, "execve") == 0) { string_list = g_key_file_get_string_list(jail_settings, host_string, "execve", &size, &err); if (err) break; if (string_list) // duplicate the list (*host_out)->execve = g_strdupv(string_list); g_strfreev(string_list); } else if (strcmp(*keys_iter, "action") == 0) { string_key = g_key_file_get_string(jail_settings, host_string, "action", &err); if (err) break; (*host_out)->action = char2enum(string_key); g_free(string_key); if ((*host_out)->action == ERROR) break; } else { gchar* string_key = g_key_file_get_string(jail_settings, host_string, *keys_iter, &err); if (err) break; // we will collect all the variables that are not a part of the policy defined keys (*host_out)->keys = g_list_append((*host_out)->keys, g_strdup_printf("%s=%s", *keys_iter, string_key)); g_free(string_key); } error_free = TRUE; keys_iter++; } if (error_free == FALSE) { if (keys) g_strfreev(keys); if (*host_out) host_free(*host_out); *host_out = NULL; g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "host_new_from_settings LEAVE FAILURE\n"); return FALSE; } return TRUE;}// extract the jail structure from the filegboolean jail_new_from_file(const gchar* dir, gchar* canonical_name, struct jail** jail_out) { char jail_path[MAX_PATH+1]; gsize size; gchar** groups = NULL, **groups_iter = NULL; GKeyFile* jail_settings = NULL; struct host* new_host; gboolean error_free = TRUE; g_assert(jail_out != NULL); g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "jail_new_from_file ENTER\n"); *jail_out = (struct jail*)malloc(sizeof(struct jail)); if (*jail_out == NULL) { g_warning("jail_new_from_file:%s\n", g_strerror(errno)); return FALSE; } memset(*jail_out, 0, sizeof(struct jail)); // store the jail canonical name in the jail structure if (!SAFE_STRNCPY((*jail_out)->name, canonical_name, MAX_PATH)) { g_warning("jail_new_from_file:could not set canonical_name\n"); free(*jail_out); *jail_out = NULL; return FALSE; } // get where this policy is located on disk if (!SAFE_SNPRINTF(jail_path, MAX_PATH, "%s/%s", dir, canonical_name)) { g_warning("jail_new_from_file:could not concatenate paths\n"); free(*jail_out); *jail_out = NULL; return FALSE; } // open the policy file jail_settings = settings_load_from_file(jail_path, FALSE, FALSE); if (jail_settings == NULL) { free(*jail_out); *jail_out = NULL; g_warning("jail_new_from_file:error during open settings %s\n%s\n", jail_path, strerror(errno)); return FALSE; } // get all the hosts for the jail groups_iter = groups = g_key_file_get_groups(jail_settings, &size); if (groups == NULL) { free(*jail_out); *jail_out = NULL; g_key_file_free(jail_settings); g_warning("jail_new_from_file:error during g_key_file_get_groups for %s\n", jail_path); return FALSE; } // iterate over all the hosts while (*groups_iter && error_free == TRUE) { error_free = FALSE; if (strstr(*groups_iter, "host#") == *groups_iter) { if (!host_new_from_settings(jail_settings, *groups_iter, &new_host)) break; (*jail_out)->hosts = g_list_append((*jail_out)->hosts, new_host); // add it to the jail list error_free = TRUE; } groups_iter++; } if (error_free == FALSE) { g_warning("jail_new_from_file:error during g_key_get_xxxxx:command for %s\n", jail_path); jail_free(*jail_out); *jail_out = NULL; } g_strfreev(groups); g_key_file_free(jail_settings); g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "jail_new_from_file LEAVE SUCCESS\n"); return error_free;}// make a new jail with either an existing name// or make a jail name which will be of the form <time><uid>struct jail* policy_create_new_jail(struct policies* in) { char new_jail_path[MAX_PATH+1]; char default_jail_path[MAX_PATH+1]; char new_jail_name[MAX_PATH+1]; int uid; struct jail* new_jail_struct = NULL; GError *err = NULL; g_assert(in != NULL); g_assert(in->settings != NULL); // get the user id of a free jail from the jail pool in jail_list uid = settings_get_free_jail(in->settings ); if (uid == -1) { g_warning("policy_create_new_jail:could not allocate a new jail\n"); return NULL; } // get the default policy path SAFE_SNPRINTF(default_jail_path, MAX_PATH, "%s/default", in->policy_path); // if jail_name is null, creat a new jail name based on time+uid. otherwise, SAFE_SNPRINTF(new_jail_name, MAX_PATH, "%d-%d", (int)time(NULL), uid); // associate the new jail name with uid in the jail_mapping table if (!settings_set_jail_uid(in->settings , new_jail_name, uid)) { g_warning("policy_create_new_jail:could make new assocciation\n"); return NULL; } // craft a path for the new jail if (!SAFE_SNPRINTF(new_jail_path, MAX_PATH, "%s/%s", in->policy_path, new_jail_name)) { g_warning("policy_create_new_jail:failure to format new_jail_path\n"); return NULL; } // copy the file if (!copy_file(default_jail_path, new_jail_path)) { g_warning("policy_create_new_jail:failed to copy file\n"); return NULL; } // retrieve the new jail structure from the fiile if (!jail_new_from_file(in->policy_path, new_jail_name, &new_jail_struct)) { g_warning("policy_create_new_jail:failed to load the datastructure from the new policy\n"); return NULL; } // update the settings file settings_save_to_file(in->settings_file, in->settings, &err); if (err) { g_warning("policy_create_new_jail: failed to update settings file\n"); jail_free(new_jail_struct); return NULL; } // index the new jail struct by uid g_hash_table_insert(in->uid2jailstruct, GINT_TO_POINTER(uid), new_jail_struct); return new_jail_struct; }// add a host to the beginning of the jail associated with a given uid. this updates// the hashes as well gboolean policy_prepend_host(struct policies* policy, struct host* new_host, struct jail** target_jail) { gboolean ret = FALSE; FILE* original = NULL; FILE* temporary = NULL; char buff[4096+1]; size_t in_read = 0; size_t in_wrote = 0; char temporary_path[MAX_PATH+1]; char original_path[MAX_PATH+1]; g_assert(target_jail != NULL); g_assert(new_host != NULL); g_assert(policy != NULL); // make the temporary path if (!SAFE_SNPRINTF(temporary_path, MAX_PATH, "%s/%s_t", policy->policy_path, (*target_jail)->name)) { g_warning("policy_prepend_host:could not sprintf temporary_path\n"); return FALSE; } // make the original path if (!SAFE_SNPRINTF(original_path, MAX_PATH, "%s/%s", policy->policy_path, (*target_jail)->name)) { g_warning("policy_prepend_host:could not sprintf original_path\n"); return FALSE; } // make sure the file is not there if (access(temporary_path, R_OK) == 0) { g_warning("policy_prepend_host:temporary file exists! this is a sign of a big error\n"); return FALSE; } // copy to a temporary file if (!copy_file(original_path, temporary_path)) { g_warning("policy_prepend_host:could not copy to a temporary file\n"); return FALSE; } // kill the original if (unlink(original_path) == -1) { g_warning("policy_prepend_host:could not delete outdated jail file:%s\n", g_strerror(errno)); return FALSE; } original = fopen(original_path, "a"); temporary = fopen(temporary_path, "r"); if (original == NULL || temporary == NULL) { if (original) fclose(original); if (temporary) fclose(temporary); return FALSE; } host_write_struct(original, new_host); while (!feof(temporary) && !ferror(original) && !ferror(original)) { in_wrote = 0; in_read = fread(buff, 1, 4096, temporary); while (in_wrote != in_read) { in_wrote = fwrite(buff+in_wrote, 1, in_read-in_wrote, original); } } if (original) fclose(original); if (temporary) { ret = feof(temporary); fclose(temporary); } if (unlink(temporary_path) == -1) { g_warning("policy_prepend_host:could not delete temporary file:%s\n", g_strerror(errno)); return FALSE; } if (ret == FALSE) { g_warning("policy_prepend_host:highly inconsistent state!\n"); return FALSE; } return policy_reload_jail(policy, target_jail);}// close the jail and open it again. update the hash and write the changes back to *targetgboolean policy_reload_jail(struct policies* policy, struct jail** target) { int uid = -1; char jail_name[MAX_PATH+1]; g_assert(policy != NULL); SAFE_STRNCPY(jail_name, (*target)->name, MAX_PATH); uid = settings_get_jail_uid(policy->settings, (*target)->name); if (uid == -1) g_error("policy_reload_jail:could not reload a jail that does not exist\n"); g_hash_table_remove(policy->uid2jailstruct, GINT_TO_POINTER(uid)); jail_free(*target); if (!jail_new_from_file(policy->policy_path, jail_name, target)) { g_warning("policy_reload_jail:could not read the jail\n"); return FALSE; } // update the hash g_hash_table_insert(policy->uid2jailstruct, GINT_TO_POINTER(uid), *target); return TRUE;}// return uid of a free jailstatic int settings_get_free_jail(GKeyFile* settings) { gchar** jails = NULL; gchar** jails_iter; GError *err= NULL; gsize length; // get the list of all uids jails_iter = jails = g_key_file_get_keys(settings, "jail_list", &length, &err); if (err) { g_error("settings_get_free_jail:could not get the list of jails!\n"); g_strfreev(jails); return -1; } // iterate through all uids and find a free one while (*jails_iter) { // if the jail is not assigned, return the uid if (jail_is_assigned(settings, atoi(*jails_iter)) == FALSE) { int ret = atoi(*jails_iter); // free up the buffer g_strfreev(jails); return ret; } // move to the next uid jails_iter++; } // free up the buffer if (jails) g_strfreev(jails); g_warning("settings_get_free_jail:no free jails remain\n"); return -1;}// path must be MAX_PATH long// returns the length of path stringint settings_get_jail_path(GKeyFile* settings, int uid, gchar* path) { GError* err = NULL; gchar str_uid[256]; gchar* ret = NULL; SAFE_SNPRINTF(str_uid, 256, "%d", uid); ret = g_key_file_get_string(settings, "jail_list", str_uid, &err); if (err) return -1; if (!SAFE_STRNCPY(path, ret, MAX_PATH)) { g_warning("settings_get_jail_path:could not save the result\n"); } return strlen(ret); }// is there a jail assigned to uid?static gboolean jail_is_assigned(GKeyFile* settings, int uid) { gsize length; GError* err = NULL; gchar** jails = NULL; gchar** jails_iter = NULL; // get all the jail canonical names jails = jails_iter = g_key_file_get_keys(settings, "jail_mapping", &length, &err); if (*jails == NULL) return FALSE; // iterate through all the canonicals // and see if any of them are mapped to this given uid // if so, return TRUE while (*jails_iter) { if (settings_get_jail_uid(settings, *jails_iter) == uid) { if (jails) g_strfreev(jails); return TRUE; } jails_iter++; } // free up the buffer if (jails) g_strfreev(jails); return FALSE;}// find which uid the canonical jail is mapped toint settings_get_jail_uid(GKeyFile* settings, const gchar* jail_name) { int ret; GError *err = NULL; ret = g_key_file_get_integer(settings, "jail_mapping", jail_name, &err); if (err != NULL) ret = -1; return ret;}// associate a canonical jail name with uidstatic gboolean settings_set_jail_uid(GKeyFile* settings, const gchar* jail_name, int uid) { g_key_file_set_integer(settings, "jail_mapping", jail_name, uid); return TRUE;}// copy the filestatic gboolean copy_file(const gchar* source, const gchar* destination) { FILE* in = fopen(source, "r"); FILE* out = fopen(destination, "a"); char buff[4096+1]; size_t in_read = 0; size_t in_wrote = 0; gboolean is_eof; if (in == NULL || out == NULL) { if (in) fclose(in); if (out) fclose(out); return FALSE; } while (!feof(in) && !ferror(in) && !ferror(out)) { in_wrote = 0; in_read = fread(buff, 1, 4096, in); while (in_wrote != in_read) { in_wrote = fwrite(buff+in_wrote, 1, in_read-in_wrote, out); } } is_eof = feof(in); // DEBUGGING ASSERT g_assert(ferror(in) == FALSE); g_assert(ferror(out) == FALSE); if (in) fclose(in); if (out) fclose(out); return is_eof == TRUE;}gchar* str_pack_key_value(const gchar* key_string, const gchar* value_string){ return g_strdup_printf("%s=%s", key_string, value_string);}// get key from key=value. make sure to free resultantgchar* str_unpack_key(const gchar* key_string){ gchar* eq = NULL; gchar* ret; if ((eq = strchr(key_string, '='))) { ret = malloc(eq - key_string + 1); if (ret == NULL) return NULL; strncpy(ret, key_string, eq - key_string); ret[eq-key_string] = 0x00; return ret; } return NULL;}// get value from key=value make sure to free resultantgchar* str_unpack_value(const gchar* key_string) { gchar* eq = NULL; gchar* ret; int key_string_length = strlen(key_string); if ((eq = strchr(key_string, '='))) { ret = malloc(key_string_length - (key_string - eq)); if (ret == NULL) return NULL; strncpy(ret, eq+1, key_string_length - (key_string - eq)); return ret; } return NULL;}// replace one instance of from with to in str strgchar* str_replace(const gchar* str, const gchar* from, const gchar* to) { gchar* resultant = NULL; int str_length = strlen(str); int from_length = strlen(from); int to_length = strlen(to); gchar* loc_substr = NULL; if ((loc_substr = strstr(str, from))) { int head_size = loc_substr - str; int tail_size = str_length - head_size - from_length + 1; g_assert(str_length + to_length - from_length + 1 > 0); resultant = (gchar*)malloc(str_length + to_length - from_length + 1); // copy the beginning of the string memcpy(resultant, str, head_size); // copy the replacement memcpy(head_size + resultant, to, to_length); // copy the tail (+1 for 0x00) memcpy(head_size + resultant + to_length, loc_substr + from_length, tail_size); return resultant; } else { return g_strdup(str); }}