Exemple #1
0
/*
  Read Subnets from all host config files
*/
void load_all_subnets(void) {
    DIR *dir;
    struct dirent *ent;
    char *dname;
    char *fname;
    avl_tree_t *config_tree;
    config_t *cfg;
    subnet_t *s, *s2;
    node_t *n;

    xasprintf(&dname, "%s/hosts", confbase);
    dir = opendir(dname);
    if(!dir) {
        logger(LOG_ERR, "Could not open %s: %s", dname, strerror(errno));
        free(dname);
        return;
    }

    while((ent = readdir(dir))) {
        if(!check_id(ent->d_name))
            continue;

        n = lookup_node(ent->d_name);
#ifdef _DIRENT_HAVE_D_TYPE
        //if(ent->d_type != DT_REG)
        //	continue;
#endif

        xasprintf(&fname, "%s/hosts/%s", confbase, ent->d_name);
        init_configuration(&config_tree);
        read_config_options(config_tree, ent->d_name);
        read_config_file(config_tree, fname);
        free(fname);

        if(!n) {
            n = new_node();
            n->name = xstrdup(ent->d_name);
            node_add(n);
        }

        for(cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
            if(!get_config_subnet(cfg, &s))
                continue;

            if((s2 = lookup_subnet(n, s))) {
                s2->expires = -1;
            } else {
                subnet_add(n, s);
            }
        }

        exit_configuration(&config_tree);
    }

    closedir(dir);
}
Exemple #2
0
bool read_connection_config(connection_t *c) {
	char *fname;
	bool x;

	read_config_options(c->config_tree, c->name);

	xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
	x = read_config_file(c->config_tree, fname);
	free(fname);

	return x;
}
/* Answering these questions right is tricky... */
static bool getconf_bool_node_offline(const char *nodename, char *optname) {
	char *fname;
	avl_tree_t *t;
	bool x;

	init_configuration(&t);

	xasprintf(&fname, "%s/hosts/%s", confbase, nodename);

	read_config_options(t, nodename);
	x = read_config_file(t, fname);
	if (!x) goto _end;

	if (!get_config_bool(lookup_config(t, optname), &x)) x = false;

_end:	exit_configuration(&t);
	free(fname);

	return x;
}
Exemple #4
0
bool read_server_config(void) {
	char *fname;
	bool x;

	read_config_options(config_tree, NULL);

	xasprintf(&fname, "%s/tinc.conf", confbase);
	x = read_config_file(config_tree, fname);

	// We will try to read the conf files in the "conf.d" dir
	if (x) {
		char * dname;
		xasprintf(&dname, "%s/conf.d", confbase);
		DIR *dir = opendir (dname);
		// If we can find this dir
		if (dir) { 
			struct dirent *ep;
			// We list all the files in it
			while (x && (ep = readdir (dir))) {
				size_t l = strlen(ep->d_name);
				// And we try to read the ones that end with ".conf"
				if (l > 5 && !strcmp(".conf", & ep->d_name[ l - 5 ])) {
					free(fname);
					xasprintf(&fname, "%s/%s", dname, ep->d_name);
					x = read_config_file(config_tree, fname);
				}
			}
			closedir (dir);
		}
		free(dname);
	}

	if(!x) {				/* System error: complain */
		logger(LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno));
	}

	free(fname);

	return x;
}
Exemple #5
0
int main(int argc, char *argv[]) {
	struct timeval now;
	char *conf_file = NULL;
	double begin_time, end_time;
	int num_rows;
	int device_counter = 0;
	int last_active_threads = 0;
	long int THREAD_SLEEP = 100000;
	time_t nowbin;
	const struct tm *nowstruct;

	pthread_t* threads = NULL;
	pthread_attr_t attr;
	pthread_mutexattr_t mutexattr;

	int* ids = NULL;
	MYSQL mysql;
	MYSQL_RES *result = NULL;
	MYSQL_ROW mysql_row;
	int canexit = 0;
	int host_id;
	int i;
	int mutex_status = 0;
	int thread_status = 0;
	char result_string[BUFSIZE] = "";
	char logmessage[LOGSIZE];

	/* set start time for cacti */
	gettimeofday(&now, NULL);
	begin_time = (double) now.tv_usec / 1000000 + now.tv_sec;

	/* get time for poller_output table */
	if (time(&nowbin) == (time_t) - 1)
		printf("ERROR: Could not get time of day from time()\n");

	nowstruct = localtime(&nowbin);

	if (strftime(start_datetime, sizeof(start_datetime), "%Y-%m-%d %H:%M:%S", nowstruct) == (size_t) 0)
		printf("ERROR: Could not get string from strftime()\n");

	set.verbose = POLLER_VERBOSITY_HIGH;

	/* get static defaults for system */
	config_defaults(&set);

	/* scan arguments for errors */
	if ((argc != 1) && (argc != 3)) {
		printf("ERROR: Cactid requires either 0 or 2 input parameters\n");
		printf("USAGE: <cactidpath>/cactid [start_id end_id]\n");
		exit(-1);
	}

	/* return error if the first arg is greater than the second */
	if (argc == 3) {
		if (atol(argv[1]) > atol(argv[2])) {
			printf("ERROR: Invalid row specifications.  First row must be less than the second row\n");
			exit(-2);
		}
	}

	/* read configuration file to establish local environment */
	if (conf_file) {
		if ((read_cactid_config(conf_file, &set)) < 0) {
			printf("ERROR: Could not read config file: %s\n", conf_file);
			exit(-3);
		}
	}else{
		conf_file = malloc(BUFSIZE);

		if (!conf_file) {
			printf("ERROR: Fatal malloc error!\n");
			exit(-1);
		}

		for(i=0;i<CONFIG_PATHS;i++) {
			snprintf(conf_file, BUFSIZE, "%s%s", config_paths[i], DEFAULT_CONF_FILE);

			if (read_cactid_config(conf_file, &set) >= 0) {
				break;
			}

			if (i == CONFIG_PATHS-1) {
				snprintf(conf_file, BUFSIZE, "%s%s", config_paths[0], DEFAULT_CONF_FILE);
			}
		}
	}

	/* read settings table from the database to further establish environment */
	read_config_options(&set);

	/* set the poller ID, stub for next version */
	set.poller_id = 0;

	if (set.verbose == POLLER_VERBOSITY_DEBUG) {
		snprintf(logmessage, LOGSIZE, "CACTID: Version %s starting\n", VERSION);
		cacti_log(logmessage);
	} else {
		printf("CACTID: Version %s starting\n", VERSION);
	}

	/* connect to database */
	db_connect(set.dbdb, &mysql);

	/* initialize SNMP */
	init_snmp("cactid");

	/* initialize PHP */
	php_init();

	/* get the id's to poll */
	switch (argc) {
		case 1:
			result = db_query(&mysql, "SELECT id FROM host WHERE disabled='' ORDER BY id");

			break;
		case 3:
			snprintf(result_string, sizeof(result_string), "SELECT id FROM host WHERE (disabled='' and (id >= %s and id <= %s)) ORDER BY id\0", argv[1], argv[2]);
			result = db_query(&mysql, result_string);

			break;
		default:
			break;
	}

	num_rows = mysql_num_rows(result);
	threads = (pthread_t *)malloc(num_rows * sizeof(pthread_t));
	ids = (int *)malloc(num_rows * sizeof(int));

	/* initialize threads and mutexes */
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

	init_mutexes();

	if (set.verbose == POLLER_VERBOSITY_DEBUG) {
		snprintf(logmessage, LOGSIZE, "DEBUG: Initial Value of Active Threads is %i\n", active_threads);
		cacti_log(logmessage);
	}

	/* loop through devices until done */
	while (device_counter < num_rows) {
		mutex_status = thread_mutex_trylock(LOCK_THREAD);

		switch (mutex_status) {
		case 0:
			if (last_active_threads != active_threads) {
				last_active_threads = active_threads;
			}

			while ((active_threads < set.threads) && (device_counter < num_rows)) {
				mysql_row = mysql_fetch_row(result);
				host_id = atoi(mysql_row[0]);
				ids[device_counter] = host_id;

				/* create child process */
				thread_status = pthread_create(&threads[device_counter], &attr, child, &ids[device_counter]);

				switch (thread_status) {
					case 0:
						if (set.verbose == POLLER_VERBOSITY_DEBUG) {
							snprintf(logmessage, LOGSIZE, "DEBUG: Valid Thread to be Created\n");
							cacti_log(logmessage);
						}

						device_counter++;
						active_threads++;

						if (set.verbose == POLLER_VERBOSITY_DEBUG) {
							snprintf(logmessage, LOGSIZE, "DEBUG: The Value of Active Threads is %i\n", active_threads);
							cacti_log(logmessage);
						}

						break;
					case EAGAIN:
						snprintf(logmessage, LOGSIZE, "ERROR: The System Lacked the Resources to Create a Thread\n");
						cacti_log(logmessage);
						break;
					case EFAULT:
						snprintf(logmessage, LOGSIZE, "ERROR: The Thread or Attribute Was Invalid\n");
						cacti_log(logmessage);
						break;
					case EINVAL:
						snprintf(logmessage, LOGSIZE, "ERROR: The Thread Attribute is Not Initialized\n");
						cacti_log(logmessage);
						break;
					default:
						snprintf(logmessage, LOGSIZE, "ERROR: Unknown Thread Creation Error\n");
						cacti_log(logmessage);
						break;
				}
				usleep(THREAD_SLEEP);
			}

			thread_mutex_unlock(LOCK_THREAD);

			break;
		case EBUSY:
			snprintf(logmessage, LOGSIZE, "ERROR: Deadlock Occured\n");
			cacti_log(logmessage);
			break;
		case EINVAL:
			snprintf(logmessage, LOGSIZE, "ERROR: Attempt to Unlock an Uninitialized Mutex\n");
			cacti_log(logmessage);
			break;
		case EFAULT:
			snprintf(logmessage, LOGSIZE, "ERROR: Attempt to Unlock an Invalid Mutex\n");
			cacti_log(logmessage);
			break;
		default:
			snprintf(logmessage, LOGSIZE, "ERROR: Unknown Mutex Lock Error Code Returned\n");
			cacti_log(logmessage);
			break;
		}

		usleep(THREAD_SLEEP);
	}

	/* wait for all threads to complete */
	while (canexit == 0) {
		if (thread_mutex_trylock(LOCK_THREAD) != EBUSY) {
			if (last_active_threads != active_threads) {
				last_active_threads = active_threads;
			}

			if (active_threads == 0) {
				canexit = 1;
			}

			thread_mutex_unlock(LOCK_THREAD);
		}

		usleep(THREAD_SLEEP);
	}

	/* print out stats */
	gettimeofday(&now, NULL);

	/* update the db for |data_time| on graphs */
	db_insert(&mysql, "replace into settings (name,value) values ('date',NOW())");
	db_insert(&mysql, "insert into poller_time (poller_id, start_time, end_time) values (0, NOW(), NOW())");

	/* cleanup and exit program */
	pthread_attr_destroy(&attr);
	pthread_mutexattr_destroy(&mutexattr);

	if (set.verbose == POLLER_VERBOSITY_DEBUG) {
		cacti_log("DEBUG: Thread Cleanup Complete\n");
	}

	/* close the php script server */
	php_close();

	if (set.verbose == POLLER_VERBOSITY_DEBUG) {
		cacti_log("DEBUG: PHP Script Server Pipes Closed\n");
	}

	/* free malloc'd variables */
	free(threads);
	free(ids);
	free(conf_file);

	if (set.verbose == POLLER_VERBOSITY_DEBUG) {
		cacti_log("DEBUG: Allocated Variable Memory Freed\n");
	}

	/* close mysql */
	mysql_free_result(result);
	mysql_close(&mysql);

	if (set.verbose == POLLER_VERBOSITY_DEBUG) {
		cacti_log("DEBUG: MYSQL Free & Close Completed\n");
	}

	/* finally add some statistics to the log and exit */
	end_time = (double) now.tv_usec / 1000000 + now.tv_sec;

	if ((set.verbose >= POLLER_VERBOSITY_MEDIUM) && (argc != 1)) {
		snprintf(logmessage, LOGSIZE, "Time: %.4f s, Threads: %i, Hosts: %i\n", (end_time - begin_time), set.threads, num_rows);
		cacti_log(logmessage);
	} else {
		printf("CACTID: Execution Time: %.4f s, Threads: %i, Hosts: %i\n", (end_time - begin_time), set.threads, num_rows);
	}

	exit(0);
}
Exemple #6
0
/*
  Configure node_t myself and set up the local sockets (listen only)
*/
static bool setup_myself(void) {
    config_t *cfg;
    subnet_t *subnet;
    char *name, *hostname, *mode, *afname, *cipher, *digest, *type;
    char *fname = NULL;
    char *address = NULL;
    char *proxy = NULL;
    char *space;
    char *envp[5] = {NULL};
    struct addrinfo *ai, *aip, hint = {0};
    bool choice;
    int i, err;
    int replaywin_int;
    bool port_specified = false;

    myself = new_node();
    myself->connection = new_connection();

    myself->hostname = xstrdup("MYSELF");
    myself->connection->hostname = xstrdup("MYSELF");

    myself->connection->options = 0;
    myself->connection->protocol_version = PROT_CURRENT;

    if(!(name = get_name())) {
        logger(LOG_ERR, "Name for tinc daemon required!");
        return false;
    }

    /* Read tinc.conf and our own host config file */

    myself->name = name;
    myself->connection->name = xstrdup(name);
    xasprintf(&fname, "%s/hosts/%s", confbase, name);
    read_config_options(config_tree, name);
    read_config_file(config_tree, fname);
    free(fname);

    if(!read_rsa_private_key())
        return false;

    if(!get_config_string(lookup_config(config_tree, "Port"), &myport))
        myport = xstrdup("655");
    else
        port_specified = true;

    /* Ensure myport is numeric */

    if(!atoi(myport)) {
        struct addrinfo *ai = str2addrinfo("localhost", myport, SOCK_DGRAM);
        sockaddr_t sa;
        if(!ai || !ai->ai_addr)
            return false;
        free(myport);
        memcpy(&sa, ai->ai_addr, ai->ai_addrlen);
        sockaddr2str(&sa, NULL, &myport);
    }

    get_config_string(lookup_config(config_tree, "Proxy"), &proxy);
    if(proxy) {
        if((space = strchr(proxy, ' ')))
            *space++ = 0;

        if(!strcasecmp(proxy, "none")) {
            proxytype = PROXY_NONE;
        } else if(!strcasecmp(proxy, "socks4")) {
            proxytype = PROXY_SOCKS4;
        } else if(!strcasecmp(proxy, "socks4a")) {
            proxytype = PROXY_SOCKS4A;
        } else if(!strcasecmp(proxy, "socks5")) {
            proxytype = PROXY_SOCKS5;
        } else if(!strcasecmp(proxy, "http")) {
            proxytype = PROXY_HTTP;
        } else if(!strcasecmp(proxy, "exec")) {
            proxytype = PROXY_EXEC;
        } else {
            logger(LOG_ERR, "Unknown proxy type %s!", proxy);
            return false;
        }

        switch(proxytype) {
        case PROXY_NONE:
        default:
            break;

        case PROXY_EXEC:
            if(!space || !*space) {
                logger(LOG_ERR, "Argument expected for proxy type exec!");
                return false;
            }
            proxyhost =  xstrdup(space);
            break;

        case PROXY_SOCKS4:
        case PROXY_SOCKS4A:
        case PROXY_SOCKS5:
        case PROXY_HTTP:
            proxyhost = space;
            if(space && (space = strchr(space, ' ')))
                *space++ = 0, proxyport = space;
            if(space && (space = strchr(space, ' ')))
                *space++ = 0, proxyuser = space;
            if(space && (space = strchr(space, ' ')))
                *space++ = 0, proxypass = space;
            if(!proxyhost || !*proxyhost || !proxyport || !*proxyport) {
                logger(LOG_ERR, "Host and port argument expected for proxy!");
                return false;
            }
            proxyhost = xstrdup(proxyhost);
            proxyport = xstrdup(proxyport);
            if(proxyuser && *proxyuser)
                proxyuser = xstrdup(proxyuser);
            if(proxypass && *proxypass)
                proxypass = xstrdup(proxypass);
            break;
        }

        free(proxy);
    }

    /* Read in all the subnets specified in the host configuration file */

    cfg = lookup_config(config_tree, "Subnet");

    while(cfg) {
        if(!get_config_subnet(cfg, &subnet))
            return false;

        subnet_add(myself, subnet);

        cfg = lookup_config_next(config_tree, cfg);
    }

    /* Check some options */

    if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice) && choice)
        myself->options |= OPTION_INDIRECT;

    if(get_config_bool(lookup_config(config_tree, "TCPOnly"), &choice) && choice)
        myself->options |= OPTION_TCPONLY;

    if(myself->options & OPTION_TCPONLY)
        myself->options |= OPTION_INDIRECT;

    get_config_bool(lookup_config(config_tree, "DirectOnly"), &directonly);
    get_config_bool(lookup_config(config_tree, "StrictSubnets"), &strictsubnets);
    get_config_bool(lookup_config(config_tree, "TunnelServer"), &tunnelserver);
    get_config_bool(lookup_config(config_tree, "LocalDiscovery"), &localdiscovery);
    strictsubnets |= tunnelserver;

    if(get_config_string(lookup_config(config_tree, "Mode"), &mode)) {
        if(!strcasecmp(mode, "router"))
            routing_mode = RMODE_ROUTER;
        else if(!strcasecmp(mode, "switch"))
            routing_mode = RMODE_SWITCH;
        else if(!strcasecmp(mode, "hub"))
            routing_mode = RMODE_HUB;
        else {
            logger(LOG_ERR, "Invalid routing mode!");
            return false;
        }
        free(mode);
    }

    if(get_config_string(lookup_config(config_tree, "Forwarding"), &mode)) {
        if(!strcasecmp(mode, "off"))
            forwarding_mode = FMODE_OFF;
        else if(!strcasecmp(mode, "internal"))
            forwarding_mode = FMODE_INTERNAL;
        else if(!strcasecmp(mode, "kernel"))
            forwarding_mode = FMODE_KERNEL;
        else {
            logger(LOG_ERR, "Invalid forwarding mode!");
            return false;
        }
        free(mode);
    }

    choice = true;
    get_config_bool(lookup_config(config_tree, "PMTUDiscovery"), &choice);
    if(choice)
        myself->options |= OPTION_PMTU_DISCOVERY;

    choice = true;
    get_config_bool(lookup_config(config_tree, "ClampMSS"), &choice);
    if(choice)
        myself->options |= OPTION_CLAMP_MSS;

    get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance);
    get_config_bool(lookup_config(config_tree, "DecrementTTL"), &decrement_ttl);
    if(get_config_string(lookup_config(config_tree, "Broadcast"), &mode)) {
        if(!strcasecmp(mode, "no"))
            broadcast_mode = BMODE_NONE;
        else if(!strcasecmp(mode, "yes") || !strcasecmp(mode, "mst"))
            broadcast_mode = BMODE_MST;
        else if(!strcasecmp(mode, "direct"))
            broadcast_mode = BMODE_DIRECT;
        else {
            logger(LOG_ERR, "Invalid broadcast mode!");
            return false;
        }
        free(mode);
    }

