diff --git a/src/pokey/interface.c b/src/pokey/interface.c new file mode 100644 index 00000000..26eda41b --- /dev/null +++ b/src/pokey/interface.c @@ -0,0 +1,666 @@ +#include "config.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "node.h" +#include "edge.h" +#include "interface.h" + +#include + +#include "system.h" + +extern GladeXML *xml; + +#ifdef MAXBUFSIZE +#undef MAXBUFSIZE +#endif + +#define MAXBUFSIZE 1024 + +int build_graph = 0; + +static GdkColormap *colormap = NULL; +static GdkColor timecolor; + +#define MAX_NODES 25 +#define K 10.0 + +#ifdef INFINITY +#undef INFINITY +#endif +#define INFINITY 1.0e10 + +node_t *nodes[MAX_NODES]; +double x[MAX_NODES]; +double y[MAX_NODES]; +double k[MAX_NODES][MAX_NODES]; +double d[MAX_NODES][MAX_NODES]; +double l[MAX_NODES][MAX_NODES]; +const double epsilon = 0.001; + +static int inited = 0; + +static int number_of_nodes = 0; + +static GtkWidget *nodetree; +static GtkCTreeNode *subnets_ctn, *hosts_ctn, *conns_ctn; + +static GnomeCanvasGroup *edge_group = NULL; + +static int canvas_width; +static int canvas_height; + +static GtkWidget *canvas = NULL; + +GtkWidget *create_canvas(void) +{ + GtkWidget *w; + + gtk_widget_push_visual(gdk_rgb_get_visual()); + gtk_widget_push_colormap(gdk_rgb_get_cmap()); + + canvas = gnome_canvas_new_aa(); + + gtk_widget_pop_visual(); + gtk_widget_pop_colormap(); + + gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas), 0, 0, 500, 300); + + w = glade_xml_get_widget(xml, "scrolledwindow3"); + if(!w) + { + fprintf(stderr, "Could not find widget `scrolledwindow3'\n"); + return NULL; + } + gtk_container_add(GTK_CONTAINER(w), canvas); + gtk_widget_show_all(w); + + canvas_width = 300.0; + canvas_height = 500.0; + + return canvas; +} + +int init_interface(void) +{ + char *l[1]; + GtkArg p; + + if(!xml) + return -1; + + nodetree = glade_xml_get_widget(xml, "NodeTree"); + if(!nodetree) + { + fprintf(stderr, _("Could not find widget `NodeTree'\n")); + return -1; + } + + gtk_clist_freeze(GTK_CLIST(nodetree)); + + l[0] = _("Hosts"); + hosts_ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree), + NULL, NULL, l, 1, + NULL, NULL, NULL, NULL, + FALSE, TRUE); + l[0] = _("Subnets"); + subnets_ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree), + NULL, NULL, l, 1, + NULL, NULL, NULL, NULL, + FALSE, TRUE); + l[0] = _("Connections"); + conns_ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree), + NULL, NULL, l, 1, + NULL, NULL, NULL, NULL, + FALSE, TRUE); + + gtk_clist_thaw(GTK_CLIST(nodetree)); + + create_canvas(); + + return 0; +} + +void log_message(int severity, const char *fmt, ...) +{ + va_list args; + char buffer1[MAXBUFSIZE]; + char buffer2[MAXBUFSIZE]; + GtkWidget *w; + int len; + char *p; + struct tm *tm; + time_t t; + static int inited = 0; + + if(!xml) + return; + + w = glade_xml_get_widget(xml, "Messages"); + if(!w) + return; + + /* Use vsnprintf instead of vasprintf: faster, no memory + fragmentation, cleanup is automatic, and there is a limit on the + input buffer anyway */ + va_start(args, fmt); + len = vsnprintf(buffer1, MAXBUFSIZE, fmt, args); + va_end(args); + + buffer1[MAXBUFSIZE-1] = '\0'; + if((p = strrchr(buffer1, '\n'))) + *p = '\0'; + + t = time(NULL); + tm = localtime(&t); + snprintf(buffer2, MAXBUFSIZE, "%02d:%02d:%02d ", + tm->tm_hour, tm->tm_min, tm->tm_sec); + + if(!colormap) + { + colormap = gdk_colormap_new(gdk_visual_get_system(), FALSE); + timecolor.red = 0xffff; + timecolor.green = 0; + timecolor.blue = 0; + if(gdk_colormap_alloc_color(colormap, &timecolor, FALSE, TRUE) != TRUE) + { + fprintf(stderr, "Failed to allocate color\n"); + exit(1); + } + } + + gtk_text_freeze(GTK_TEXT(w)); + + if(inited) + gtk_text_insert(GTK_TEXT(w), NULL, NULL, NULL, "\n", 1); + + gtk_text_insert(GTK_TEXT(w), NULL, &timecolor, NULL, buffer2, strlen(buffer2)); + gtk_text_insert(GTK_TEXT(w), NULL, NULL, NULL, buffer1, len); + gtk_text_thaw(GTK_TEXT(w)); + + inited = 1; +} + +static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) +{ + static double item_x, old_x, new_x, item_y, old_y, new_y; + static int dragging = FALSE; + GdkCursor *fleur; + node_t *n; + + item_x = event->button.x; + item_y = event->button.y; + gnome_canvas_item_w2i(item->parent, &item_x, &item_y); + + switch(event->type) + { + case GDK_BUTTON_PRESS: + switch(event->button.button) + { + case 1: + old_x = item_x; + old_y = item_y; + + fleur = gdk_cursor_new(GDK_FLEUR); + gnome_canvas_item_grab(item, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, fleur, event->button.time); + gdk_cursor_destroy(fleur); + dragging = TRUE; + break; + + default: + break; + } + break; + + case GDK_MOTION_NOTIFY: + if(dragging && (event->motion.state & GDK_BUTTON1_MASK)) + { + new_x = item_x, + new_y = item_y; + gnome_canvas_item_move(item, new_x - old_x, new_y - old_y); + old_x = new_x; + old_y = new_y; + } + break; + + case GDK_BUTTON_RELEASE: + gnome_canvas_item_ungrab(item, event->button.time); + dragging = FALSE; + n = (node_t *)gtk_object_get_user_data(GTK_OBJECT(item)); + n->x = item_x; + n->y = item_y; + x[n->id] = item_x; + y[n->id] = item_y; + build_graph = 1; + break; + + default: + break; + } + return FALSE; +} + +GtkCTreeNode *if_node_add(node_t *n) +{ + char *l[1]; + GtkCTreeNode *ctn; + + if(!xml) + return NULL; + + l[0] = n->name; + gtk_clist_freeze(GTK_CLIST(nodetree)); + n->host_ctn = gtk_ctree_insert_node(GTK_CTREE(nodetree), + hosts_ctn, NULL, l, 1, + NULL, NULL, NULL, NULL, + FALSE, FALSE); + gtk_clist_thaw(GTK_CLIST(nodetree)); + + if_graph_add_node(n); + + inited = 0; + build_graph = 1; + + return ctn; +} + +void if_node_del(node_t *n) +{ + gtk_clist_freeze(GTK_CLIST(nodetree)); + if(n->host_ctn) + gtk_ctree_remove_node(GTK_CTREE(nodetree), n->host_ctn); + if(n->conn_ctn) + gtk_ctree_remove_node(GTK_CTREE(nodetree), n->conn_ctn); + if(n->subnet_ctn) + gtk_ctree_remove_node(GTK_CTREE(nodetree), n->subnet_ctn); + gtk_clist_thaw(GTK_CLIST(nodetree)); +} + +void if_subnet_add(subnet_t *subnet) +{ + char *l[1]; + + l[0] = net2str(subnet); + gtk_clist_freeze(GTK_CLIST(nodetree)); + gtk_ctree_insert_node(GTK_CTREE(nodetree), + subnets_ctn, NULL, l, 1, + NULL, NULL, NULL, NULL, + TRUE, FALSE); + gtk_clist_thaw(GTK_CLIST(nodetree)); +} + +void if_subnet_del(subnet_t *subnet) +{ +} + +void redraw_edges(void) +{ + GnomeCanvasGroup *group; + GnomeCanvasPoints *points; + avl_node_t *avlnode; + edge_t *e; + + if(edge_group) + gtk_object_destroy(GTK_OBJECT(edge_group)); + + group = gnome_canvas_root(GNOME_CANVAS(canvas)); + group = GNOME_CANVAS_GROUP(gnome_canvas_item_new(group, + gnome_canvas_group_get_type(), + "x", 0.0, + "y", 0.0, + NULL)); + + for(avlnode = edge_tree->head; avlnode; avlnode = avlnode->next) + { +/* char s[12]; */ + e = (edge_t *)avlnode->data; + + points = gnome_canvas_points_new(2); + + points->coords[0] = e->from.node->x; + points->coords[1] = e->from.node->y; + points->coords[2] = e->to.node->x; + points->coords[3] = e->to.node->y; + gnome_canvas_item_new(group, + gnome_canvas_line_get_type(), + "points", points, + "fill_color_rgba", 0xe080c0ff, + "width_pixels", 2, + NULL); + gnome_canvas_points_unref(points); +/* snprintf(s, sizeof(s) - 1, "%d", e->weight); */ +/* gnome_canvas_item_new(group, */ +/* gnome_canvas_text_get_type(), */ +/* "x", (e->from.node->x + e->to.node->x) / 2, */ +/* "y", (e->from.node->y + e->to.node->y) / 2, */ +/* "text", s, */ +/* "anchor", GTK_ANCHOR_CENTER, */ +/* "fill_color", "black", */ +/* "font", "-*-verdana-medium-r-*-*-8-*-*-*-*-*-iso8859-1", */ +/* /\* "font", "fixed", *\/ */ +/* NULL); */ + } + + edge_group = group; +} + +void if_edge_add(edge_t *e) +{ + redraw_edges(); + if_graph_add_edge(e); + inited = 0; + build_graph = 1; + +} + +void if_edge_del(edge_t *e) +{ + redraw_edges(); + inited = 0; + build_graph = 1; + +} + +void if_graph_add_node(node_t *n) +{ + GnomeCanvasGroup *group; + double newx, newy; + + if(!canvas) + if(!create_canvas()) + return; + + group = gnome_canvas_root(GNOME_CANVAS(canvas)); + group = GNOME_CANVAS_GROUP(gnome_canvas_item_new(group, + gnome_canvas_group_get_type(), + "x", 0.0, + "y", 0.0, + NULL)); + + gnome_canvas_item_new(group, gnome_canvas_ellipse_get_type(), + "x1", -30.0, + "y1", -08.0, + "x2", 30.0, + "y2", 08.0, + "fill_color_rgba", 0x5f9ea0ff, + "outline_color", "black", + "width_pixels", 0, + NULL); + + gnome_canvas_item_new(group, + gnome_canvas_text_get_type(), + "x", 0.0, + "y", 0.0, + "text", n->name, + "anchor", GTK_ANCHOR_CENTER, + "fill_color", "white", + "font", "-*-verdana-medium-r-*-*-10-*-*-*-*-*-iso8859-1", +/* "font", "fixed", */ + NULL); + + n->item = GNOME_CANVAS_ITEM(group); + gtk_object_set_user_data(GTK_OBJECT(group), (gpointer)n); + + /* TODO: Use this to get more detailed info on a node (For example + popup a dialog with more info, select the node in the left + pane, whatever.) */ + gtk_signal_connect(GTK_OBJECT(n->item), "event", (GtkSignalFunc) item_event, NULL); + + newx = 250.0 + 200.0 * sin(number_of_nodes / 10.0 * M_PI); + newy = 150.0 - 100.0 * cos(number_of_nodes / 10.0 * M_PI); +/* newx = (double)random() / (double)RAND_MAX * 300.0 + 100.0; */ +/* newy = (double)random() / (double)RAND_MAX * 200.0 + 50.0; */ + gnome_canvas_item_move(GNOME_CANVAS_ITEM(n->item), newx, newy); + n->x = newx; + n->y = newy; + + x[number_of_nodes] = newx; + y[number_of_nodes] = newy; + nodes[number_of_nodes] = n; + n->id = number_of_nodes; + + number_of_nodes++; + + gnome_canvas_update_now(GNOME_CANVAS(canvas)); +} + +void if_move_node(node_t *n, double dx, double dy) +{ + double newx, newy; + + newx = n->x + dx; + newy = n->y + dy; + gnome_canvas_item_move(GNOME_CANVAS_ITEM(n->item), newx - n->x, newy - n->y); + n->x = newx; + n->y = newy; +} + +void if_graph_add_edge(edge_t *e) +{ +/* e->from.node->ifn->nat++; */ +/* e->to.node->ifn->nat++; */ + +/* avl_insert(e->from.node->ifn->attractors, e->to.node); */ +/* avl_insert(e->to.node->ifn->attractors, e->from.node); */ + + redraw_edges(); + + build_graph = 1; +} + +#define X_MARGIN 50.0 +#define X_MARGIN_BUFFER 25.0 +#define Y_MARGIN 20.0 +#define Y_MARGIN_BUFFER 10.0 + +void set_zooming(void) +{ + int i; + double minx, miny, maxx, maxy; + static double ominx = 0.0, ominy = 0.0, omaxx = 0.0, omaxy = 0.0; + double ppu, ppux, ppuy; + + minx = miny = maxx = maxy = 0.0; + for(i = 0; i < number_of_nodes; i++) + { + if(nodes[i]->x < minx) + minx = nodes[i]->x; + else + if(nodes[i]->x > maxx) + maxx = nodes[i]->x; + + if(nodes[i]->y < miny) + miny = nodes[i]->y; + else + if(nodes[i]->y > maxy) + maxy = nodes[i]->y; + } + + if(minx > ominx - X_MARGIN_BUFFER && ominx > minx) + minx = ominx; + if(maxx < omaxx + X_MARGIN_BUFFER && omaxx < maxx) + maxx = omaxx; + if(miny > ominy - Y_MARGIN_BUFFER && ominy > miny) + miny = ominy; + if(maxy < omaxy + Y_MARGIN_BUFFER && omaxy < maxy) + maxy = omaxy; + + ominx = minx; ominy = miny; omaxx = maxx; omaxy = maxy; + +/* ppux = canvas_width / (maxx - minx); */ +/* ppuy = canvas_height / (maxy - miny); */ +/* if(ppux < ppuy) */ +/* ppu = ppux; */ +/* else */ +/* ppu = ppuy; */ + +/* gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas), ppu); */ + gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas), minx - X_MARGIN, miny - Y_MARGIN, maxx + X_MARGIN, maxy + Y_MARGIN); +} + +double calculate_delta_m(int m) +{ + double dedxm, dedym, xmxi, ymyi; + int i; + + dedxm = dedym = 0.0; + for(i = 0; i < number_of_nodes; i++) + { + if(i == m) + continue; + + xmxi = x[m] - x[i]; + ymyi = y[m] - y[i]; + + dedxm += k[m][i] * (xmxi - ((l[m][i] * xmxi) / sqrt(xmxi * xmxi + ymyi * ymyi))); + dedym += k[m][i] * (xmxi - ((l[m][i] * xmxi) / sqrt(xmxi * xmxi + ymyi * ymyi))); + } + + return sqrt(dedxm * dedxm + dedym * dedym); +} + +void move_node(int m, double *dx, double *dy) +{ + double d2edxm2, d2edym2, d2edxmdym, dedxm, dedym; + double xmxi, ymyi, denominator; + int i; + + d2edxm2 = d2edym2 = d2edxmdym = dedxm = dedym = 0.0; + for(i = 0; i < number_of_nodes; i++) + { + if(i == m) + continue; + + xmxi = x[m] - x[i]; + ymyi = y[m] - y[i]; + + denominator = pow(sqrt(xmxi * xmxi + ymyi * ymyi), 3.0); + + d2edxm2 += k[m][i] * (1 - ((l[m][i] * ymyi * ymyi) / denominator)); + d2edxmdym += k[m][i] * l[m][i] * xmxi * ymyi / denominator; + d2edym2 += k[m][i] * (1 - ((l[m][i] * xmxi * xmxi) / denominator)); + dedxm += k[m][i] * (xmxi - ((l[m][i] * xmxi) / sqrt(xmxi * xmxi + ymyi * ymyi))); + dedym += k[m][i] * (ymyi - ((l[m][i] * ymyi) / sqrt(xmxi * xmxi + ymyi * ymyi))); + } + + denominator = ((d2edxm2 * d2edym2) - (d2edxmdym * d2edxmdym)); + *dx = (-(d2edym2 * dedxm) + (d2edxmdym * dedym)) / denominator; + *dy = ((d2edxmdym * dedxm) - (d2edxm2 * dedym)) / denominator; +} + +void if_build_graph(void) +{ + int i, j, p, max_i; + double delta_m, max_delta_m; + double dx, dy, s, L, max_d, old_x, old_y; + edge_t *e; + + if(!inited) + { + for(i = 0; i < number_of_nodes; i++) + { + d[i][i] = 0.0; + for(j = i + 1; j < number_of_nodes; j++) + { + e = lookup_edge(nodes[i], nodes[j]); + if(e) + d[i][j] = d[j][i] = (double)e->weight; + else + d[i][j] = d[j][i] = INFINITY; + } + } + for(i = 0; i < number_of_nodes; i++) + { + for(j = 0; j < number_of_nodes; j++) + { + if(i == j) + continue; + + if(d[j][i] < INFINITY) + { + for(p = 0; p < number_of_nodes; p++) + { + if(d[i][j] < INFINITY) + { + s = d[j][i] + d[i][p]; + if(s < d[j][p]) + { + d[j][p] = s; + } + } + } + } + } + } + + max_d = 0.0; + for(i = 0; i < number_of_nodes; i++) + for(j = i + 1; j < number_of_nodes; j++) + if(d[i][j] > max_d && d[i][j] < INFINITY) + max_d = d[i][j]; + + L = 300.0 / log(max_d); + + for(i = 0; i < number_of_nodes; i++) + { + for(j = i + 1; j < number_of_nodes; j++) + { + d[i][j] = d[j][i] = log(d[i][j]+1.0); + l[i][j] = l[j][i] = L * d[i][j]; + k[i][j] = k[j][i] = K / (d[i][j] * d[i][j]); + } + } + + inited = 1; + } + + max_delta_m = 0.0; + /* Find node with maximal local energy */ + for(i = 0; i < number_of_nodes; i++) + { + delta_m = calculate_delta_m(i); + if(delta_m > max_delta_m) + { + max_delta_m = delta_m; + max_i = i; + } + } + + if(max_delta_m <= epsilon) + build_graph = 0; + else + { + int iter = 0, maxiter = 20; + delta_m = max_delta_m; + old_x = x[max_i]; + old_y = y[max_i]; + while(delta_m > epsilon && iter < maxiter) + { + move_node(max_i, &dx, &dy); + x[max_i] += dx; + y[max_i] += dy; + delta_m = calculate_delta_m(max_i); + iter++; + } + + if_move_node(nodes[max_i], x[max_i] - old_x, y[max_i] - old_y); + + redraw_edges(); + + set_zooming(); + } + +/* build_graph = 0; */ +} diff --git a/src/pokey/interface.h b/src/pokey/interface.h new file mode 100644 index 00000000..199ca516 --- /dev/null +++ b/src/pokey/interface.h @@ -0,0 +1,55 @@ +/* + interface.h -- header for interface.c + Copyright (C) 2002 Guus Sliepen , + 2002 Ivo Timmermans + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: interface.h,v 1.1 2002/04/11 14:23:56 zarq Exp $ +*/ + +#ifndef __TINC_INTERFACE_H__ +#define __TINC_INTERFACE_H__ + +#include + +#include "node.h" +#include "edge.h" + +typedef struct graph_t { + struct graph_t *attractors[20]; + struct graph_t *repellors[20]; + int nat; + int nrp; + node_t *node; +} graph_t; + +extern int build_graph; + +void log_message(int, const char *, ...); +GtkCTreeNode *if_node_add(node_t *); +void if_node_del(node_t *); +void if_subnet_add(subnet_t *); +void if_subnet_del(subnet_t *); +void if_edge_add(edge_t *); +void if_edge_del(edge_t *); + +void if_build_graph(void); +void if_graph_add_node(node_t *); +void if_graph_add_edge(edge_t *); + +int init_interface(void); + +#endif /* __TINC_INTERFACE_H__ */ diff --git a/src/pokey/pokey.c b/src/pokey/pokey.c new file mode 100644 index 00000000..a2385a7f --- /dev/null +++ b/src/pokey/pokey.c @@ -0,0 +1,374 @@ +/* + tincd.c -- the main file for tincd + Copyright (C) 1998-2002 Ivo Timmermans + 2000-2002 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: pokey.c,v 1.1 2002/04/11 14:23:56 zarq Exp $ +*/ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_IOCTL_H +# include +#endif + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "conf.h" +#include "interface.h" +#include "net.h" +#include "netutl.h" +#include "process.h" +#include "protocol.h" +#include "subnet.h" + +#include "system.h" + +/* The name this program was run with. */ +char *program_name; + +/* If nonzero, display usage information and exit. */ +int show_help; + +/* If nonzero, print the version on standard output and exit. */ +int show_version; + +/* If nonzero, it will attempt to kill a running tincd and exit. */ +int kill_tincd = 0; + +/* If nonzero, generate public/private keypair for this host/net. */ +int generate_keys = 0; + +/* If nonzero, use null ciphers and skip all key exchanges. */ +int bypass_security = 0; + +char *identname; /* program name for syslog */ +char *pidfilename; /* pid file location */ +char **g_argv; /* a copy of the cmdline arguments */ +char **environment; /* A pointer to the environment on startup */ + +/* GTK Interface */ +GladeXML *xml = NULL; + + +static struct option const long_options[] = +{ + { "config", required_argument, NULL, 'c' }, + { "kill", optional_argument, NULL, 'k' }, + { "net", required_argument, NULL, 'n' }, + { "help", no_argument, &show_help, 1 }, + { "version", no_argument, &show_version, 1 }, + { "no-detach", no_argument, &do_detach, 0 }, + { "generate-keys", optional_argument, NULL, 'K'}, + { "debug", optional_argument, NULL, 'd'}, + { "bypass-security", no_argument, &bypass_security, 1 }, + { NULL, 0, NULL, 0 } +}; + +static void +usage(int status) +{ + if(status != 0) + fprintf(stderr, _("Try `%s --help\' for more information.\n"), program_name); + else + { + printf(_("Usage: %s [option]...\n\n"), program_name); + printf(_(" -c, --config=DIR Read configuration options from DIR.\n" + " -D, --no-detach Don't fork and detach.\n" + " -d, --debug[=LEVEL] Increase debug level or set it to LEVEL.\n" + " -k, --kill[=SIGNAL] Attempt to kill a running tincd and exit.\n" + " -n, --net=NETNAME Connect to net NETNAME.\n")); + printf(_(" -K, --generate-keys[=BITS] Generate public/private RSA keypair.\n" + " --help Display this help and exit.\n" + " --version Output version information and exit.\n\n")); + printf(_("Report bugs to tinc@nl.linux.org.\n")); + } + exit(status); +} + +void +parse_options(int argc, char **argv, char **envp) +{ + int r; + int option_index = 0; + + while((r = getopt_long(argc, argv, "c:Dd::k::n:K::", long_options, &option_index)) != EOF) + { + switch(r) + { + case 0: /* long option */ + break; + case 'c': /* config file */ + confbase = xmalloc(strlen(optarg)+1); + strcpy(confbase, optarg); + break; + case 'D': /* no detach */ + do_detach = 0; + break; + case 'd': /* inc debug level */ + if(optarg) + debug_lvl = atoi(optarg); + else + debug_lvl++; + break; + case 'k': /* kill old tincds */ + kill_tincd = optarg?atoi(optarg):SIGTERM; + break; + case 'n': /* net name given */ + netname = xmalloc(strlen(optarg)+1); + strcpy(netname, optarg); + break; + case 'K': /* generate public/private keypair */ + if(optarg) + { + generate_keys = atoi(optarg); + if(generate_keys < 512) + { + fprintf(stderr, _("Invalid argument `%s'; BITS must be a number equal to or greater than 512.\n"), + optarg); + usage(1); + } + generate_keys &= ~7; /* Round it to bytes */ + } + else + generate_keys = 1024; + break; + case '?': + usage(1); + default: + break; + } + } +} + +/* This function prettyprints the key generation process */ + +void indicator(int a, int b, void *p) +{ + switch(a) + { + case 0: + fprintf(stderr, "."); + break; + case 1: + fprintf(stderr, "+"); + break; + case 2: + fprintf(stderr, "-"); + break; + case 3: + switch(b) + { + case 0: + fprintf(stderr, " p\n"); + break; + case 1: + fprintf(stderr, " q\n"); + break; + default: + fprintf(stderr, "?"); + } + break; + default: + fprintf(stderr, "?"); + } +} + +/* + Generate a public/private RSA keypair, and ask for a file to store + them in. +*/ +int keygen(int bits) +{ + RSA *rsa_key; + FILE *f; + char *name = NULL; + char *filename; + + fprintf(stderr, _("Generating %d bits keys:\n"), bits); + rsa_key = RSA_generate_key(bits, 0xFFFF, indicator, NULL); + + if(!rsa_key) + { + fprintf(stderr, _("Error during key generation!\n")); + return -1; + } + else + fprintf(stderr, _("Done.\n")); + + get_config_string(lookup_config(config_tree, "Name"), &name); + + if(name) + asprintf(&filename, "%s/hosts/%s", confbase, name); + else + asprintf(&filename, "%s/rsa_key.pub", confbase); + + if((f = ask_and_safe_open(filename, _("public RSA key"), "a")) == NULL) + return -1; + + if(ftell(f)) + fprintf(stderr, _("Appending key to existing contents.\nMake sure only one key is stored in the file.\n")); + + PEM_write_RSAPublicKey(f, rsa_key); + fclose(f); + free(filename); + + asprintf(&filename, "%s/rsa_key.priv", confbase); + if((f = ask_and_safe_open(filename, _("private RSA key"), "a")) == NULL) + return -1; + + if(ftell(f)) + fprintf(stderr, _("Appending key to existing contents.\nMake sure only one key is stored in the file.\n")); + + PEM_write_RSAPrivateKey(f, rsa_key, NULL, NULL, 0, NULL, NULL); + fclose(f); + free(filename); + + return 0; +} + +/* + Set all files and paths according to netname +*/ +void make_names(void) +{ + if(netname) + { + if(!pidfilename) + asprintf(&pidfilename, LOCALSTATEDIR "/run/tinc.%s.pid", netname); + if(!confbase) + asprintf(&confbase, "%s/tinc/%s", CONFDIR, netname); + else + log_message(LOG_INFO, _("Both netname and configuration directory given, using the latter...")); + if(!identname) + asprintf(&identname, "tinc.%s", netname); + } + else + { + if(!pidfilename) + pidfilename = LOCALSTATEDIR "/run/tinc.pid"; + if(!confbase) + asprintf(&confbase, "%s/tinc", CONFDIR); + if(!identname) + identname = "tinc"; + } +} + +int +main(int argc, char **argv, char **envp) +{ + char *fake_argv[] = { argv[0], NULL }; + program_name = argv[0]; + + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + environment = envp; + parse_options(argc, argv, envp); + + if(show_version) + { + printf(_("%s version %s (built %s %s, protocol %d)\n"), PACKAGE, VERSION, __DATE__, __TIME__, PROT_CURRENT); + printf(_("Copyright (C) 1998-2002 Ivo Timmermans, Guus Sliepen and others.\n" + "See the AUTHORS file for a complete list.\n\n" + "tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n" + "and you are welcome to redistribute it under certain conditions;\n" + "see the file COPYING for details.\n")); + + return 0; + } + + if(show_help) + usage(0); + + gnome_init("Pokey", "0.0", 1, fake_argv); + + glade_init(); + + xml = glade_xml_new("pokey.glade", NULL); + + if (!xml) { + g_warning("something bad happened while creating the interface"); + return 1; + } + +/* if(geteuid()) */ +/* { */ +/* fprintf(stderr, _("You must be root to run this program.\n")); */ +/* return 1; */ +/* } */ + + g_argv = argv; + + make_names(); + init_configuration(&config_tree); + + /* Slllluuuuuuurrrrp! */ +cp + RAND_load_file("/dev/urandom", 1024); + +#ifdef HAVE_SSLEAY_ADD_ALL_ALGORITHMS + SSLeay_add_all_algorithms(); +#else + OpenSSL_add_all_algorithms(); +#endif + +cp + if(read_server_config()) + exit(1); +cp + setup_signals(); + + if(init_interface()) + { + fprintf(stderr, _("Could not setup all necessary interface elements.\n")); + exit(1); + } + + if(!setup_network_connections()) + { + main_loop(); + cleanup_and_exit(1); + } + + log_message(LOG_ERR, _("Unrecoverable error")); + cp_trace(); + + return 1; +}