Esempio n. 1
0
File: irc.c Progetto: dgruss/bitlbee
irc_t *irc_new(int fd)
{
	irc_t *irc;
	struct sockaddr_storage sock;
	socklen_t socklen = sizeof(sock);
	char *host = NULL, *myhost = NULL;
	irc_user_t *iu;
	GSList *l;
	set_t *s;
	bee_t *b;

	irc = g_new0(irc_t, 1);

	irc->fd = fd;
	sock_make_nonblocking(irc->fd);

	irc->r_watch_source_id = b_input_add(irc->fd, B_EV_IO_READ, bitlbee_io_current_client_read, irc);

	irc->status = USTATUS_OFFLINE;
	irc->last_pong = gettime();

	irc->nick_user_hash = g_hash_table_new(g_str_hash, g_str_equal);
	irc->watches = g_hash_table_new(g_str_hash, g_str_equal);

	irc->iconv = (GIConv) - 1;
	irc->oconv = (GIConv) - 1;

	if (global.conf->hostname) {
		myhost = g_strdup(global.conf->hostname);
	} else if (getsockname(irc->fd, (struct sockaddr*) &sock, &socklen) == 0) {
		char buf[NI_MAXHOST + 1];

		if (getnameinfo((struct sockaddr *) &sock, socklen, buf,
		                NI_MAXHOST, NULL, 0, 0) == 0) {
			myhost = g_strdup(ipv6_unwrap(buf));
		}
	}

	if (getpeername(irc->fd, (struct sockaddr*) &sock, &socklen) == 0) {
		char buf[NI_MAXHOST + 1];

		if (getnameinfo((struct sockaddr *) &sock, socklen, buf,
		                NI_MAXHOST, NULL, 0, 0) == 0) {
			host = g_strdup(ipv6_unwrap(buf));
		}
	}

	if (host == NULL) {
		host = g_strdup("localhost.localdomain");
	}
	if (myhost == NULL) {
		myhost = g_strdup("localhost.localdomain");
	}

	if (global.conf->ping_interval > 0 && global.conf->ping_timeout > 0) {
		irc->ping_source_id = b_timeout_add(global.conf->ping_interval * 1000, irc_userping, irc);
	}

	irc_connection_list = g_slist_append(irc_connection_list, irc);

	b = irc->b = bee_new();
	b->ui_data = irc;
	b->ui = &irc_ui_funcs;

	s = set_add(&b->set, "allow_takeover", "true", set_eval_bool, irc);
	s = set_add(&b->set, "away_devoice", "true", set_eval_bw_compat, irc);
	s->flags |= SET_HIDDEN;
	s = set_add(&b->set, "away_reply_timeout", "3600", set_eval_int, irc);
	s = set_add(&b->set, "charset", "utf-8", set_eval_charset, irc);
	s = set_add(&b->set, "default_target", "root", NULL, irc);
	s = set_add(&b->set, "display_namechanges", "false", set_eval_bool, irc);
	s = set_add(&b->set, "display_timestamps", "true", set_eval_bool, irc);
	s = set_add(&b->set, "handle_unknown", "add_channel", NULL, irc);
	s = set_add(&b->set, "last_version", "0", NULL, irc);
	s->flags |= SET_HIDDEN;
	s = set_add(&b->set, "nick_format", "%-@nick", NULL, irc);
	s = set_add(&b->set, "nick_lowercase", "false", set_eval_bool, irc);
	s = set_add(&b->set, "nick_underscores", "false", set_eval_bool, irc);
	s = set_add(&b->set, "offline_user_quits", "true", set_eval_bool, irc);
	s = set_add(&b->set, "ops", "both", set_eval_irc_channel_ops, irc);
	s = set_add(&b->set, "paste_buffer", "false", set_eval_bool, irc);
	s->old_key = g_strdup("buddy_sendbuffer");
	s = set_add(&b->set, "paste_buffer_delay", "200", set_eval_int, irc);
	s->old_key = g_strdup("buddy_sendbuffer_delay");
	s = set_add(&b->set, "password", NULL, set_eval_password, irc);
	s->flags |= SET_NULL_OK | SET_PASSWORD;
	s = set_add(&b->set, "private", "true", set_eval_bool, irc);
	s = set_add(&b->set, "query_order", "lifo", NULL, irc);
	s = set_add(&b->set, "root_nick", ROOT_NICK, set_eval_root_nick, irc);
	s->flags |= SET_HIDDEN;
	s = set_add(&b->set, "show_offline", "false", set_eval_bw_compat, irc);
	s->flags |= SET_HIDDEN;
	s = set_add(&b->set, "self_messages", "true", set_eval_self_messages, irc);
	s = set_add(&b->set, "simulate_netsplit", "true", set_eval_bool, irc);
	s = set_add(&b->set, "timezone", "local", set_eval_timezone, irc);
	s = set_add(&b->set, "to_char", ": ", set_eval_to_char, irc);
	s = set_add(&b->set, "typing_notice", "false", set_eval_bool, irc);
	s = set_add(&b->set, "utf8_nicks", "false", set_eval_utf8_nicks, irc);

	irc->root = iu = irc_user_new(irc, ROOT_NICK);
	iu->host = g_strdup(myhost);
	iu->fullname = g_strdup(ROOT_FN);
	iu->f = &irc_user_root_funcs;

	iu = irc_user_new(irc, NS_NICK);
	iu->host = g_strdup(myhost);
	iu->fullname = g_strdup(ROOT_FN);
	iu->f = &irc_user_root_funcs;

	irc->user = g_new0(irc_user_t, 1);
	irc->user->host = g_strdup(host);

	conf_loaddefaults(irc);

	/* Evaluator sets the iconv/oconv structures. */
	set_eval_charset(set_find(&b->set, "charset"), set_getstr(&b->set, "charset"));

	irc_write(irc, ":%s NOTICE * :%s", irc->root->host, "BitlBee-IRCd initialized, please go on");
	if (isatty(irc->fd)) {
		irc_write(irc, ":%s NOTICE * :%s", irc->root->host,
		          "If you read this, you most likely accidentally "
		          "started BitlBee in inetd mode on the command line. "
		          "You probably want to run it in (Fork)Daemon mode. "
		          "See doc/README for more information.");
	}

	g_free(myhost);
	g_free(host);

	/* libpurple doesn't like fork()s after initializing itself, so this
	   is the right moment to initialize it. */
#ifdef WITH_PURPLE
	nogaim_init();
#endif

	/* SSL library initialization also should be done after the fork, to
	   avoid shared CSPRNG state. This is required by NSS, which refuses to
	   work if a fork is detected */
	ssl_init();

	for (l = irc_plugins; l; l = l->next) {
		irc_plugin_t *p = l->data;
		if (p->irc_new) {
			p->irc_new(irc);
		}
	}

	return irc;
}
Esempio n. 2
0
int main( int argc, char *argv[] )
{
	int i = 0;
	char *old_cwd = NULL;
	struct sigaction sig, old;
	
	/* Required to make iconv to ASCII//TRANSLIT work. This makes BitlBee
	   system-locale-sensitive. :-( */
	setlocale( LC_CTYPE, "" );
	
	if( argc > 1 && strcmp( argv[1], "-x" ) == 0 )
		return crypt_main( argc, argv );
	
	log_init();
	
	global.conf_file = g_strdup( CONF_FILE_DEF );
	global.conf = conf_load( argc, argv );
	if( global.conf == NULL )
		return( 1 );
	
	b_main_init();
	
	/* libpurple doesn't like fork()s after initializing itself, so if
	   we use it, do this init a little later (in case we're running in
	   ForkDaemon mode). */
#ifndef WITH_PURPLE
	nogaim_init();
#endif
	
 	/* Ugly Note: libotr and gnutls both use libgcrypt. libgcrypt
 	   has a process-global config state whose initialization happpens
 	   twice if libotr and gnutls are used together. libotr installs custom
 	   memory management functions for libgcrypt while our gnutls module
 	   uses the defaults. Therefore we initialize OTR after SSL. *sigh* */
 	ssl_init();
#ifdef OTR_BI
 	otr_init();
#endif
	/* And in case OTR is loaded as a plugin, it'll also get loaded after
	   this point. */
	
	srand( time( NULL ) ^ getpid() );
	
	global.helpfile = g_strdup( HELP_FILE );
	if( help_init( &global.help, global.helpfile ) == NULL )
		log_message( LOGLVL_WARNING, "Error opening helpfile %s.", HELP_FILE );

	global.storage = storage_init( global.conf->primary_storage, global.conf->migrate_storage );
	if( global.storage == NULL )
	{
		log_message( LOGLVL_ERROR, "Unable to load storage backend '%s'", global.conf->primary_storage );
		return( 1 );
	}
	
	if( global.conf->runmode == RUNMODE_INETD )
	{
		log_link( LOGLVL_ERROR, LOGOUTPUT_IRC );
		log_link( LOGLVL_WARNING, LOGOUTPUT_IRC );
	
		i = bitlbee_inetd_init();
		log_message( LOGLVL_INFO, "%s %s starting in inetd mode.", PACKAGE, BITLBEE_VERSION );

	}
	else if( global.conf->runmode == RUNMODE_DAEMON )
	{
		log_link( LOGLVL_ERROR, LOGOUTPUT_CONSOLE );
		log_link( LOGLVL_WARNING, LOGOUTPUT_CONSOLE );

		i = bitlbee_daemon_init();
		log_message( LOGLVL_INFO, "%s %s starting in daemon mode.", PACKAGE, BITLBEE_VERSION );
	}
	else if( global.conf->runmode == RUNMODE_FORKDAEMON )
	{
		log_link( LOGLVL_ERROR, LOGOUTPUT_CONSOLE );
		log_link( LOGLVL_WARNING, LOGOUTPUT_CONSOLE );

		/* In case the operator requests a restart, we need this. */
		old_cwd = g_malloc( 256 );
		if( getcwd( old_cwd, 255 ) == NULL )
		{
			log_message( LOGLVL_WARNING, "Could not save current directory: %s", strerror( errno ) );
			g_free( old_cwd );
			old_cwd = NULL;
		}
		
		i = bitlbee_daemon_init();
		log_message( LOGLVL_INFO, "%s %s starting in forking daemon mode.", PACKAGE, BITLBEE_VERSION );
	}
	if( i != 0 )
		return( i );
	
	if( ( global.conf->user && *global.conf->user ) &&
	    ( global.conf->runmode == RUNMODE_DAEMON || 
	      global.conf->runmode == RUNMODE_FORKDAEMON ) &&
	    ( !getuid() || !geteuid() ) )
	{
		struct passwd *pw = NULL;
		pw = getpwnam( global.conf->user );
		if( pw )
		{
			initgroups( global.conf->user, pw->pw_gid );
			setgid( pw->pw_gid );
			setuid( pw->pw_uid );
		}
		else
		{
			log_message( LOGLVL_WARNING, "Failed to look up user %s.", global.conf->user );
		}
	}
 	
	/* Catch some signals to tell the user what's happening before quitting */
	memset( &sig, 0, sizeof( sig ) );
	sig.sa_handler = sighandler;
	sigaction( SIGCHLD, &sig, &old );
	sigaction( SIGPIPE, &sig, &old );
	sig.sa_flags = SA_RESETHAND;
	sigaction( SIGINT,  &sig, &old );
	sigaction( SIGILL,  &sig, &old );
	sigaction( SIGBUS,  &sig, &old );
	sigaction( SIGFPE,  &sig, &old );
	sigaction( SIGSEGV, &sig, &old );
	sigaction( SIGTERM, &sig, &old );
	sigaction( SIGQUIT, &sig, &old );
	sigaction( SIGXCPU, &sig, &old );
	
	if( !getuid() || !geteuid() )
		log_message( LOGLVL_WARNING, "BitlBee is running with root privileges. Why?" );
	
	b_main_run();
	
	/* Mainly good for restarting, to make sure we close the help.txt fd. */
	help_free( &global.help );
	
	if( global.restart )
	{
		char *fn = ipc_master_save_state();
		char *env;
		
		env = g_strdup_printf( "_BITLBEE_RESTART_STATE=%s", fn );
		putenv( env );
		g_free( fn );
		/* Looks like env should *not* be freed here as putenv
		   doesn't make a copy. Odd. */
		
		i = chdir( old_cwd );
		close( global.listen_socket );
		
		if( execv( argv[0], argv ) == -1 )
			/* Apparently the execve() failed, so let's just
			   jump back into our own/current main(). */
			/* Need more cleanup code to make this work. */
			return 1; /* main( argc, argv ); */
	}
	
	return( 0 );
}