#if !defined(SOL_IP) || !defined(IP_TOS)
    if(priorityinheritance)
        logger(LOG_WARNING, "%s not supported on this platform", "PriorityInheritance");
#endif

    if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire))
        macexpire = 600;

    if(get_config_int(lookup_config(config_tree, "MaxTimeout"), &maxtimeout)) {
        if(maxtimeout <= 0) {
            logger(LOG_ERR, "Bogus maximum timeout!");
            return false;
        }
    } else
        maxtimeout = 900;

    if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) {
        if(udp_rcvbuf <= 0) {
            logger(LOG_ERR, "UDPRcvBuf cannot be negative!");
            return false;
        }
    }

    if(get_config_int(lookup_config(config_tree, "UDPSndBuf"), &udp_sndbuf)) {
        if(udp_sndbuf <= 0) {
            logger(LOG_ERR, "UDPSndBuf cannot be negative!");
            return false;
        }
    }

    if(get_config_int(lookup_config(config_tree, "ReplayWindow"), &replaywin_int)) {
        if(replaywin_int < 0) {
            logger(LOG_ERR, "ReplayWindow cannot be negative!");
            return false;
        }
        replaywin = (unsigned)replaywin_int;
    }

    if(get_config_string(lookup_config(config_tree, "AddressFamily"), &afname)) {
        if(!strcasecmp(afname, "IPv4"))
            addressfamily = AF_INET;
        else if(!strcasecmp(afname, "IPv6"))
            addressfamily = AF_INET6;
        else if(!strcasecmp(afname, "any"))
            addressfamily = AF_UNSPEC;
        else {
            logger(LOG_ERR, "Invalid address family!");
            return false;
        }
        free(afname);
    }

    get_config_bool(lookup_config(config_tree, "Hostnames"), &hostnames);

    /* Generate packet encryption key */

    if(get_config_string
            (lookup_config(config_tree, "Cipher"), &cipher)) {
        if(!strcasecmp(cipher, "none")) {
            myself->incipher = NULL;
        } else {
            myself->incipher = EVP_get_cipherbyname(cipher);

            if(!myself->incipher) {
                logger(LOG_ERR, "Unrecognized cipher type!");
                return false;
            }
        }
    } else
        myself->incipher = EVP_bf_cbc();

    if(myself->incipher)
        myself->inkeylength = myself->incipher->key_len + myself->incipher->iv_len;
    else
        myself->inkeylength = 1;

    myself->connection->outcipher = EVP_bf_ofb();

    if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
        keylifetime = 3600;

    keyexpires = now + keylifetime;

    /* Check if we want to use message authentication codes... */

    if(get_config_string(lookup_config(config_tree, "Digest"), &digest)) {
        if(!strcasecmp(digest, "none")) {
            myself->indigest = NULL;
        } else {
            myself->indigest = EVP_get_digestbyname(digest);

            if(!myself->indigest) {
                logger(LOG_ERR, "Unrecognized digest type!");
                return false;
            }
        }
    } else
        myself->indigest = EVP_sha1();

    myself->connection->outdigest = EVP_sha1();

    if(get_config_int(lookup_config(config_tree, "MACLength"), &myself->inmaclength)) {
        if(myself->indigest) {
            if(myself->inmaclength > myself->indigest->md_size) {
                logger(LOG_ERR, "MAC length exceeds size of digest!");
                return false;
            } else if(myself->inmaclength < 0) {
                logger(LOG_ERR, "Bogus MAC length!");
                return false;
            }
        }
    } else
        myself->inmaclength = 4;

    myself->connection->outmaclength = 0;

    /* Compression */

    if(get_config_int(lookup_config(config_tree, "Compression"), &myself->incompression)) {
        if(myself->incompression < 0 || myself->incompression > 11) {
            logger(LOG_ERR, "Bogus compression level!");
            return false;
        }
    } else
        myself->incompression = 0;

    myself->connection->outcompression = 0;

    /* Done */

    myself->nexthop = myself;
    myself->via = myself;
    myself->status.reachable = true;
    node_add(myself);

    graph();

    if(strictsubnets)
        load_all_subnets();

    /* Open device */

    devops = os_devops;

    if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
        if(!strcasecmp(type, "dummy"))
            devops = dummy_devops;
        else if(!strcasecmp(type, "raw_socket"))
            devops = raw_socket_devops;
        else if(!strcasecmp(type, "multicast"))
            devops = multicast_devops;
