diff options
| author | Sven Moritz Hallberg <sm@khjk.org> | 2008-02-09 18:58:13 +0100 | 
|---|---|---|
| committer | Sven Moritz Hallberg <sm@khjk.org> | 2008-02-09 18:58:13 +0100 | 
| commit | 5a71d9c5b14aa749b532666b71b25ce2afcdc5bb (patch) | |
| tree | 5e6ec25cb526a9940ba6ba4c63dc590a8991679f /otr.c | |
| parent | a13855a57daae6eba05c9600b69f640c2949e944 (diff) | |
- add support for setting ops/voice according to OTR msgstate
- add 'otr trust' user command
- support non-otr messages during keygen
- run otr messages through strip_html
- interpret <b> and <i> tags in html messages
- record max message size in prpl
- add 'encrypted' flag to user_t
- cosmetics
Diffstat (limited to 'otr.c')
| -rw-r--r-- | otr.c | 286 | 
1 files changed, 236 insertions, 50 deletions
| @@ -34,8 +34,6 @@ void op_write_fingerprints(void *opdata);  void op_gone_secure(void *opdata, ConnContext *context); -void op_gone_secure(void *opdata, ConnContext *context); -  void op_gone_insecure(void *opdata, ConnContext *context);  void op_still_secure(void *opdata, ConnContext *context, int is_reply); @@ -52,7 +50,8 @@ const char *op_account_name(void *opdata, const char *account, const char *proto  /* 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_auth(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); @@ -61,7 +60,8 @@ void cmd_otr_policy(irc_t *irc, char **args);  const command_t otr_commands[] = {  	{ "abort",    1, &cmd_otr_abort,    0 },  	{ "request",  1, &cmd_otr_request,  0 }, -	{ "auth",     2, &cmd_otr_auth,     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 }, @@ -96,12 +96,22 @@ void no_keygen(gpointer w, void *data);  struct im_connection *check_imc(void *opdata, const char *accountname,  	const char *protocol); -/* determine the nick for a given handle/protocol pair */ +/* determine the nick for a given handle/protocol pair +   returns "handle/protocol" if not found */  const char *peernick(irc_t *irc, const char *handle, const char *protocol); +/* 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); +  /* handle SMP TLVs from a received message */  void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs); +/* update op/voice flag of given user according to encryption state and settings +   returns 0 if neither op_buddies nor voice_buddies is set to "encrypted", +   i.e. msgstate should be announced seperately */ +int otr_update_modeflags(irc_t *irc, user_t *u); +  /* show the list of fingerprints associated with a given context */  void show_fingerprints(irc_t *irc, ConnContext *ctx); @@ -238,8 +248,15 @@ char *otr_handle_message(struct im_connection *ic, const char *handle, const cha  	char *colormsg;      if(!g_mutex_trylock(ic->irc->otr_mutex)) { -    	/* TODO: queue msgs received during keygen for later */ -		irc_usermsg(ic->irc, "msg from %s during keygen - dropped", +    	user_t *u = user_findhandle(ic, handle); +    	 +    	/* fallback for non-otr clients */ +    	if(u && !u->encrypted) { +    		return g_strdup(msg); +    	} +    	 +    	/* TODO: queue msgs received during keygen for later? */ +		irc_usermsg(ic->irc, "otr msg from %s during keygen - dropped",  			peernick(ic->irc, handle, ic->acc->prpl->name));  		return NULL;  	} @@ -282,14 +299,24 @@ char *otr_handle_message(struct im_connection *ic, const char *handle, const cha  int otr_send_message(struct im_connection *ic, const char *handle, const char *msg, int flags)  {	 -    int st; -    char *otrmsg = NULL; -    ConnContext *ctx = NULL; -     +	int st; +	char *otrmsg = NULL; +	ConnContext *ctx = NULL; +	      if(!g_mutex_trylock(ic->irc->otr_mutex)) { -    	irc_usermsg(ic->irc, "msg to %s during keygen - not sent", -    		peernick(ic->irc, handle, ic->acc->prpl->name)); -    	return 1; +		user_t *u = user_findhandle(ic, handle); +    	 +		/* Fallback for non-otr clients. +		   Yes, we must be very sure this doesn't send stuff in the clear where it +		   shouldn't... */ +		if(u && !u->encrypted) { +			return ic->acc->prpl->buddy_msg(ic, (char *)handle, (char *)msg, flags); +		} +		 +		/* otherwise refuse to send */ +		irc_usermsg(ic->irc, "otr msg to %s not sent during keygen", +			peernick(ic->irc, handle, ic->acc->prpl->name)); +		return 1;      }  	st = otrl_message_sending(ic->irc->otr_us, &global.otr_ops, ic, @@ -413,14 +440,17 @@ void op_inject_message(void *opdata, const char *accountname,  }  int op_display_otr_message(void *opdata, const char *accountname, -	const char *protocol, const char *username, const char *msg) +	const char *protocol, const char *username, const char *message)  {  	struct im_connection *ic = check_imc(opdata, accountname, protocol); +	char *msg = g_strdup(message); -	log_message(LOGLVL_DEBUG, "op_display_otr_message '%s' '%s' '%s' '%s'", accountname, protocol, username, msg); +	log_message(LOGLVL_DEBUG, "op_display_otr_message '%s' '%s' '%s' '%s'", accountname, protocol, username, message); -	irc_usermsg(ic->irc, "%s", msg); +	strip_html(msg); +	irc_usermsg(ic->irc, "otr: %s", msg); +	g_free(msg);  	return 0;  } @@ -451,51 +481,84 @@ void op_gone_secure(void *opdata, ConnContext *context)  {  	struct im_connection *ic =  		check_imc(opdata, context->accountname, context->protocol); +	user_t *u;  	log_message(LOGLVL_DEBUG, "op_gone_secure '%s' '%s' '%s'", context->accountname, context->protocol, context->username); -	irc_usermsg(ic->irc, "conversation with %s is now off the record", -		peernick(ic->irc, context->username, context->protocol)); +	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); +		return; +	} +	if(context->active_fingerprint->trust[0]) +		u->encrypted = 2; +	else +		u->encrypted = 1; +	if(!otr_update_modeflags(ic->irc, u)) +		irc_usermsg(ic->irc, "conversation with %s is now off the record", u->nick);  }  void op_gone_insecure(void *opdata, ConnContext *context)  {  	struct im_connection *ic =  		check_imc(opdata, context->accountname, context->protocol); +	user_t *u;  	log_message(LOGLVL_DEBUG, "op_gone_insecure '%s' '%s' '%s'", context->accountname, context->protocol, context->username); -	irc_usermsg(ic->irc, "conversation with %s is now in the clear", -		peernick(ic->irc, context->username, context->protocol)); +	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); +		return; +	} +	u->encrypted = 0; +	if(!otr_update_modeflags(ic->irc, u)) +		irc_usermsg(ic->irc, "conversation with %s is now in the clear", u->nick);  }  void op_still_secure(void *opdata, ConnContext *context, int is_reply)  {  	struct im_connection *ic =  		check_imc(opdata, context->accountname, context->protocol); +	user_t *u;  	log_message(LOGLVL_DEBUG, "op_still_secure '%s' '%s' '%s' is_reply=%d",  		context->accountname, context->protocol, context->username, is_reply); -	irc_usermsg(ic->irc, "otr connection with %s has been refreshed", -		peernick(ic->irc, context->username, context->protocol)); +	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); +		return; +	} +	if(context->active_fingerprint->trust[0]) +		u->encrypted = 2; +	else +		u->encrypted = 1; +	if(!otr_update_modeflags(ic->irc, u)) +		irc_usermsg(ic->irc, "otr connection with %s has been refreshed", u->nick);  }  void op_log_message(void *opdata, const char *message)  { -	log_message(LOGLVL_INFO, "%s", message); +	char *msg = g_strdup(message); +	 +	strip_html(msg); +	log_message(LOGLVL_INFO, "otr: %s", msg); +	g_free(msg);  }  int op_max_message_size(void *opdata, ConnContext *context)  { -	/* TODO: make max_message_size a property of the prpl. -	         the values here are taken from the libotr UPGRADING file */ -	if(!strcmp(context->protocol, "msn")) -		return 1409; -	if(!strcmp(context->protocol, "yahoo")) -		return 832; -	if(!strcmp(context->protocol, "oscar")) -		return 2343; +	struct im_connection *ic = +		check_imc(opdata, context->accountname, context->protocol); + +	return ic->acc->prpl->mms;  }  const char *op_account_name(void *opdata, const char *account, const char *protocol) @@ -541,7 +604,7 @@ void cmd_otr_request(irc_t *irc, char **args)  	imc_buddy_msg(u->ic, u->handle, "?OTR?", 0);  } -void cmd_otr_auth(irc_t *irc, char **args) +void cmd_otr_smp(irc_t *irc, char **args)  {  	user_t *u;  	ConnContext *ctx; @@ -588,6 +651,80 @@ void cmd_otr_auth(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; +	ConnContext *ctx; +	unsigned char raw[20]; +	Fingerprint *fp; +	int i,j; +	 +	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, "%s: no otr context with user", args[1]); +		return; +	} +	 +	/* convert given fingerprint to raw representation */ +	for(i=0; i<5; i++) { +		for(j=0; j<4; j++) { +			char *p = args[2+i]+(2*j); +			char *q = p+1; +			int x, y; +			 +			if(!*p || !*q) { +				irc_usermsg(irc, "failed: truncated fingerprint block %d", i+1); +				return; +			} +			 +			x = hexval(*p); +			y = hexval(*q); +			if(x<0) { +				irc_usermsg(irc, "failed: %d. hex digit of block %d out of range", 2*j+1, i+1); +				return; +			} +			if(y<0) { +				irc_usermsg(irc, "failed: %d. hex digit of block %d out of range", 2*j+2, i+1); +				return; +			} + +			raw[i*4+j] = x*16 + y; +		} +	} +	fp = otrl_context_find_fingerprint(ctx, raw, 0, NULL); +	if(!fp) { +		irc_usermsg(irc, "failed: no such fingerprint for %s", args[1]); +	} else { +		char *trust = args[7] ? args[7] : "affirmed"; +		otrl_context_set_trust(fp, trust); +		irc_usermsg(irc, "fingerprint match, trust set to \"%s\"", trust); +		if(u->encrypted) +			u->encrypted = 2; +		otr_update_modeflags(irc, u); +	} +} +  void cmd_otr_fprints(irc_t *irc, char **args)  {  	if(args[1]) { @@ -648,7 +785,7 @@ void cmd_otr_info(irc_t *irc, char **args)  	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 info on %s", args[1]); +		irc_usermsg(irc, "no otr context with %s", args[1]);  		return;  	} @@ -671,18 +808,21 @@ void cmd_otr_info(irc_t *irc, char **args)  		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); -	irc_usermsg(irc, "  protocol version: %d", ctx->protocol_version); -	fp = ctx->active_fingerprint; -	if(!fp) { -		irc_usermsg(irc, "  active f'print:   none"); -	} else { -		otrl_privkey_hash_to_human(human, fp->fingerprint); -		if(!fp->trust || fp->trust[0] == '\0') { -			trust="untrusted"; +	 +	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?");  		} else { -			trust=fp->trust; +			otrl_privkey_hash_to_human(human, fp->fingerprint); +			if(!fp->trust || fp->trust[0] == '\0') { +				trust="untrusted"; +			} else { +				trust=fp->trust; +			} +			irc_usermsg(irc, "  active f'print:   %s (%s)", human, trust);  		} -		irc_usermsg(irc, "  active f'print:   %s (%s)", human, trust);  	}  } @@ -808,12 +948,10 @@ struct im_connection *check_imc(void *opdata, const char *accountname,  	return ic;  } -const char *peernick(irc_t *irc, const char *handle, const char *protocol) +user_t *peeruser(irc_t *irc, const char *handle, const char *protocol)  {  	user_t *u; -	static char fallback[512]; -	g_snprintf(fallback, 511, "%s/%s", handle, protocol);  	for(u=irc->users; u; u=u->next) {  		struct prpl *prpl;  		if(!u->ic || !u->handle) @@ -821,11 +959,55 @@ const char *peernick(irc_t *irc, const char *handle, const char *protocol)  		prpl = u->ic->acc->prpl;  		if(strcmp(prpl->name, protocol) == 0  			&& prpl->handle_cmp(u->handle, handle) == 0) { -			return u->nick; +			return u;  		}  	} -	return fallback; +	return NULL; +} + +const char *peernick(irc_t *irc, const char *handle, const char *protocol) +{ +	static char fallback[512]; +	 +	user_t *u = peeruser(irc, handle, protocol); +	if(u) { +		return u->nick; +	} else { +		g_snprintf(fallback, 511, "%s/%s", handle, protocol); +		return fallback; +	} +} + +int otr_update_modeflags(irc_t *irc, user_t *u) +{ +	char *vo = set_getstr(&irc->set, "voice_buddies"); +	char *oo = set_getstr(&irc->set, "op_buddies"); +	char eflag=0, tflag=0; +	int e = u->encrypted; +	int t = (u->encrypted > 1); +	 +	if(!strcmp(vo, "encrypted")) +		eflag='v'; +	else if(!strcmp(oo, "encrypted")) +		eflag='o'; +	if(!strcmp(vo, "trusted")) +		tflag='v'; +	else if(!strcmp(oo, "trusted")) +		tflag='o'; +	 +	if(!eflag) +		return 0; +	 +	if(tflag) { +		irc_write( irc, ":%s!%s@%s MODE %s %c%c%c%c %s %s", irc->mynick, irc->mynick, irc->myhost, +			irc->channel, e?'+':'-', eflag, t?'+':'-', tflag, u->nick, u->nick ); +	} else { +		irc_write( irc, ":%s!%s@%s MODE %s %c%c %s", irc->mynick, irc->mynick, irc->myhost, +			irc->channel, e?'+':'-', eflag, u->nick ); +	} +		 +	return 1;  }  void show_fingerprints(irc_t *irc, ConnContext *ctx) @@ -965,9 +1147,13 @@ void no_keygen(gpointer w, void *data)  {  	account_t *acc = (account_t *)data; -	/* TODO: remember that we didn't want a key? */  	irc_usermsg(acc->irc, "proceeding without key, otr inoperable on %s/%s",  		acc->user, acc->prpl->name); +	/* TODO:  +	irc_usermsg(acc->irc, "setting otr policy for %s/%s to \"never\"", +		acc->user, acc->prpl->name); +	set_setstr(acc->set, "otr_policy", "never"); +	*/  } | 
