diff options
| -rw-r--r-- | otr.c | 319 | 
1 files changed, 183 insertions, 136 deletions
| @@ -47,24 +47,22 @@ const char *op_account_name(void *opdata, const char *account, const char *proto  /** otr sub-command handlers: **/ -/* TODO: void cmd_otr_keygen(irc_t *irc, char **args); */ -void cmd_otr_abort(irc_t *irc, char **args); /* TODO: does this cmd even make sense? */ -void cmd_otr_request(irc_t *irc, char **args); /* TODO: do we even need this? */ +void cmd_otr_connect(irc_t *irc, char **args); +void cmd_otr_disconnect(irc_t *irc, char **args);  void cmd_otr_smp(irc_t *irc, char **args);  void cmd_otr_trust(irc_t *irc, char **args); -/* TODO: void cmd_otr_affirm(irc_t *irc, char **args); */ -void cmd_otr_fprints(irc_t *irc, char **args);  void cmd_otr_info(irc_t *irc, char **args); -void cmd_otr_policy(irc_t *irc, char **args); +/* void cmd_otr_forget(irc_t *irc, char **args); */  const command_t otr_commands[] = { -	{ "abort",    1, &cmd_otr_abort,    0 }, -	{ "request",  1, &cmd_otr_request,  0 }, -	{ "smp",      2, &cmd_otr_smp,      0 }, -	{ "trust",    6, &cmd_otr_trust,    0 }, -	{ "fprints",  0, &cmd_otr_fprints,  0 }, -	{ "info",     1, &cmd_otr_info,     0 }, -	{ "policy",   0, &cmd_otr_policy,   0 }, +	{ "connect",     1, &cmd_otr_connect,    0 }, +	{ "disconnect",  1, &cmd_otr_disconnect, 0 }, +	{ "smp",         2, &cmd_otr_smp,        0 }, +	{ "trust",       6, &cmd_otr_trust,      0 }, +	{ "info",        0, &cmd_otr_info,       0 }, +	/* +	{ "forget",      1, &cmd_otr_forget,     0 }, +	*/  	{ NULL }  }; @@ -100,6 +98,9 @@ struct im_connection *check_imc(void *opdata, const char *accountname,     returns "handle/protocol" if not found */  const char *peernick(irc_t *irc, const char *handle, const char *protocol); +/* turn a hexadecimal digit into its numerical value */ +int hexval(char a); +  /* determine the user_t for a given handle/protocol pair     returns NULL if not found */  user_t *peeruser(irc_t *irc, const char *handle, const char *protocol); @@ -112,11 +113,16 @@ void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs)     i.e. msgstate should be announced seperately */  int otr_update_modeflags(irc_t *irc, user_t *u); +/* show general info about the OTR subsystem; called by 'otr info' */ +void show_general_otr_info(irc_t *irc); + +/* show info about a given OTR context */ +void show_otr_context_info(irc_t *irc, ConnContext *ctx); +  /* show the list of fingerprints associated with a given context */  void show_fingerprints(irc_t *irc, ConnContext *ctx); -  /*** routines declared in otr.h: ***/  void otr_init(void) @@ -488,8 +494,8 @@ void op_gone_secure(void *opdata, ConnContext *context)  	u = peeruser(ic->irc, context->username, context->protocol);  	if(!u) {  		log_message(LOGLVL_ERROR, -			"BUG: otr.c: op_gone_secure: user_t for %s/%s not found!", -			context->username, context->protocol); +			"BUG: otr.c: op_gone_secure: user_t for %s/%s/%s not found!", +			context->username, context->protocol, context->accountname);  		return;  	}  	if(context->active_fingerprint->trust[0]) @@ -511,8 +517,8 @@ void op_gone_insecure(void *opdata, ConnContext *context)  	u = peeruser(ic->irc, context->username, context->protocol);  	if(!u) {  		log_message(LOGLVL_ERROR, -			"BUG: otr.c: op_gone_insecure: user_t for %s/%s not found!", -			context->username, context->protocol); +			"BUG: otr.c: op_gone_insecure: user_t for %s/%s/%s not found!", +			context->username, context->protocol, context->accountname);  		return;  	}  	u->encrypted = 0; @@ -532,8 +538,8 @@ void op_still_secure(void *opdata, ConnContext *context, int is_reply)  	u = peeruser(ic->irc, context->username, context->protocol);  	if(!u) {  		log_message(LOGLVL_ERROR, -			"BUG: otr.c: op_still_secure: user_t for %s/%s not found!", -			context->username, context->protocol); +			"BUG: otr.c: op_still_secure: user_t for %s/%s/%s not found!", +			context->username, context->protocol, context->accountname);  		return;  	}  	if(context->active_fingerprint->trust[0]) @@ -573,7 +579,7 @@ const char *op_account_name(void *opdata, const char *account, const char *proto  /*** OTR sub-command handlers ***/ -void cmd_otr_abort(irc_t *irc, char **args) +void cmd_otr_disconnect(irc_t *irc, char **args)  {  	user_t *u; @@ -587,7 +593,7 @@ void cmd_otr_abort(irc_t *irc, char **args)  		u->ic, u->ic->acc->user, u->ic->acc->prpl->name, u->handle);  } -void cmd_otr_request(irc_t *irc, char **args) +void cmd_otr_connect(irc_t *irc, char **args)  {  	user_t *u; @@ -651,20 +657,6 @@ void cmd_otr_smp(irc_t *irc, char **args)  	}  } -int hexval(char a) -{ -	int x=tolower(a); -	 -	if(x>='a' && x<='f') -		x = x - 'a' + 10; -	else if(x>='0' && x<='9') -		x = x - '0'; -	else -		return -1; -	 -	return x; -} -  void cmd_otr_trust(irc_t *irc, char **args)  {  	user_t *u; @@ -725,112 +717,59 @@ void cmd_otr_trust(irc_t *irc, char **args)  	}  } -void cmd_otr_fprints(irc_t *irc, char **args) +void cmd_otr_info(irc_t *irc, char **args)  { -	if(args[1]) { -		/* list given buddy's fingerprints */ -		user_t *u; -		ConnContext *ctx; -	 -		u = user_find(irc, args[1]); -		if(!u || !u->ic) { -			irc_usermsg(irc, "%s: unknown user", args[1]); -			return; -		} -	 -		ctx = otrl_context_find(irc->otr_us, u->handle, -			u->ic->acc->user, u->ic->acc->prpl->name, 0, NULL, NULL, NULL); -		if(!ctx) { -			irc_usermsg(irc, "no fingerprints"); -		} else { -			show_fingerprints(irc, ctx); -		} +	if(!args[1]) { +		show_general_otr_info(irc);  	} else { -		/* list all known fingerprints */ +		char *arg = g_strdup(args[1]); +		char *myhandle, *handle, *protocol;  		ConnContext *ctx; -		for(ctx=irc->otr_us->context_root; ctx; ctx=ctx->next) { -			irc_usermsg(irc, "[%s]", peernick(irc, ctx->username, ctx->protocol)); -			show_fingerprints(irc, ctx); -		} -		if(!irc->otr_us->context_root) { -			irc_usermsg(irc, "no fingerprints"); +		 +		/* interpret arg as 'user/protocol/account' if possible */ +		protocol = strchr(arg, '/'); +		if(protocol) { +			*(protocol++) = '\0'; +			myhandle = strchr(protocol, '/'); +			if(!myhandle) { +				/* TODO: try to find a unique account for this context */ +			}  		} -	} -} - -void cmd_otr_info(irc_t *irc, char **args) -{ -	user_t *u; -	ConnContext *ctx; -	Fingerprint *fp; -	char human[45]; -	const char *offer_status; -	const char *message_state; -	const char *trust; - -	if(!args) { -		irc_usermsg(irc, "no args?!"); -		return; -	} -	if(!args[1]) { -		irc_usermsg(irc, "no args[1]?!"); -		return; -	} -	u = user_find(irc, args[1]); -	if(!u || !u->ic) { -		irc_usermsg(irc, "%s: unknown user", args[1]); -		return; -	} -	 -	ctx = otrl_context_find(irc->otr_us, u->handle, -		u->ic->acc->user, u->ic->acc->prpl->name, 0, NULL, NULL, NULL); -	if(!ctx) { -		irc_usermsg(irc, "no otr context with %s", args[1]); -		return; -	} - -	switch(ctx->otr_offer) { -	case OFFER_NOT:       offer_status="none sent";          break; -	case OFFER_SENT:      offer_status="awaiting reply";     break; -	case OFFER_ACCEPTED:  offer_status="accepted our offer"; break; -	case OFFER_REJECTED:  offer_status="ignored our offer";  break; -	default:              offer_status="?"; -	} - -	switch(ctx->msgstate) { -	case OTRL_MSGSTATE_PLAINTEXT: message_state="cleartext"; break; -	case OTRL_MSGSTATE_ENCRYPTED: message_state="encrypted"; break; -	case OTRL_MSGSTATE_FINISHED:  message_state="shut down"; break; -	default:                      message_state="?"; -	} - -	irc_usermsg(irc, "%s is %s/%s; we are %s/%s to them", args[1], -		ctx->username, ctx->protocol, ctx->accountname, ctx->protocol); -	irc_usermsg(irc, "  otr offer status: %s", offer_status); -	irc_usermsg(irc, "  connection state: %s", message_state); -	 -	if(ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) { -		irc_usermsg(irc, "  protocol version: %d", ctx->protocol_version); -		fp = ctx->active_fingerprint; -		if(!fp) { -			irc_usermsg(irc, "  active f'print:   none?"); +		if(protocol && myhandle) { +			*(myhandle++) = '\0'; +			handle = arg; +			ctx = otrl_context_find(irc->otr_us, handle, myhandle, protocol, 0, NULL, NULL, NULL); +			if(!ctx) { +				irc_usermsg(irc, "no such context (%s %s %s)", handle, protocol, myhandle); +				g_free(arg); +				return; +			}  		} else { -			otrl_privkey_hash_to_human(human, fp->fingerprint); -			if(!fp->trust || fp->trust[0] == '\0') { -				trust="untrusted"; -			} else { -				trust=fp->trust; +			user_t *u = user_find(irc, args[1]); +			if(!u || !u->ic) { +				irc_usermsg(irc, "%s: unknown user", args[1]); +				g_free(arg); +				return; +			} +			ctx = otrl_context_find(irc->otr_us, u->handle, u->ic->acc->user, +				u->ic->acc->prpl->name, 0, NULL, NULL, NULL); +			if(!ctx) { +				irc_usermsg(irc, "no otr context with %s", args[1]); +				g_free(arg); +				return;  			} -			irc_usermsg(irc, "  active f'print:   %s (%s)", human, trust);  		} +	 +		/* show how we resolved the (nick) argument, if we did */ +		if(handle!=arg) { +			irc_usermsg(irc, "%s is %s/%s; we are %s/%s to them", args[1], +				ctx->username, ctx->protocol, ctx->accountname, ctx->protocol); +		} +		show_otr_context_info(irc, ctx); +		g_free(arg);  	}  } -void cmd_otr_policy(irc_t *irc, char **args) -{ -	irc_usermsg(irc, "n/a: not implemented"); -} -  /*** local helpers / subroutines: ***/ @@ -952,10 +891,12 @@ user_t *peeruser(irc_t *irc, const char *handle, const char *protocol)  {  	user_t *u; +	log_message(LOGLVL_DEBUG, "peeruser '%s' '%s'", handle, protocol); +	  	for(u=irc->users; u; u=u->next) {  		struct prpl *prpl;  		if(!u->ic || !u->handle) -			break; +			continue;  		prpl = u->ic->acc->prpl;  		if(strcmp(prpl->name, protocol) == 0  			&& prpl->handle_cmp(u->handle, handle) == 0) { @@ -966,6 +907,20 @@ user_t *peeruser(irc_t *irc, const char *handle, const char *protocol)  	return NULL;  } +int hexval(char a) +{ +	int x=tolower(a); +	 +	if(x>='a' && x<='f') +		x = x - 'a' + 10; +	else if(x>='0' && x<='9') +		x = x - '0'; +	else +		return -1; +	 +	return x; +} +  const char *peernick(irc_t *irc, const char *handle, const char *protocol)  {  	static char fallback[512]; @@ -1053,13 +1008,105 @@ void show_fingerprints(irc_t *irc, ConnContext *ctx)  			trust=fp->trust;  		}  		if(fp == ctx->active_fingerprint) { -			irc_usermsg(irc, "\x02%s (%s)\x02", human, trust); +			irc_usermsg(irc, "  \x02%s (%s)\x02", human, trust);  		} else { -			irc_usermsg(irc, "%s (%s)", human, trust); +			irc_usermsg(irc, "  %s (%s)", human, trust);  		}  	}  	if(count==0) -		irc_usermsg(irc, "no fingerprints"); +		irc_usermsg(irc, "  no fingerprints"); +} + +void show_general_otr_info(irc_t *irc) +{ +	ConnContext *ctx; +	OtrlPrivKey *key; +	char human[45]; + +	/* list all privkeys */ +	irc_usermsg(irc, "\x1fprivate keys:\x1f"); +	for(key=irc->otr_us->privkey_root; key; key=key->next) { +		const char *hash; +		 +		switch(key->pubkey_type) { +		case OTRL_PUBKEY_TYPE_DSA: +			irc_usermsg(irc, "  %s/%s - DSA", key->accountname, key->protocol); +			break; +		default: +			irc_usermsg(irc, "  %s/%s - type %d", key->accountname, key->protocol, +				key->pubkey_type); +		} + +		/* No, it doesn't make much sense to search for the privkey again by +		   account/protocol, but libotr currently doesn't provide a direct routine +		   for hashing a given 'OtrlPrivKey'... */ +		hash = otrl_privkey_fingerprint(irc->otr_us, human, key->accountname, key->protocol); +		if(hash) /* should always succeed */ +			irc_usermsg(irc, "    %s", human); +	} + +	/* list all contexts */ +	irc_usermsg(irc, "%s", ""); +	irc_usermsg(irc, "\x1f" "connection contexts:\x1f (bold=currently encrypted)"); +	for(ctx=irc->otr_us->context_root; ctx; ctx=ctx->next) {\ +		user_t *u; +		char *userstring; +		 +		u = peeruser(irc, ctx->username, ctx->protocol); +		if(u) +			userstring = g_strdup_printf("%s/%s/%s (%s)", +				ctx->username, ctx->protocol, ctx->accountname, u->nick); +		else +			userstring = g_strdup_printf("%s/%s/%s", +				ctx->username, ctx->protocol, ctx->accountname); +		 +		if(ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) { +			otrl_privkey_hash_to_human(human, ctx->active_fingerprint->fingerprint); +			irc_usermsg(irc, "  \x02%s\x02", userstring); +			irc_usermsg(irc, "    %s", human); +		} else { +			irc_usermsg(irc, "  %s", userstring); +		} +		 +		g_free(userstring); +	} +} + +void show_otr_context_info(irc_t *irc, ConnContext *ctx) +{ +	switch(ctx->otr_offer) { +	case OFFER_NOT: +		irc_usermsg(irc, "  otr offer status: none sent"); +		break; +	case OFFER_SENT: +		irc_usermsg(irc, "  otr offer status: awaiting reply"); +		break; +	case OFFER_ACCEPTED: +		irc_usermsg(irc, "  otr offer status: accepted our offer"); +		break; +	case OFFER_REJECTED: +		irc_usermsg(irc, "  otr offer status: ignored our offer"); +		break; +	default: +		irc_usermsg(irc, "  otr offer status: %d", ctx->otr_offer); +	} + +	switch(ctx->msgstate) { +	case OTRL_MSGSTATE_PLAINTEXT: +		irc_usermsg(irc, "  connection state: cleartext"); +		break; +	case OTRL_MSGSTATE_ENCRYPTED: +		irc_usermsg(irc, "  connection state: encrypted (v%d)", ctx->protocol_version); +		break; +	case OTRL_MSGSTATE_FINISHED: +		irc_usermsg(irc, "  connection state: shut down"); +		break; +	default: +		irc_usermsg(irc, "  connection state: %d", ctx->msgstate); +	} + +    irc_usermsg(irc, "  known fingerprints: (bold=active)");	 +	show_fingerprints(irc, ctx);  }  void otr_keygen(irc_t *irc, const char *handle, const char *protocol) | 
