예제 #1
0
파일: otr.c 프로젝트: KwadroNaut/irssi-otr
/*
 * implements /otr authabort
 */
void otr_auth_abort(SERVER_REC *irssi, const char *nick)
{
	ConnContext *ctx;

	assert(irssi);
	assert(nick);

	ctx = otr_find_context(irssi, nick, FALSE);
	if (!ctx) {
		IRSSI_NOTICE(irssi, nick, "Context for %9%s%9 not found.", nick);
		goto end;
	}

	otrl_message_abort_smp(user_state_global->otr_state, &otr_ops, irssi, ctx);
	otr_status_change(irssi, nick, OTR_STATUS_SMP_ABORT);

	if (ctx->smstate->nextExpected != OTRL_SMP_EXPECT1) {
		IRSSI_NOTICE(irssi, nick, "%rOngoing authentication aborted%n");
	} else {
		IRSSI_NOTICE(irssi, nick, "%rAuthentication aborted%n");
	}

end:
	return;
}
예제 #2
0
/*
 * Gone insecure.
 */
static void ops_insecure(void *opdata, ConnContext *context)
{
	SERVER_REC *irssi = opdata;

	IRSSI_NOTICE(irssi, context->username, "Gone %rinsecure%r");
	otr_status_change(irssi, context->username, OTR_STATUS_GONE_INSECURE);
}
예제 #3
0
파일: otr.c 프로젝트: KwadroNaut/irssi-otr
/*
 * Trust our peer.
 */
void otr_trust(SERVER_REC *irssi, const char *nick, char *str_fp,
		struct otr_user_state *ustate)
{
	char peerfp[OTRL_PRIVKEY_FPRINT_HUMAN_LEN];
	struct otr_peer_context *opc;
	ConnContext *ctx;
	Fingerprint *fp_trust;

	assert(ustate);

	if (!irssi && !str_fp) {
		IRSSI_NOTICE(NULL, nick, "Need a fingerprint!");
		goto error;
	}

	/* No human string fingerprint given. */
	if (!str_fp) {
		ctx = otr_find_context(irssi, nick, FALSE);
		if (!ctx) {
			goto error;
		}

		opc = ctx->app_data;
		/* Always NEED a peer context or else code error. */
		assert(opc);

		fp_trust = ctx->active_fingerprint;
	} else {
		fp_trust = otr_find_hash_fingerprint_from_human(str_fp, ustate);
	}

