Пример #1
0
void query_answer( irc_t *irc, query_t *q, int ans )
{
	int disp = 0;
	
	if( !q )
	{
		q = query_default( irc );
		disp = 1;
	}
	if( ans )
	{
		if( q->ic )
			imcb_log( q->ic, "Accepted: %s", q->question );
		else
			irc_usermsg( irc, "Accepted: %s", q->question );
		q->yes( q->data );
	}
	else
	{
		if( q->ic )
			imcb_log( q->ic, "Rejected: %s", q->question );
		else
			irc_usermsg( irc, "Rejected: %s", q->question );
		q->no( q->data );
	}
	q->data = NULL;
	
	query_del( irc, q );
	
	if( disp && ( q = query_default( irc ) ) )
		query_display( irc, q );
}
Пример #2
0
static void query_display( irc_t *irc, query_t *q )
{
	if( q->ic )
	{
		imcb_log( q->ic, "New request: %s\nYou can use the \2yes\2/\2no\2 commands to accept/reject this request.", q->question );
	}
	else
	{
		irc_usermsg( irc, "New request: %s\nYou can use the \2yes\2/\2no\2 commands to accept/reject this request.", q->question );
	}
}
Пример #3
0
static void irc_cmd_oper_hack( irc_t *irc, char **cmd )
{
	char *password = g_strjoinv( " ", cmd + 2 );
	
	/* /OPER can now also be used to enter IM/identify passwords without
	   echoing. It's a hack but the extra password security is worth it. */
	if( irc->status & OPER_HACK_ACCOUNT_ADD )
	{
		account_t *a;
		
		for( a = irc->b->accounts; a; a = a->next )
			if( strcmp( a->pass, PASSWORD_PENDING ) == 0 )
			{
				set_setstr( &a->set, "password", password );
				irc_usermsg( irc, "Password added to IM account "
				             "%s(%s)", a->prpl->name, a->user );
				/* The IRC client may expect this. 491 suggests the OPER
				   password was wrong, so the client won't expect a +o.
				   It may however repeat the password prompt. We'll see. */
				irc_send_num( irc, 491, ":Password added to IM account "
				              "%s(%s)", a->prpl->name, a->user );
			}
	}
	else if( irc->status & OPER_HACK_IDENTIFY )
	{
		char *send_cmd[] = { "identify", password, NULL };
		irc_send_num( irc, 491, ":Trying to identify" );
		root_command( irc, send_cmd );
	}
	else if( irc->status & OPER_HACK_REGISTER )
	{
		char *send_cmd[] = { "register", password, NULL };
		irc_send_num( irc, 491, ":Trying to identify" );
		root_command( irc, send_cmd );
	}
	
	irc->status &= ~OPER_HACK_ANY;
	g_free( password );
}
Пример #4
0
static void irc_cmd_nick( irc_t *irc, char **cmd )
{
	irc_user_t *iu;
	
	if( ( iu = irc_user_by_name( irc, cmd[1] ) ) && iu != irc->user )
	{
		irc_send_num( irc, 433, "%s :This nick is already in use", cmd[1] );
	}
	else if( !nick_ok( cmd[1] ) )
	{
		/* [SH] Invalid characters. */
		irc_send_num( irc, 432, "%s :This nick contains invalid characters", cmd[1] );
	}
	else if( irc->status & USTATUS_LOGGED_IN )
	{
		if( irc->status & USTATUS_IDENTIFIED )
		{
			irc_setpass( irc, NULL );
			irc->status &= ~USTATUS_IDENTIFIED;
			irc_umode_set( irc, "-R", 1 );
			irc_usermsg( irc, "Changing nicks resets your identify status. "
			             "Re-identify or register a new account if you want "
			             "your configuration to be saved. See \x02help "
			             "nick_changes\x02." );
		}
		
		irc_user_set_nick( irc->user, cmd[1] );
	}
	else
	{
		g_free( irc->user->nick );
		irc->user->nick = g_strdup( cmd[1] );
		
		irc_check_login( irc );
	}
}
Пример #5
0
static void cmd_moo(irc_t *irc, char **cmd) {
    irc_usermsg(irc, "%s", cmd[0]);
}
Пример #6
0
static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_name, const gchar **attr_names, const gchar **attr_values, gpointer data, GError **error )
{
	struct xml_parsedata *xd = data;
	irc_t *irc = xd->irc;
	
	if( xd->unknown_tag > 0 )
	{
		xd->unknown_tag ++;
	}
	else if( g_strcasecmp( element_name, "user" ) == 0 )
	{
		char *nick = xml_attr( attr_names, attr_values, "nick" );
		char *pass = xml_attr( attr_names, attr_values, "password" );
		int st;
		
		if( !nick || !pass )
		{
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Missing attributes for %s element", element_name );
		}
		else if( ( st = md5_verify_password( xd->given_pass, pass ) ) == -1 )
		{
			xd->pass_st = XML_PASS_WRONG;
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Error while decoding password attribute" );
		}
		else if( st == 0 )
		{
			if( xd->pass_st != XML_PASS_CHECK_ONLY )
				xd->pass_st = XML_PASS_OK;
		}
		else
		{
			xd->pass_st = XML_PASS_WRONG;
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Password mismatch" );
		}
	}
	else if( xd->pass_st < XML_PASS_OK )
	{
		/* Let's not parse anything else if we only have to check
		   the password. */
	}
	else if( g_strcasecmp( element_name, "account" ) == 0 )
	{
		char *protocol, *handle, *server, *password = NULL, *autoconnect, *tag;
		char *pass_b64 = NULL;
		unsigned char *pass_cr = NULL;
		int pass_len;
		struct prpl *prpl = NULL;
		
		handle = xml_attr( attr_names, attr_values, "handle" );
		pass_b64 = xml_attr( attr_names, attr_values, "password" );
		server = xml_attr( attr_names, attr_values, "server" );
		autoconnect = xml_attr( attr_names, attr_values, "autoconnect" );
		tag = xml_attr( attr_names, attr_values, "tag" );
		
		protocol = xml_attr( attr_names, attr_values, "protocol" );
		if( protocol )
			prpl = find_protocol( protocol );
		
		if( !handle || !pass_b64 || !protocol )
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Missing attributes for %s element", element_name );
		else if( !prpl )
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Unknown protocol: %s", protocol );
		else if( ( pass_len = base64_decode( pass_b64, (unsigned char**) &pass_cr ) ) &&
		                         arc_decode( pass_cr, pass_len, &password, xd->given_pass ) )
		{
			xd->current_account = account_add( irc->b, prpl, handle, password );
			if( server )
				set_setstr( &xd->current_account->set, "server", server );
			if( autoconnect )
				set_setstr( &xd->current_account->set, "auto_connect", autoconnect );
			if( tag )
				set_setstr( &xd->current_account->set, "tag", tag );
		}
		else
		{
			/* Actually the _decode functions don't even return error codes,
			   but maybe they will later... */
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Error while decrypting account password" );
		}
		
		g_free( pass_cr );
		g_free( password );
	}
	else if( g_strcasecmp( element_name, "setting" ) == 0 )
	{
		char *setting;
		
		if( xd->current_setting )
		{
			g_free( xd->current_setting );
			xd->current_setting = NULL;
		}
		
		if( ( setting = xml_attr( attr_names, attr_values, "name" ) ) )
		{
			if( xd->current_channel != NULL )
				xd->current_set_head = &xd->current_channel->set;
			else if( xd->current_account != NULL )
				xd->current_set_head = &xd->current_account->set;
			else
				xd->current_set_head = &xd->irc->b->set;
			
			xd->current_setting = g_strdup( setting );
		}
		else
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Missing attributes for %s element", element_name );
	}
	else if( g_strcasecmp( element_name, "buddy" ) == 0 )
	{
		char *handle, *nick;
		
		handle = xml_attr( attr_names, attr_values, "handle" );
		nick = xml_attr( attr_names, attr_values, "nick" );
		
		if( xd->current_account && handle && nick )
		{
			nick_set_raw( xd->current_account, handle, nick );
		}
		else
		{
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Missing attributes for %s element", element_name );
		}
	}
	else if( g_strcasecmp( element_name, "channel" ) == 0 )
	{
		char *name, *type;
		
		name = xml_attr( attr_names, attr_values, "name" );
		type = xml_attr( attr_names, attr_values, "type" );
		
		if( !name || !type )
		{
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Missing attributes for %s element", element_name );
			return;
		}
		
		/* The channel may exist already, for example if it's &bitlbee.
		   Also, it's possible that the user just reconnected and the
		   IRC client already rejoined all channels it was in. They
		   should still get the right settings. */
		if( ( xd->current_channel = irc_channel_by_name( irc, name ) ) ||
		    ( xd->current_channel = irc_channel_new( irc, name ) ) )
			set_setstr( &xd->current_channel->set, "type", type );
	}
	/* Backward compatibility: Keep this around for a while for people
	   switching from BitlBee 1.2.4+. */
	else if( g_strcasecmp( element_name, "chat" ) == 0 )
	{
		char *handle, *channel;
		
		handle = xml_attr( attr_names, attr_values, "handle" );
		channel = xml_attr( attr_names, attr_values, "channel" );
		
		if( xd->current_account && handle && channel )
		{
			irc_channel_t *ic;
			
			if( ( ic = irc_channel_new( irc, channel ) ) &&
			    set_setstr( &ic->set, "type", "chat" ) &&
			    set_setstr( &ic->set, "chat_type", "room" ) &&
			    set_setstr( &ic->set, "account", xd->current_account->tag ) &&
			    set_setstr( &ic->set, "room", handle ) )
			{
				/* Try to pick up some settings where possible. */
				xd->current_channel = ic;
			}
			else if( ic )
				irc_channel_free( ic );
		}
		else
		{
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Missing attributes for %s element", element_name );
		}
	}
	else
	{
		xd->unknown_tag ++;
		irc_usermsg( irc, "Warning: Unknown XML tag found in configuration file (%s). "
		                  "This may happen when downgrading BitlBee versions. "
		                  "This tag will be skipped and the information will be lost "
		                  "once you save your settings.", element_name );
		/*
		g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
		             "Unkown element: %s", element_name );
		*/
	}
}
Пример #7
0
static storage_status_t xml_save( irc_t *irc, int overwrite )
{
	char path[512], *path2, *pass_buf = NULL;
	set_t *set;
	account_t *acc;
	int fd;
	md5_byte_t pass_md5[21];
	md5_state_t md5_state;
	GSList *l;
	
	path2 = g_strdup( irc->user->nick );
	nick_lc( path2 );
	g_snprintf( path, sizeof( path ) - 2, "%s%s%s", global.conf->configdir, path2, ".xml" );
	g_free( path2 );
	
	if( !overwrite && g_access( path, F_OK ) == 0 )
		return STORAGE_ALREADY_EXISTS;
	
	strcat( path, ".XXXXXX" );
	if( ( fd = mkstemp( path ) ) < 0 )
	{
		irc_usermsg( irc, "Error while opening configuration file." );
		return STORAGE_OTHER_ERROR;
	}
	
	/* Generate a salted md5sum of the password. Use 5 bytes for the salt
	   (to prevent dictionary lookups of passwords) to end up with a 21-
	   byte password hash, more convenient for base64 encoding. */
	random_bytes( pass_md5 + 16, 5 );
	md5_init( &md5_state );
	md5_append( &md5_state, (md5_byte_t*) irc->password, strlen( irc->password ) );
	md5_append( &md5_state, pass_md5 + 16, 5 ); /* Add the salt. */
	md5_finish( &md5_state, pass_md5 );
	/* Save the hash in base64-encoded form. */
	pass_buf = base64_encode( pass_md5, 21 );
	
	if( !xml_printf( fd, 0, "<user nick=\"%s\" password=\"%s\" version=\"%d\">\n", irc->user->nick, pass_buf, XML_FORMAT_VERSION ) )
		goto write_error;
	
	g_free( pass_buf );
	
	for( set = irc->b->set; set; set = set->next )
		if( set->value && !( set->flags & SET_NOSAVE ) )
			if( !xml_printf( fd, 1, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) )
				goto write_error;
	
	for( acc = irc->b->accounts; acc; acc = acc->next )
	{
		unsigned char *pass_cr;
		char *pass_b64;
		int pass_len;
		
		pass_len = arc_encode( acc->pass, strlen( acc->pass ), (unsigned char**) &pass_cr, irc->password, 12 );
		pass_b64 = base64_encode( pass_cr, pass_len );
		g_free( pass_cr );
		
		if( !xml_printf( fd, 1, "<account protocol=\"%s\" handle=\"%s\" password=\"%s\" "
		                        "autoconnect=\"%d\" tag=\"%s\"", acc->prpl->name, acc->user,
		                        pass_b64, acc->auto_connect, acc->tag ) )
		{
			g_free( pass_b64 );
			goto write_error;
		}
		g_free( pass_b64 );
		
		if( acc->server && acc->server[0] && !xml_printf( fd, 0, " server=\"%s\"", acc->server ) )
			goto write_error;
		if( !xml_printf( fd, 0, ">\n" ) )
			goto write_error;
		
		for( set = acc->set; set; set = set->next )
			if( set->value && !( set->flags & ACC_SET_NOSAVE ) )
				if( !xml_printf( fd, 2, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) )
					goto write_error;
		
		/* This probably looks pretty strange. g_hash_table_foreach
		   is quite a PITA already (but it can't get much better in
		   C without using #define, I'm afraid), and since it
		   doesn't seem to be possible to abort the foreach on write
		   errors, so instead let's use the _find function and
		   return TRUE on write errors. Which means, if we found
		   something, there was an error. :-) */
		if( g_hash_table_find( acc->nicks, xml_save_nick, & fd ) )
			goto write_error;
		
		if( !xml_printf( fd, 1, "</account>\n" ) )
			goto write_error;
	}
	
	for( l = irc->channels; l; l = l->next )
	{
		irc_channel_t *ic = l->data;
		
		if( ic->flags & IRC_CHANNEL_TEMP )
			continue;
		
		if( !xml_printf( fd, 1, "<channel name=\"%s\" type=\"%s\">\n",
		                 ic->name, set_getstr( &ic->set, "type" ) ) )
			goto write_error;
		
		for( set = ic->set; set; set = set->next )
			if( set->value && strcmp( set->key, "type" ) != 0 )
				if( !xml_printf( fd, 2, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) )
					goto write_error;
		
		if( !xml_printf( fd, 1, "</channel>\n" ) )
			goto write_error;
	}
	
	if( !xml_printf( fd, 0, "</user>\n" ) )
		goto write_error;
	
	fsync( fd );
	close( fd );
	
	path2 = g_strndup( path, strlen( path ) - 7 );
	if( rename( path, path2 ) != 0 )
	{
		irc_usermsg( irc, "Error while renaming temporary configuration file." );
		
		g_free( path2 );
		unlink( path );
		
		return STORAGE_OTHER_ERROR;
	}
	
	g_free( path2 );
	
	return STORAGE_OK;

write_error:
	g_free( pass_buf );
	
	irc_usermsg( irc, "Write error. Disk full?" );
	close( fd );
	
	return STORAGE_OTHER_ERROR;
}
Пример #8
0
static storage_status_t xml_load_real( irc_t *irc, const char *my_nick, const char *password, xml_pass_st action )
{
	GMarkupParseContext *ctx;
	struct xml_parsedata *xd;
	char *fn, buf[512];
	GError *gerr = NULL;
	int fd, st;
	
	xd = g_new0( struct xml_parsedata, 1 );
	xd->irc = irc;
	xd->given_nick = g_strdup( my_nick );
	xd->given_pass = g_strdup( password );
	xd->pass_st = action;
	nick_lc( xd->given_nick );
	
	fn = g_strdup_printf( "%s%s%s", global.conf->configdir, xd->given_nick, ".xml" );
	if( ( fd = open( fn, O_RDONLY ) ) < 0 )
	{
		xml_destroy_xd( xd );
		g_free( fn );
		return STORAGE_NO_SUCH_USER;
	}
	g_free( fn );
	
	ctx = g_markup_parse_context_new( &xml_parser, 0, xd, xml_destroy_xd );
	
	while( ( st = read( fd, buf, sizeof( buf ) ) ) > 0 )
	{
		if( !g_markup_parse_context_parse( ctx, buf, st, &gerr ) || gerr )
		{
			xml_pass_st pass_st = xd->pass_st;
			
			g_markup_parse_context_free( ctx );
			close( fd );
			
			if( pass_st == XML_PASS_WRONG )
			{
				g_clear_error( &gerr );
				return STORAGE_INVALID_PASSWORD;
			}
			else
			{
				if( gerr && irc )
					irc_usermsg( irc, "Error from XML-parser: %s", gerr->message );
				
				g_clear_error( &gerr );
				return STORAGE_OTHER_ERROR;
			}
		}
	}
	/* Just to be sure... */
	g_clear_error( &gerr );
	
	g_markup_parse_context_free( ctx );
	close( fd );
	
	if( action == XML_PASS_CHECK_ONLY )
		return STORAGE_OK;
	
	return STORAGE_OK;
}