#include #include #include #include #include #include #include /* 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); }