static gboolean tf_getent_group(gchar *key, gchar *member_name, GString *result) { struct group grp; struct group *res; char *buf; long bufsize; int s; gint64 d; gboolean is_num, r; bufsize = 16384; buf = g_malloc(bufsize); if ((is_num = parse_dec_number(key, &d)) == TRUE) s = getgrgid_r((gid_t)d, &grp, buf, bufsize, &res); else s = getgrnam_r(key, &grp, buf, bufsize, &res); if (res == NULL && s != 0) { msg_error("$(getent group) failed", evt_tag_str("key", key), evt_tag_error("errno")); g_free(buf); return FALSE; } if (member_name == NULL) { if (is_num) member_name = "name"; else member_name = "gid"; } if (res == NULL) { g_free(buf); return FALSE; } s = _find_formatter(group_field_map, member_name); if (s == -1) { msg_error("$(getent group): unknown member", evt_tag_str("key", key), evt_tag_str("member", member_name)); g_free(buf); return FALSE; } r = group_field_map[s].format(member_name, ((uint8_t *)res) + group_field_map[s].offset, result); g_free(buf); return r; }
/** * g_process_enable_cap: * @capability: capability to turn on * * This function modifies the current permitted set of capabilities by * enabling the capability specified in @capability. * * Returns: whether the operation was successful. **/ gboolean g_process_enable_cap(const gchar *cap_name) { if (!g_process_is_cap_enabled()) return TRUE; cap_value_t capability; cap_result_type ret = _check_and_get_cap_from_text(cap_name, &capability); if (CAP_SUPPORTED != ret) return FALSE; /* * if libcap or kernel doesn't support cap_syslog, then resort to * cap_sys_admin */ if (capability == cap_syslog && !have_capsyslog) { ret = _check_and_get_cap_from_text("cap_sys_admin", &capability); if (ret != CAP_SUPPORTED) return FALSE; } cap_t caps = cap_get_proc(); if (!caps) return FALSE; if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &capability, CAP_SET) == -1) { goto error; } if (cap_set_proc(caps) == -1) { goto error; } cap_free(caps); return TRUE; error: msg_error("Error managing capability set", evt_tag_cap_t("caps", caps), evt_tag_error("error")); cap_free(caps); return FALSE; }
/** * cap_restore: * @r: capability set saved by cap_save() * * Restore the set of current capabilities specified by @r. * * Returns: whether the operation was successful. **/ void g_process_cap_restore(cap_t r) { gboolean rc; if (!g_process_is_cap_enabled()) return; rc = cap_set_proc(r) != -1; if (!rc) { msg_error("Error managing capability set, cap_set_proc returned an error", evt_tag_cap_t("caps", r), evt_tag_error("error")); } cap_free(r); }
static gboolean _setup_reuseport(gint fd) { #ifdef SO_REUSEPORT gint on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0) { msg_error("The kernel refused our SO_REUSEPORT setting, which should be supported by Linux 3.9+", evt_tag_error("error")); return FALSE; } return TRUE; #else msg_error("You enabled so-reuseport(), but your platform does not support SO_REUSEPORT socket option, which should be supported on Linux 3.9+"); return FALSE; #endif }
gboolean confgen_exec_generate(CfgBlockGenerator *s, GlobalConfig *cfg, CfgArgs *args, GString *result, const gchar *reference) { ConfgenExec *self = (ConfgenExec *) s; FILE *out; gchar buf[256]; gint res; g_snprintf(buf, sizeof(buf), "%s confgen %s", cfg_lexer_lookup_context_name_by_type(self->super.context), self->super.name); cfg_args_foreach(args, confgen_set_args_as_env, NULL); out = popen(self->exec, "r"); cfg_args_foreach(args, confgen_unset_args_from_env, NULL); if (!out) { msg_error("confgen: Error executing generator program", evt_tag_str("reference", reference), evt_tag_str("context", cfg_lexer_lookup_context_name_by_type(self->super.context)), evt_tag_str("block", self->super.name), evt_tag_str("exec", self->exec), evt_tag_error("error")); return FALSE; } _read_program_output(out, result); res = pclose(out); if (res != 0) { msg_error("confgen: Generator program returned with non-zero exit code", evt_tag_str("reference", reference), evt_tag_str("context", cfg_lexer_lookup_context_name_by_type(self->super.context)), evt_tag_str("block", self->super.name), evt_tag_str("exec", self->exec), evt_tag_int("rc", res)); return FALSE; } msg_debug("confgen: output from the executed program to be included is", evt_tag_printf("block", "%.*s", (gint) result->len, result->str)); return TRUE; }
gboolean cfg_lexer_include_file(CfgLexer *self, const gchar *filename_) { struct stat st; gchar *filename; if (self->include_depth >= MAX_INCLUDE_DEPTH - 1) { msg_error("Include file depth is too deep, increase MAX_INCLUDE_DEPTH and recompile", evt_tag_str("filename", filename_), evt_tag_int("depth", self->include_depth)); return FALSE; } filename = find_file_in_path(_get_include_path(self), filename_, G_FILE_TEST_EXISTS); if (!filename || stat(filename, &st) < 0) { if (filename) g_free(filename); if (cfg_lexer_include_file_glob(self, filename_)) return TRUE; msg_error("Include file/directory not found", evt_tag_str("filename", filename_), evt_tag_str("include-path", _get_include_path(self)), evt_tag_error("error")); return FALSE; } else { gboolean result; result = cfg_lexer_include_file_simple(self, filename); g_free(filename); return result; } }
static void control_connection_io_output(gpointer s) { ControlConnection *self = (ControlConnection *) s; gint rc; rc = self->write(self, self->output_buffer->str + self->pos, self->output_buffer->len - self->pos); if (rc < 0) { if (errno != EAGAIN) { msg_error("Error writing control channel", evt_tag_error("error")); control_server_connection_closed(self->server, self); return; } } else { self->pos += rc; } control_connection_update_watches(self); }
static void control_connection_io_input(void *s) { ControlConnection *self = (ControlConnection *) s; GString *command = NULL; gchar *nl; gint rc; gint orig_len; GList *iter; if (self->input_buffer->len > MAX_CONTROL_LINE_LENGTH) { /* too much data in input, drop the connection */ msg_error("Too much data in the control socket input buffer"); control_server_connection_closed(self->server, self); return; } orig_len = self->input_buffer->len; /* NOTE: plus one for the terminating NUL */ g_string_set_size(self->input_buffer, self->input_buffer->len + 128 + 1); rc = self->read(self, self->input_buffer->str + orig_len, 128); if (rc < 0) { if (errno != EAGAIN) { msg_error("Error reading command on control channel, closing control channel", evt_tag_error("error")); goto destroy_connection; } /* EAGAIN, should try again when data comes */ control_connection_update_watches(self); return; } else if (rc == 0) { msg_debug("EOF on control channel, closing connection"); goto destroy_connection; } else { self->input_buffer->len = orig_len + rc; self->input_buffer->str[self->input_buffer->len] = 0; } /* here we have finished reading the input, check if there's a newline somewhere */ nl = strchr(self->input_buffer->str, '\n'); if (nl) { command = g_string_sized_new(128); /* command doesn't contain NL */ g_string_assign_len(command, self->input_buffer->str, nl - self->input_buffer->str); secret_storage_wipe(self->input_buffer->str, nl - self->input_buffer->str); /* strip NL */ /*g_string_erase(self->input_buffer, 0, command->len + 1);*/ g_string_truncate(self->input_buffer, 0); } else { /* no EOL in the input buffer, wait for more data */ control_connection_update_watches(self); return; } iter = g_list_find_custom(get_control_command_list(), command->str, (GCompareFunc)control_command_start_with_command); if (iter == NULL) { msg_error("Unknown command read on control channel, closing control channel", evt_tag_str("command", command->str)); g_string_free(command, TRUE); goto destroy_connection; } ControlCommand *cmd_desc = (ControlCommand *) iter->data; cmd_desc->func(self, command, cmd_desc->user_data); control_connection_wait_for_output(self); secret_storage_wipe(command->str, command->len); g_string_free(command, TRUE); return; destroy_connection: control_server_connection_closed(self->server, self); }