	if (fp_trust) {
		int ret;

		ret = otrl_context_is_fingerprint_trusted(fp_trust);
		if (ret) {
			IRSSI_NOTICE(irssi, nick, "Already trusted!");
			goto end;
		}

		/* Trust level is manual at this point. */
		otrl_context_set_trust(fp_trust, "manual");
		key_write_fingerprints(ustate);

		otr_status_change(irssi, nick, OTR_STATUS_TRUST_MANUAL);

		otrl_privkey_hash_to_human(peerfp, fp_trust->fingerprint);
		IRSSI_NOTICE(irssi, nick, "Fingerprint %g%s%n trusted!", peerfp);
	} else {
		IRSSI_NOTICE(irssi, nick, "Fingerprint %y%s%n NOT found",
				(str_fp != NULL) ? str_fp : "");
	}

end:
error:
	return;
}
예제 #4
0
static void ops_smp_event(void *opdata, OtrlSMPEvent smp_event,
		ConnContext *context, unsigned short progress_percent, char *question)
{
	SERVER_REC *irssi = opdata;
	const char *from = context->username;
	struct otr_peer_context *opc = context->app_data;

	/*
	 * Without a peer context, we can't update the status bar. Code flow error
	 * if none is found. This context is created automatically by an otrl_*
	 * call or if non existent when returned from
	 * otrl_message_sending/receiving.
	 */
	assert(opc);

	opc->smp_event = smp_event;

	switch (smp_event) {
	case OTRL_SMPEVENT_ASK_FOR_SECRET:
		IRSSI_NOTICE(irssi, from, "%9%s%9 wants to authenticate. "
				"Type %9/otr auth <SECRET>%9 to complete.", from);
		opc->ask_secret = 1;
		otr_status_change(irssi, from, OTR_STATUS_SMP_INCOMING);
		break;
	case OTRL_SMPEVENT_ASK_FOR_ANSWER:
		IRSSI_NOTICE(irssi, from, "%9%s%9 wants to authenticate and "
				"asked this question:", from);
		IRSSI_NOTICE(irssi, from, "%b>%n %y%s%n", question);
		IRSSI_NOTICE(irssi, from, "Type %9/otr auth <SECRET>%9 to complete.");
		opc->ask_secret = 1;
		otr_status_change(irssi, from, OTR_STATUS_SMP_INCOMING);
		break;
	case OTRL_SMPEVENT_IN_PROGRESS:
		IRSSI_NOTICE(irssi, from, "%9%s%9 replied to our auth request",
				from);
		otr_status_change(irssi, from, OTR_STATUS_SMP_FINALIZE);
		break;
	case OTRL_SMPEVENT_SUCCESS:
		IRSSI_NOTICE(irssi, from, "%gAuthentication successful.%n");
		otr_status_change(irssi, from, OTR_STATUS_SMP_SUCCESS);
		break;
	case OTRL_SMPEVENT_ABORT:
		otr_auth_abort(irssi, context->username);
		otr_status_change(irssi, from, OTR_STATUS_SMP_ABORTED);
		break;
	case OTRL_SMPEVENT_FAILURE:
	case OTRL_SMPEVENT_CHEATED:
	case OTRL_SMPEVENT_ERROR:
		IRSSI_NOTICE(irssi, from, "%RAuthentication failed%n");
		otr_status_change(irssi, from, OTR_STATUS_SMP_FAILED);
		break;
	default:
		IRSSI_NOTICE(irssi, from, "Received unknown SMP event. "
			"Ignoring");
		break;
	}
}
예제 #5
0
/*
 * Gone secure.
 */