#ifdef ENABLE_UML
        else if(!strcasecmp(type, "uml"))
            devops = uml_devops;
#endif
#ifdef ENABLE_VDE
        else if(!strcasecmp(type, "vde"))
            devops = vde_devops;
#endif
    }

    if(!devops.setup())
        return false;

    /* Run tinc-up script to further initialize the tap interface */
    xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
    xasprintf(&envp[1], "DEVICE=%s", device ? : "");
    xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
    xasprintf(&envp[3], "NAME=%s", myself->name);

    execute_script("tinc-up", envp);

    for(i = 0; i < 4; i++)
        free(envp[i]);

    /* Run subnet-up scripts for our own subnets */

    subnet_update(myself, NULL, true);

    /* Open sockets */

    if(!do_detach && getenv("LISTEN_FDS")) {
        sockaddr_t sa;
        socklen_t salen;

        listen_sockets = atoi(getenv("LISTEN_FDS"));
#ifdef HAVE_UNSETENV
        unsetenv("LISTEN_FDS");
#endif

        if(listen_sockets > MAXSOCKETS) {
            logger(LOG_ERR, "Too many listening sockets");
            return false;
        }

        for(i = 0; i < listen_sockets; i++) {
            salen = sizeof sa;
            if(getsockname(i + 3, &sa.sa, &salen) < 0) {
                logger(LOG_ERR, "Could not get address of listen fd %d: %s", i + 3, sockstrerror(errno));
                return false;
            }

            listen_socket[i].tcp = i + 3;

#ifdef FD_CLOEXEC
            fcntl(i + 3, F_SETFD, FD_CLOEXEC);
#endif

            listen_socket[i].udp = setup_vpn_in_socket(&sa);
            if(listen_socket[i].udp < 0)
                return false;

            ifdebug(CONNECTIONS) {
                hostname = sockaddr2hostname(&sa);
                logger(LOG_NOTICE, "Listening on %s", hostname);
                free(hostname);
            }

            memcpy(&listen_socket[i].sa, &sa, salen);
        }
    } else {
Exemple #7
0
/*! \fn main(int argc, char *argv[])
 *  \brief The Cactid program entry point
 *  \param argc The number of arguments passed to the function plus one (+1)
 *  \param argv An array of the command line arguments
 *
 *  The Cactid entry point.  This function performs the following tasks.
 *  1) Processes command line input parameters
 *  2) Processes the Cactid configuration file to obtain database access information
 *  3) Process runtime parameters from the settings table
 *  4) Initialize the runtime threads and mutexes for the threaded environment
 *  5) Initialize Net-SNMP, MySQL, and the PHP Script Server (if required)
 *  6) Spawns X threads in order to process hosts
 *  7) Loop until either all hosts have been processed or until the poller runtime
 *     has been exceeded
 *  8) Close database and free variables
 *  9) Log poller process statistics if required
 *  10) Exit
 *
 *  Note: Command line runtime parameters override any database settings.
 *
 *  \return 0 if SUCCESS, or -1 if FAILED
 *
 */
int main(int argc, char *argv[]) {
	struct timeval now;
	char *conf_file = NULL;
	double begin_time, end_time, current_time;
	int poller_interval;
	int num_rows;
	int device_counter = 0;
	int poller_counter = 0;
	int last_active_threads = 0;
	long int EXTERNAL_THREAD_SLEEP = 100000;
	long int internal_thread_sleep;
	time_t nowbin;
	struct tm now_time;
	struct tm *now_ptr;

	pthread_t* threads = NULL;
	pthread_attr_t attr;

	int* ids = NULL;
	MYSQL mysql;
	MYSQL_RES *result = NULL;
	MYSQL_ROW mysql_row;
	int canexit = 0;
	int host_id;
	int i;
	int mutex_status = 0;
	int thread_status = 0;

	UNUSED_PARAMETER(argc);		/* we operate strictly with argv */

	/* establish php processes and initialize space */
	php_processes = (php_t*) calloc(MAX_PHP_SERVERS, sizeof(php_t));
	for (i = 0; i < MAX_PHP_SERVERS; i++) {
		php_processes[i].php_state = PHP_BUSY;
	}

	/* set start time for cacti */
	begin_time = get_time_as_double();

	/* get time for poller_output table */
	if (time(&nowbin) == (time_t) - 1) {
		die("ERROR: Could not get time of day from time()\n");
	}
	localtime_r(&nowbin,&now_time);
	now_ptr = &now_time;

	if (strftime(start_datetime, sizeof(start_datetime), "%Y-%m-%d %H:%M:%S", now_ptr) == (size_t) 0) {
		die("ERROR: Could not get string from strftime()\n");
	}

	/* set default verbosity */
	set.log_level = POLLER_VERBOSITY_LOW;

	/* get static defaults for system */
	config_defaults();

	/*! ----------------------------------------------------------------
	 * PROCESS COMMAND LINE
	 *
	 * Run through the list of ARGV words looking for parameters we
	 * know about. Most have two flavors (-C + --conf), and many
	 * themselves take a parameter.
	 *
	 * These parameters can be structured in two ways:
	 *
	 *	--conf=FILE		both parts in one argv[] string
	 *	--conf FILE		two separate argv[] strings
	 *
	 * We set "arg" to point to "--conf", and "opt" to point to FILE.
	 * The helper routine
	 *
	 * In each loop we set "arg" to next argv[] string, then look
	 * to see if it has an equal sign. If so, we split it in half
	 * and point to the option separately.
	 *
	 * NOTE: most direction to the program is given with dash-type
	 * parameters, but we also allow standalone numeric device IDs
	 * in "first last" format: this is how poller.php calls this
	 * program.
	 */

	/* initialize some global variables */
	set.start_host_id = -1;
	set.end_host_id   = -1;
	set.php_initialized = FALSE;
	set.logfile_processed = FALSE;
	set.parent_fork = CACTID_PARENT;

	for (argv++; *argv; argv++) {
		char	*arg = *argv;
		char	*opt = strchr(arg, '=');	/* pick off the =VALUE part */

		if (opt) *opt++ = '\0';

		if (STRIMATCH(arg, "-f") ||
			STRIMATCH(arg, "--first")) {
			if (HOSTID_DEFINED(set.start_host_id)) {
				die("ERROR: %s can only be used once", arg);
			}

			set.start_host_id = atoi(opt = getarg(opt, &argv));

			if (!HOSTID_DEFINED(set.start_host_id)) {
				die("ERROR: '%s=%s' is invalid first-host ID", arg, opt);
			}
		}

		else if (STRIMATCH(arg, "-l") ||
				 STRIMATCH(arg, "--last")) {
			if (HOSTID_DEFINED(set.end_host_id)) {
				die("ERROR: %s can only be used once", arg);
			}

			set.end_host_id = atoi(opt = getarg(opt, &argv));

			if (!HOSTID_DEFINED(set.end_host_id)) {
				die("ERROR: '%s=%s' is invalid last-host ID", arg, opt);
			}
		}

		else if (STRIMATCH(arg, "-p") ||
				 STRIMATCH(arg, "--poller")) {
			set.poller_id = atoi(getarg(opt, &argv));
		}

		else if (STRIMATCH(arg, "-h") ||
				 STRIMATCH(arg, "-v") ||
				 STRIMATCH(arg, "--help") ||
				 STRIMATCH(arg, "--version")) {
			display_help();

			exit(EXIT_SUCCESS);
		}

		else if (STRIMATCH(arg, "-O") ||
				 STRIMATCH(arg, "--option")) {
			char	*setting = getarg(opt, &argv);
			char	*value   = strchr(setting, ':');

			if (*value) {
				*value++ = '\0';
			}else{
				die("ERROR: -O requires setting:value");
			}

			set_option(setting, value);
		}

		else if (STRIMATCH(arg, "-R") ||
				 STRIMATCH(arg, "--readonly") ||
				 STRIMATCH(arg, "--read-only")) {
			set.SQL_readonly = TRUE;
		}

		else if (STRIMATCH(arg, "-C") ||
				 STRIMATCH(arg, "--conf")) {
			conf_file = strdup(getarg(opt, &argv));
		}

		else if (STRIMATCH(arg, "-S") ||
				 STRIMATCH(arg, "--stdout")) {
			set_option("log_destination", "STDOUT");
		}

		else if (STRIMATCH(arg, "-L") ||
				 STRIMATCH(arg, "--log")) {
			set_option("log_destination", getarg(opt, &argv));
		}

		else if (STRIMATCH(arg, "-V") ||
				 STRIMATCH(arg, "--verbosity")) {
			set_option("log_verbosity", getarg(opt, &argv));
		}

		else if (STRIMATCH(arg, "--snmponly") ||
				 STRIMATCH(arg, "--snmp-only")) {
			set.snmponly = TRUE;
		}

		else if (!HOSTID_DEFINED(set.start_host_id) && all_digits(arg)) {
			set.start_host_id = atoi(arg);
		}

		else if (!HOSTID_DEFINED(set.end_host_id) && all_digits(arg)) {
			set.end_host_id = atoi(arg);
		}

		else {
			die("ERROR: %s is an unknown command-line parameter", arg);
		}
	}

	/* we require either both the first and last hosts, or niether host */
	if (HOSTID_DEFINED(set.start_host_id) != HOSTID_DEFINED(set.end_host_id)) {
		die("ERROR: must provide both -f/-l, or neither");
	}

	if (set.start_host_id > set.end_host_id) {
		die("ERROR: Invalid row spec; first host_id must be less than the second");
	}

	/* read configuration file to establish local environment */
	if (conf_file) {
		if ((read_cactid_config(conf_file)) < 0) {
			die("ERROR: Could not read config file: %s\n", conf_file);
		}
	}else{
		if (!(conf_file = calloc(1, BUFSIZE))) {
			die("ERROR: Fatal malloc error: cactid.c conf_file!\n");
		}

		for (i=0; i<CONFIG_PATHS; i++) {
			snprintf(conf_file, BUFSIZE-1, "%s%s", config_paths[i], DEFAULT_CONF_FILE);

			if (read_cactid_config(conf_file) >= 0) {
				break;
			}

			if (i == CONFIG_PATHS-1) {
				snprintf(conf_file, BUFSIZE-1, "%s%s", config_paths[0], DEFAULT_CONF_FILE);
			}
		}
	}

	/* read settings table from the database to further establish environment */
	read_config_options();

	/* set the poller interval for those who use less than 5 minute intervals */
	if (set.poller_interval == 0) {
		poller_interval = 300;
	}else {
		poller_interval = set.poller_interval;
	}

	/* calculate the external_tread_sleep value */
	internal_thread_sleep = EXTERNAL_THREAD_SLEEP * set.num_parent_processes / 2;

	if (set.log_level == POLLER_VERBOSITY_DEBUG) {
		CACTID_LOG_DEBUG(("CACTID: Version %s starting\n", VERSION));
	}else{
		printf("CACTID: Version %s starting\n", VERSION);
	}

	/* connect to database */
	db_connect(set.dbdb, &mysql);

	/* initialize SNMP */
	CACTID_LOG_DEBUG(("CACTID: Initializing Net-SNMP API\n"));
	snmp_cactid_init();

	/* initialize PHP if required */
	CACTID_LOG_DEBUG(("CACTID: Initializing PHP Script Server\n"));

	/* tell cactid that it is parent, and set the poller id */
	set.parent_fork = CACTID_PARENT;
	set.poller_id = 0;

	/* initialize the script server */
	if (set.php_required) {
		php_init(PHP_INIT);
		set.php_initialized = TRUE;
		set.php_current_server = 0;
	}

	/* obtain the list of hosts to poll */
	{
	char querybuf[256], *qp = querybuf;

	qp += sprintf(qp, "SELECT id FROM host");
	qp += sprintf(qp, " WHERE disabled=''");
	qp += append_hostrange(qp, "id");	/* AND id BETWEEN a AND b */
	qp += sprintf(qp, " ORDER BY id");

	result = db_query(&mysql, querybuf);
	}

	num_rows = mysql_num_rows(result) + 1; /* add 1 for host = 0 */

	if (!(threads = (pthread_t *)malloc(num_rows * sizeof(pthread_t)))) {
		die("ERROR: Fatal malloc error: cactid.c threads!\n");
	}

	if (!(ids = (int *)malloc(num_rows * sizeof(int)))) {
		die("ERROR: Fatal malloc error: cactid.c host id's!\n");
	}

	/* initialize threads and mutexes */
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

	init_mutexes();

	CACTID_LOG_DEBUG(("DEBUG: Initial Value of Active Threads is %i\n", active_threads));

	/* tell fork processes that they are now active */
	set.parent_fork = CACTID_FORK;

	/* loop through devices until done */
	while ((device_counter < num_rows) && (canexit == 0)) {
		mutex_status = thread_mutex_trylock(LOCK_THREAD);

		switch (mutex_status) {
		case 0:
			if (last_active_threads != active_threads) {
				last_active_threads = active_threads;
			}

			while ((active_threads < set.threads) && (device_counter < num_rows)) {
				if (device_counter > 0) {
					mysql_row = mysql_fetch_row(result);
					host_id = atoi(mysql_row[0]);
					ids[device_counter] = host_id;
				}else{
					ids[device_counter] = 0;
				}

				/* create child process */
				thread_status = pthread_create(&threads[device_counter], &attr, child, &ids[device_counter]);

				switch (thread_status) {
					case 0:
						CACTID_LOG_DEBUG(("DEBUG: Valid Thread to be Created\n"));

						device_counter++;
						active_threads++;

						CACTID_LOG_DEBUG(("DEBUG: The Value of Active Threads is %i\n", active_threads));

						break;
					case EAGAIN:
						CACTID_LOG(("ERROR: The System Lacked the Resources to Create a Thread\n"));
						break;
					case EFAULT:
						CACTID_LOG(("ERROR: The Thread or Attribute Was Invalid\n"));
						break;
					case EINVAL:
						CACTID_LOG(("ERROR: The Thread Attribute is Not Initialized\n"));
						break;
					default:
						CACTID_LOG(("ERROR: Unknown Thread Creation Error\n"));
						break;
				}
				usleep(internal_thread_sleep);

				/* get current time and exit program if time limit exceeded */
				if (poller_counter >= 20) {
					current_time = get_time_as_double();

					if ((current_time - begin_time + 6) > poller_interval) {
						CACTID_LOG(("ERROR: Cactid Timed Out While Processing Hosts Internal\n"));
						canexit = 1;
						break;
					}

					poller_counter = 0;
				}else{
					poller_counter++;
				}
			}

			thread_mutex_unlock(LOCK_THREAD);

			break;
		case EDEADLK:
			CACTID_LOG(("ERROR: Deadlock Occured\n"));
			break;
		case EBUSY:
			break;
		case EINVAL:
			CACTID_LOG(("ERROR: Attempt to Unlock an Uninitialized Mutex\n"));
			break;
		case EFAULT:
			CACTID_LOG(("ERROR: Attempt to Unlock an Invalid Mutex\n"));
			break;
		default:
			CACTID_LOG(("ERROR: Unknown Mutex Lock Error Code Returned\n"));
			break;
		}

		usleep(internal_thread_sleep);

		/* get current time and exit program if time limit exceeded */
		if (poller_counter >= 20) {
			current_time = get_time_as_double();

			if ((current_time - begin_time + 6) > poller_interval) {
				CACTID_LOG(("ERROR: Cactid Timed Out While Processing Hosts Internal\n"));
				canexit = 1;
				break;
			}

			poller_counter = 0;
		}else{
			poller_counter++;
		}
	}

	/* wait for all threads to complete */
	while (canexit == 0) {
		if (thread_mutex_trylock(LOCK_THREAD) == 0) {
			if (last_active_threads != active_threads) {
				last_active_threads = active_threads;
			}

			if (active_threads == 0) {
				canexit = 1;
			}

			thread_mutex_unlock(LOCK_THREAD);
		}

		usleep(EXTERNAL_THREAD_SLEEP);

		/* get current time and exit program if time limit exceeded */
		if (poller_counter >= 20) {
			current_time = get_time_as_double();

			if ((current_time - begin_time + 6) > poller_interval) {
				CACTID_LOG(("ERROR: Cactid Timed Out While Processing Hosts Internal\n"));
				canexit = 1;
				break;
			}

			poller_counter = 0;
		}else{
			poller_counter++;
		}
	}

	/* tell Cactid that it is now parent */
	set.parent_fork = CACTID_PARENT;

	/* print out stats */
	gettimeofday(&now, NULL);

	/* update the db for |data_time| on graphs */
	db_insert(&mysql, "replace into settings (name,value) values ('date',NOW())");
	db_insert(&mysql, "insert into poller_time (poller_id, start_time, end_time) values (0, NOW(), NOW())");

	/* cleanup and exit program */
	pthread_attr_destroy(&attr);

	CACTID_LOG_DEBUG(("DEBUG: Thread Cleanup Complete\n"));

	/* close the php script server */
	if (set.php_required) {
		php_close(PHP_INIT);
	}

	CACTID_LOG_DEBUG(("DEBUG: PHP Script Server Pipes Closed\n"));

	/* free malloc'd variables */
	free(threads);
	free(ids);
	free(conf_file);

	CACTID_LOG_DEBUG(("DEBUG: Allocated Variable Memory Freed\n"));

	/* shutdown SNMP */
	snmp_cactid_close();

	CACTID_LOG_DEBUG(("CACTID: Net-SNMP API Shutdown Completed\n"));

	/* close mysql */
	mysql_free_result(result);
	mysql_close(&mysql);

	CACTID_LOG_DEBUG(("DEBUG: MYSQL Free & Close Completed\n"));

	/* finally add some statistics to the log and exit */
	end_time = TIMEVAL_TO_DOUBLE(now);

	CACTID_LOG_MEDIUM(("Time: %.4f s, Threads: %i, Hosts: %i\n", (end_time - begin_time), set.threads, num_rows));

	exit(EXIT_SUCCESS);
}
Exemple #8
0
/*
  Configure node_t myself and set up the local sockets (listen only)
*/
bool setup_myself(void) {
    config_t *cfg;
    subnet_t *subnet;
    char *name, *hostname, *mode, *afname, *cipher, *digest;
    char *fname = NULL;
    char *address = NULL;
    char *envp[5];
    struct addrinfo *ai, *aip, hint = {0};
    bool choice;
    int i, err;
    int replaywin_int;

    myself = new_node();
    myself->connection = new_connection();

    myself->hostname = xstrdup("MYSELF");
    myself->connection->hostname = xstrdup("MYSELF");

    myself->connection->options = 0;
    myself->connection->protocol_version = PROT_CURRENT;

    if(!get_config_string(lookup_config(config_tree, "Name"), &name)) {	/* Not acceptable */
        logger(LOG_ERR, "Name for tinc daemon required!");
        return false;
    }

    if(!check_id(name)) {
        logger(LOG_ERR, "Invalid name for myself!");
        free(name);
        return false;
    }

    myself->name = name;
    myself->connection->name = xstrdup(name);
    xasprintf(&fname, "%s/hosts/%s", confbase, name);
    read_config_options(config_tree, name);
    read_config_file(config_tree, fname);
    free(fname);

    if(!read_rsa_private_key())
        return false;

    if(!get_config_string(lookup_config(config_tree, "Port"), &myport))
        myport = xstrdup("655");

    if(!atoi(myport)) {
        struct addrinfo *ai = str2addrinfo("localhost", myport, SOCK_DGRAM);
        sockaddr_t sa;
        if(!ai || !ai->ai_addr)
            return false;
        free(myport);
        memcpy(&sa, ai->ai_addr, ai->ai_addrlen);
        sockaddr2str(&sa, NULL, &myport);
    }

    /* Read in all the subnets specified in the host configuration file */

    cfg = lookup_config(config_tree, "Subnet");

    while(cfg) {
        if(!get_config_subnet(cfg, &subnet))
            return false;

        subnet_add(myself, subnet);

        cfg = lookup_config_next(config_tree, cfg);
    }

    /* Check some options */

    if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice) && choice)
        myself->options |= OPTION_INDIRECT;

    if(get_config_bool(lookup_config(config_tree, "TCPOnly"), &choice) && choice)
        myself->options |= OPTION_TCPONLY;

    if(myself->options & OPTION_TCPONLY)
        myself->options |= OPTION_INDIRECT;

    get_config_bool(lookup_config(config_tree, "DirectOnly"), &directonly);
    get_config_bool(lookup_config(config_tree, "StrictSubnets"), &strictsubnets);
    get_config_bool(lookup_config(config_tree, "TunnelServer"), &tunnelserver);
    strictsubnets |= tunnelserver;

    if(get_config_string(lookup_config(config_tree, "Mode"), &mode)) {
        if(!strcasecmp(mode, "router"))
            routing_mode = RMODE_ROUTER;
        else if(!strcasecmp(mode, "switch"))
            routing_mode = RMODE_SWITCH;
        else if(!strcasecmp(mode, "hub"))
            routing_mode = RMODE_HUB;
        else {
            logger(LOG_ERR, "Invalid routing mode!");
            return false;
        }
        free(mode);
    }

    if(get_config_string(lookup_config(config_tree, "Forwarding"), &mode)) {
        if(!strcasecmp(mode, "off"))
            forwarding_mode = FMODE_OFF;
        else if(!strcasecmp(mode, "internal"))
            forwarding_mode = FMODE_INTERNAL;
        else if(!strcasecmp(mode, "kernel"))
            forwarding_mode = FMODE_KERNEL;
        else {
            logger(LOG_ERR, "Invalid forwarding mode!");
            return false;
        }
        free(mode);
    }

    choice = true;
    get_config_bool(lookup_config(config_tree, "PMTUDiscovery"), &choice);
    if(choice)
        myself->options |= OPTION_PMTU_DISCOVERY;

    choice = true;
    get_config_bool(lookup_config(config_tree, "ClampMSS"), &choice);
    if(choice)
        myself->options |= OPTION_CLAMP_MSS;

    get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance);

