#include <entity.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
/* We are using popen so we have to kill all the special
* chars in the command. */
static void normalize_resolve_cmd (gchar * resolve_cmd)
{
char * str;
str = resolve_cmd;
while (*str != '\0')
{
if ('\\' == *str ||
'\'' == *str ||
'\"' == *str ||
'*' == *str ||
'&' == *str ||
'#' == *str ||
'(' == *str ||
')' == *str ||
'|' == *str ||
'~' == *str ||
'\t' == *str ||
'$' == *str ||
'>' == *str ||
'<' == *str ||
'{' == *str ||
'}' == *str
)
{
*str = '_'; /* Assume that want _. :) */
}
str++;
}
}
static int
resolverrend_resolv_finished (gint fd, EIOCond cond, ENode * node)
{
FILE *fp; /* The file pointer to pclose on. */
char buf[2048]; /* buffer for read(2) to fill. */
int exit_val; /* the exit value of the child. */
int count; /* bytes read. */
int res; /* pclose(3) return. (exit status) */
gpointer tag; /* the tag to remove from the mainloop. */
gchar *function; /* The function to call with the data. */
fp = enode_get_kv(node, "resolver-fp");
tag = enode_get_kv(node, "resolver-io-tag");
count = read (fd, buf, 2047);
if (-1 == count) { /* Some sort of read error. */
EDEBUG(("resolver", "error reading hostname lookup '%s'",
strerror(errno) ));
buf[0] = '\0'; /* Make sure it looks like an empty string. */
} else {
if (buf[count - 1] == '\n') { /* Set the newline to nul. */
buf[count - 1] = '\0';
} else { /* Just set the end to nul. */
buf[count] = '\0';
}
}
entity_mainloop->io_remove (tag);
enode_set_kv (node, "resolver-io-tag", 0);
res = pclose(fp);
exit_val = WEXITSTATUS(res);
EDEBUG(("resolver", "child's exit value = %i", exit_val));
if (exit_val == EXIT_FAILURE) {
EDEBUG(("resolve", "child exited with failure status."));
enode_attrib_str (node, "error", buf);
enode_ref (node);
/* Call the error function and then the action one with no result,
* so even if they don't have an onerror function they know the lookup
* is finished. */
function = enode_attrib_str (node, "onerror", NULL);
enode_call_ignore_return (node, function, "s", buf);
/* The user may have destroyed that node... */
if (!ENODE_FLAG_ISSET (node, ENODE_DELETED)) {
function = enode_attrib_str (node, "action", NULL);
enode_call_ignore_return (node, function, "s", "");
}
enode_unref (node);
} else {
function = enode_attrib_str (node, "action", NULL);
enode_call_ignore_return (node, function, "s", buf);
}
return FALSE;
}
static void
resolverrend_render (ENode * node)
{
enode_attribs_sync (node);
}
static void
resolverrend_destroy (ENode *node)
{
gpointer tag;
tag = enode_get_kv (node, "resolver-io-tag");
if (tag) {
entity_mainloop->io_remove (tag);
}
}
static int
resolverrend_ip_attr_set (ENode * node, EBuf * attr, EBuf * value)
{
gchar resolve_cmd[15 + PATH_MAX + 4]; /* IP addr + command. */
FILE *fp;
int fd;
gpointer tag;
enode_attrib_str (node, "error", "");
snprintf (resolve_cmd, sizeof (resolve_cmd) - 1,
RESOLVER_BIN " -h %s", value->str);
/* Keep malicious code from being ran when we popen(3).
* resolve_cmd is changed in place. */
normalize_resolve_cmd (resolve_cmd);
EDEBUG(("resolver", "running popen"));
fp = popen(resolve_cmd, "r");
if(!fp) {
EDEBUG(("resolver", "error opening resolve command '%s'",
resolve_cmd));
return FALSE;
}
fd = fileno(fp);
tag = entity_mainloop->io_add (fd, EIO_READ | EIO_ERROR,
(void *) resolverrend_resolv_finished, node);
enode_set_kv (node, "resolver-io-tag", tag);
enode_set_kv (node, "resolver-fp", fp);
return TRUE;
}
static int
resolverrend_hostname_attr_set (ENode * node, EBuf * attr, EBuf * value)
{
gchar resolve_cmd[256 + PATH_MAX + 4]; /* hostname + command. */
FILE *fp;
int fd;
gpointer tag;
enode_attrib_str (node, "error", "");
snprintf (resolve_cmd, sizeof (resolve_cmd) - 1,
RESOLVER_BIN " -i %s", value->str);
/* Keep malicious code from being ran when we popen(3).
* resolve_cmd is changed in place. */
normalize_resolve_cmd (resolve_cmd);
EDEBUG(("resolver", "running popen"));
fp = popen(resolve_cmd, "r");
if(!fp) {
EDEBUG(("resolver", "error opening resolve command '%s'\n",
resolve_cmd));
return FALSE;
}
fd = fileno(fp);
tag = entity_mainloop->io_add (fd, EIO_READ | EIO_ERROR,
(void *) resolverrend_resolv_finished, node);
enode_set_kv (node, "resolver-io-tag", tag);
enode_set_kv (node, "resolver-fp", fp);
return TRUE;
}
void rendresolver_init (int flags)
{
Element *element;
ElementAttr *e_attr;
/* Register the resolver element */
element = g_new0 (Element, 1);
element->render_func = resolverrend_render;
element->destroy_func = resolverrend_destroy;
element->tag = "resolver";
element_register (element);
e_attr = g_new0 (ElementAttr, 1);
e_attr->attribute = "ip";
e_attr->description = "The ip address in \"dotted quad\" notation. "
"ex. 208.153.12.155.";
e_attr->value_desc = "string";
e_attr->set_attr_func = resolverrend_ip_attr_set;
element_register_attrib (element, e_attr);
e_attr = g_new0 (ElementAttr, 1);
e_attr->attribute = "hostname";
e_attr->description = "The hostname to get the ip address for";
e_attr->value_desc = "string";
e_attr->set_attr_func = resolverrend_hostname_attr_set;
element_register_attrib (element, e_attr);
e_attr = g_new0 (ElementAttr, 1);
e_attr->attribute = "error";
e_attr->description = "The error string if no result was found";
e_attr->value_desc = "string";
element_register_attrib (element, e_attr);
e_attr = g_new0 (ElementAttr, 1);
e_attr->attribute = "action";
e_attr->description = "Function to call when it is resolved";
e_attr->value_desc = "function";
e_attr->possible_values = "(resolver_node, result)";
element_register_attrib (element, e_attr);
e_attr = g_new0 (ElementAttr, 1);
e_attr->attribute = "onerror";
e_attr->description = "Function to call if an error occurs in the lookup";
e_attr->value_desc = "function";
e_attr->possible_values = "(resolver_node, error)";
element_register_attrib (element, e_attr);
}
syntax highlighted by Code2HTML, v. 0.9.1