static void ops_secure(void *opdata, ConnContext *context)
{
	int ret;
	char ownfp[OTRL_PRIVKEY_FPRINT_HUMAN_LEN];
	char peerfp[OTRL_PRIVKEY_FPRINT_HUMAN_LEN];
	SERVER_REC *irssi = opdata;
	struct otr_peer_context *opc;

	assert(context);
	/* This should *really* not happened */
	assert(context->msgstate == OTRL_MSGSTATE_ENCRYPTED);

	IRSSI_NOTICE(irssi, context->username, "Gone %9secure%9");
	otr_status_change(irssi, context->username, OTR_STATUS_GONE_SECURE);

	opc = context->app_data;
	opc->active_fingerprint = context->active_fingerprint;

	ret = otrl_context_is_fingerprint_trusted(context->active_fingerprint);
	if (ret) {
		/* Secure and trusted */
		goto end;
	}

	/* Not authenticated. Let's print out the fingerprints for comparison. */
	otrl_privkey_hash_to_human(peerfp,
			context->active_fingerprint->fingerprint);
	otrl_privkey_fingerprint(user_state_global->otr_state, ownfp,
			context->accountname, OTR_PROTOCOL_ID);

	IRSSI_NOTICE(irssi, context->username, "Your peer is not "
			"authenticated. To make sure you're talking to the right person you can "
			"either agree on a secret and use the authentication command "
			"%9/otr auth%9 or %9/otr authq [QUESTION] SECRET%9. You can also "
			"use the traditional way and compare fingerprints "
			"(e.g. telephone or GPG-signed mail) and subsequently enter "
			"%9/otr trust%9.");

	IRSSI_NOTICE(irssi, context->username, "Your fingerprint is: %y%s%n",
			ownfp);
	IRSSI_NOTICE(irssi, context->username, "%9%s's%9 fingerprint is: %r%s%n",
			context->username, peerfp);

end:
	return;
}
예제 #6
0
static void ops_smp_event(void *opdata, OtrlSMPEvent smp_event,
		   ConnContext *context, unsigned short progress_percent,
		   char *question)
{
	IRC_CTX *ircctx = (opdata);
	char *from = context->username;
	struct co_info *coi = context->app_data;

	coi->received_smp_init =
		(smp_event == OTRL_SMPEVENT_ASK_FOR_SECRET) ||
		(smp_event == OTRL_SMPEVENT_ASK_FOR_ANSWER);

	switch (smp_event) {
	case OTRL_SMPEVENT_ASK_FOR_SECRET:
		otr_notice(ircctx, from, TXT_AUTH_PEER,
			   from);
		otr_status_change(ircctx, from, IO_STC_SMP_INCOMING);
		break;
	case OTRL_SMPEVENT_ASK_FOR_ANSWER:
		otr_notice(ircctx, from, TXT_AUTH_PEER_QA, from, question);
		otr_status_change(ircctx, from, IO_STC_SMP_INCOMING);
		break;
	case OTRL_SMPEVENT_IN_PROGRESS:
		otr_notice(ircctx, from,
			   TXT_AUTH_PEER_REPLIED,
			   from);
		otr_status_change(ircctx, from, IO_STC_SMP_FINALIZE);
		break;
	case OTRL_SMPEVENT_SUCCESS:
		otr_notice(ircctx, from,
			   TXT_AUTH_SUCCESSFUL);
		otr_status_change(ircctx, from, IO_STC_SMP_SUCCESS);
		break;
	case OTRL_SMPEVENT_ABORT:
		otr_abort_auth(context, ircctx, from);
		otr_status_change(ircctx, from, IO_STC_SMP_ABORTED);
		break;
	case OTRL_SMPEVENT_FAILURE:
	case OTRL_SMPEVENT_CHEATED:
	case OTRL_SMPEVENT_ERROR:
		otr_notice(ircctx, from, TXT_AUTH_FAILED);
		coi->smp_failed = TRUE;
		otr_status_change(ircctx, from, IO_STC_SMP_FAILED);
		break;
	default:
		otr_logst(MSGLEVEL_CRAP, "Received unknown SMP event");
		break;
	}
}
예제 #7
0
파일: otr.c 프로젝트: KwadroNaut/irssi-otr
/*
 * Finish the conversation.
 */
void otr_finish(SERVER_REC *irssi, const char *nick)
{
	ConnContext *ctx;

	assert(irssi);
	assert(nick);

	ctx = otr_find_context(irssi, nick, FALSE);
	if (!ctx) {
		IRSSI_INFO(irssi, nick, "Nothing to do");
		goto end;
	}

	otrl_message_disconnect(user_state_global->otr_state, &otr_ops, irssi,
			ctx->accountname, OTR_PROTOCOL_ID, nick, ctx->their_instance);

	otr_status_change(irssi, nick, OTR_STATUS_FINISHED);

	IRSSI_INFO(irssi, nick, "Finished conversation with %9%s%9",
			nick);

end:
	return;
}
예제 #8
0
/*
 * A context changed.
 */
static void ops_up_ctx_list(void *opdata)
{
	otr_status_change(opdata, NULL, OTR_STATUS_CTX_UPDATE);
}
예제 #9
0
파일: otr.c 프로젝트: KwadroNaut/irssi-otr
/*
 * Hand the given message to OTR.
 *
 * Returns 0 if its an OTR protocol message or else negative value.
 */