#if !defined(SOL_IP) || !defined(IP_TOS)
    if(priorityinheritance)
        logger(LOG_WARNING, "%s not supported on this platform", "PriorityInheritance");
#endif

    if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire))
        macexpire = 600;

    if(get_config_int(lookup_config(config_tree, "MaxTimeout"), &maxtimeout)) {
        if(maxtimeout <= 0) {
            logger(LOG_ERR, "Bogus maximum timeout!");
            return false;
        }
    } else
        maxtimeout = 900;

    if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) {
        if(udp_rcvbuf <= 0) {
            logger(LOG_ERR, "UDPRcvBuf cannot be negative!");
            return false;
        }
    }

    if(get_config_int(lookup_config(config_tree, "UDPSndBuf"), &udp_sndbuf)) {
        if(udp_sndbuf <= 0) {
            logger(LOG_ERR, "UDPSndBuf cannot be negative!");
            return false;
        }
    }

    if(get_config_int(lookup_config(config_tree, "ReplayWindow"), &replaywin_int)) {
        if(replaywin_int < 0) {
            logger(LOG_ERR, "ReplayWindow cannot be negative!");
            return false;
        }
        replaywin = (unsigned)replaywin_int;
    }

    if(get_config_string(lookup_config(config_tree, "AddressFamily"), &afname)) {
        if(!strcasecmp(afname, "IPv4"))
            addressfamily = AF_INET;
        else if(!strcasecmp(afname, "IPv6"))
            addressfamily = AF_INET6;
        else if(!strcasecmp(afname, "any"))
            addressfamily = AF_UNSPEC;
        else {
            logger(LOG_ERR, "Invalid address family!");
            return false;
        }
        free(afname);
    }

    get_config_bool(lookup_config(config_tree, "Hostnames"), &hostnames);

    /* Generate packet encryption key */

    if(get_config_string
            (lookup_config(config_tree, "Cipher"), &cipher)) {
        if(!strcasecmp(cipher, "none")) {
            myself->incipher = NULL;
        } else {
            myself->incipher = EVP_get_cipherbyname(cipher);

            if(!myself->incipher) {
                logger(LOG_ERR, "Unrecognized cipher type!");
                return false;
            }
        }
    } else
        myself->incipher = EVP_bf_cbc();

    if(myself->incipher)
        myself->inkeylength = myself->incipher->key_len + myself->incipher->iv_len;
    else
        myself->inkeylength = 1;

    myself->connection->outcipher = EVP_bf_ofb();

    if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
        keylifetime = 3600;

    keyexpires = now + keylifetime;

    /* Check if we want to use message authentication codes... */

    if(get_config_string(lookup_config(config_tree, "Digest"), &digest)) {
        if(!strcasecmp(digest, "none")) {
            myself->indigest = NULL;
        } else {
            myself->indigest = EVP_get_digestbyname(digest);

            if(!myself->indigest) {
                logger(LOG_ERR, "Unrecognized digest type!");
                return false;
            }
        }
    } else
        myself->indigest = EVP_sha1();

    myself->connection->outdigest = EVP_sha1();

    if(get_config_int(lookup_config(config_tree, "MACLength"), &myself->inmaclength)) {
        if(myself->indigest) {
            if(myself->inmaclength > myself->indigest->md_size) {
                logger(LOG_ERR, "MAC length exceeds size of digest!");
                return false;
            } else if(myself->inmaclength < 0) {
                logger(LOG_ERR, "Bogus MAC length!");
                return false;
            }
        }
    } else
        myself->inmaclength = 4;

    myself->connection->outmaclength = 0;

    /* Compression */

    if(get_config_int(lookup_config(config_tree, "Compression"), &myself->incompression)) {
        if(myself->incompression < 0 || myself->incompression > 11) {
            logger(LOG_ERR, "Bogus compression level!");
            return false;
        }
    } else
        myself->incompression = 0;

    myself->connection->outcompression = 0;

    /* Done */

    myself->nexthop = myself;
    myself->via = myself;
    myself->status.reachable = true;
    node_add(myself);

    graph();

    if(strictsubnets)
        load_all_subnets();

    /* Open device */

    if(!setup_device())
        return false;

    /* Run tinc-up script to further initialize the tap interface */
    xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
    xasprintf(&envp[1], "DEVICE=%s", device ? : "");
    xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
    xasprintf(&envp[3], "NAME=%s", myself->name);
    envp[4] = NULL;

    execute_script("tinc-up", envp);

    for(i = 0; i < 5; i++)
        free(envp[i]);

    /* Run subnet-up scripts for our own subnets */

    subnet_update(myself, NULL, true);

    /* Open sockets */

    get_config_string(lookup_config(config_tree, "BindToAddress"), &address);

    hint.ai_family = addressfamily;
    hint.ai_socktype = SOCK_STREAM;
    hint.ai_protocol = IPPROTO_TCP;
    hint.ai_flags = AI_PASSIVE;

    err = getaddrinfo(address, myport, &hint, &ai);

    if(err || !ai) {
        logger(LOG_ERR, "System call `%s' failed: %s", "getaddrinfo",
               gai_strerror(err));
        return false;
    }

    listen_sockets = 0;

    for(aip = ai; aip; aip = aip->ai_next) {
        listen_socket[listen_sockets].tcp =
            setup_listen_socket((sockaddr_t *) aip->ai_addr);

        if(listen_socket[listen_sockets].tcp < 0)
            continue;

        listen_socket[listen_sockets].udp =
            setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);

        if(listen_socket[listen_sockets].udp < 0)
            continue;

        ifdebug(CONNECTIONS) {
            hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
            logger(LOG_NOTICE, "Listening on %s", hostname);
            free(hostname);
        }

        memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
        listen_sockets++;
    }

    freeaddrinfo(ai);

    if(listen_sockets)
        logger(LOG_NOTICE, "Ready");
    else {
        logger(LOG_ERR, "Unable to create any listening socket!");
        return false;
    }

    return true;
}
static int init(char *argv[]) {
  struct stat fstatus;
  struct group *group;
  cp_string filename;
  const char *uri=cupsBackendDeviceURI(argv);

  if ((uri != NULL) && (strncmp(uri, "cups-pdf:/", 10) == 0) && strlen(uri) > 10) {
    uri = uri + 10;
    sprintf(filename, "%s/cups-pdf-%s.conf", CP_CONFIG_PATH, uri);
  } 
  else {
    sprintf(filename, "%s/cups-pdf.conf", CP_CONFIG_PATH);
  }
  read_config_file(filename);
  cwwdebug(filename);

  read_config_ppd();

  read_config_options(argv[5]);

  (void) umask(0077);

  group=getgrnam(Conf_Grp);
  if (group)
    (void) setgid(group->gr_gid);
  cwwdebug(Conf_Log);
  if (strlen(Conf_Log)) {
    if (stat(Conf_Log, &fstatus) || !S_ISDIR(fstatus.st_mode)) {
      if (create_dir(Conf_Log, 1)) 
        return 1;
      if (chmod(Conf_Log, 0700))
        return 1;
    }
    snprintf(filename, BUFSIZE, "%s/%s%s%s", Conf_Log, "cups-pdf-", getenv("PRINTER"), "_log");
    logfp=fopen(filename, "a");
  }
  char tmpstr[100];
  *tmpstr = '\0';
  sprintf(tmpstr, "uid = %d, euid = %d", getuid(), geteuid());
  cwwdebug(tmpstr);
  if (logfp == NULL) {
	cwwdebug(strerror(errno));
	cwwdebug("logfp == NULL");
  }
  cwwdebug(filename);
  dump_configuration();

  if (!group) {
    log_event(CPERROR, "Grp not found: %s", Conf_Grp);
    return 1;
  }
  else 
    log_event(CPDEBUG, "switching to new gid: %s", Conf_Grp);
  cwwdebug("group");
  (void) umask(0022);
  cwwdebug("umask");
  cwwdebug(Conf_Spool);
  if (stat(Conf_Spool, &fstatus) || !S_ISDIR(fstatus.st_mode)) {
    if (create_dir(Conf_Spool, 0)) {
      log_event(CPERROR, "failed to create spool directory: %s", Conf_Spool);
      return 1;
    }
	cwwdebug("create_dir(Conf_Spool, 0) success!");
    if (chmod(Conf_Spool, 0751)) {
      log_event(CPERROR, "failed to set mode on spool directory: %s", Conf_Spool);
      return 1;
    }
	cwwdebug("chmod(Conf_Spool, 0751) success!");
    if (chown(Conf_Spool, -1, group->gr_gid)) 
      log_event(CPERROR, "failed to set group id %s on spool directory: %s (non fatal)", Conf_Grp, Conf_Spool);
    log_event(CPSTATUS, "spool directory created: %s", Conf_Spool);
  }
  cwwdebug("stat");
  (void) umask(0077);
  return 0;
}