int otr_receive(SERVER_REC *irssi, const char *msg, const char *from,
		char **new_msg)
{
	int ret = -1;
	char *accname = NULL, *full_msg = NULL;
	const char *recv_msg = NULL;
	OtrlTLV *tlvs;
	ConnContext *ctx;
	struct otr_peer_context *opc;

	assert(irssi);

	accname = create_account_name(irssi);
	if (!accname) {
		goto error;
	}

	IRSSI_DEBUG("Receiving message...");

	ctx = otr_find_context(irssi, from, 1);
	if (!ctx) {
		goto error;
	}

	/* Add peer context to OTR context if none exists */
	if (!ctx->app_data) {
		add_peer_context_cb(irssi, ctx);
	}

	opc = ctx->app_data;
	assert(opc);

	ret = enqueue_otr_fragment(msg, opc, &full_msg);
	switch (ret) {
	case OTR_MSG_ORIGINAL:
		recv_msg = msg;
		break;
	case OTR_MSG_WAIT_MORE:
		ret = 1;
		goto error;
	case OTR_MSG_USE_QUEUE:
		recv_msg = full_msg;
		break;
	case OTR_MSG_ERROR:
		ret = -1;
		goto error;
	}

	ret = otrl_message_receiving(user_state_global->otr_state,
		&otr_ops, irssi, accname, OTR_PROTOCOL_ID, from, recv_msg, new_msg,
		&tlvs, &ctx, add_peer_context_cb, irssi);
	if (ret) {
		IRSSI_DEBUG("Ignoring message of length %d from %s to %s.\n"
				"%s", strlen(msg), from, accname, msg);
	} else {
		if (*new_msg) {
			IRSSI_DEBUG("Converted received message.");
		}
	}

	/* Check for disconnected message */
	OtrlTLV *tlv = otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED);
	if (tlv) {
		otr_status_change(irssi, from, OTR_STATUS_PEER_FINISHED);
		IRSSI_NOTICE(irssi, from, "%9%s%9 has finished the OTR "
				"conversation. If you want to continue talking enter "
				"%9/otr finish%9 for plaintext or %9/otr init%9 to restart.",
				from);
	}

	otrl_tlv_free(tlvs);

	IRSSI_DEBUG("Message received.");

error:
	if (full_msg) {
		free(full_msg);
	}
	free(accname);
	return ret;
}
예제 #10
0
파일: otr.c 프로젝트: KwadroNaut/irssi-otr
/*
 * Initiate or respond to SMP authentication.
 */
void otr_auth(SERVER_REC *irssi, const char *nick, const char *question,
		const char *secret)
{
	int ret;
	size_t secret_len = 0;
	ConnContext *ctx;
	struct otr_peer_context *opc;

	assert(irssi);
	assert(nick);

	ctx = otr_find_context(irssi, nick, 0);
	if (!ctx) {
		IRSSI_NOTICE(irssi, nick, "Context for %9%s%9 not found.", nick);
		goto end;
	}

	opc = ctx->app_data;
	/* Again, code flow error. */
	assert(opc);

	if (ctx->msgstate != OTRL_MSGSTATE_ENCRYPTED) {
		IRSSI_INFO(irssi, nick,
				"You need to establish an OTR session before you "
				"can authenticate.");
		goto end;
	}

	/* Aborting an ongoing auth */
	if (ctx->smstate->nextExpected != OTRL_SMP_EXPECT1) {
		otr_auth_abort(irssi, nick);
	}

	/* reset trust level */
	if (ctx->active_fingerprint) {
		ret = otrl_context_is_fingerprint_trusted(ctx->active_fingerprint);
		if (!ret) {
			otrl_context_set_trust(ctx->active_fingerprint, "");
			key_write_fingerprints(user_state_global);
		}
	}

	/* Libotr allows empty secret. */
	if (secret) {
		secret_len = strlen(secret);
	}

	if (opc->ask_secret) {
		otrl_message_respond_smp(user_state_global->otr_state, &otr_ops,
				irssi, ctx, (unsigned char *) secret, secret_len);
		otr_status_change(irssi, nick, OTR_STATUS_SMP_RESPONDED);
		IRSSI_NOTICE(irssi, nick, "%yResponding to authentication...%n");
	} else {
		if (question) {
			otrl_message_initiate_smp_q(user_state_global->otr_state,
				&otr_ops, irssi, ctx, question, (unsigned char *) secret,
				secret_len);
		} else {
			otrl_message_initiate_smp(user_state_global->otr_state,
				&otr_ops, irssi, ctx, (unsigned char *) secret, secret_len);
		}
		otr_status_change(irssi, nick, OTR_STATUS_SMP_STARTED);
		IRSSI_NOTICE(irssi, nick, "%yInitiated authentication...%n");
	}

	opc->ask_secret = 0;

end:
	return;
}