1 /***************************************************************************\
2 *                                                                           *
3 *  BitlBee - An IRC to IM gateway                                           *
4 *  Jabber module - SI packets                                               *
5 *                                                                           *
6 *  Copyright 2007 Uli Meis <a.sporto+bee@gmail.com>                         *
7 *                                                                           *
8 *  This program is free software; you can redistribute it and/or modify     *
9 *  it under the terms of the GNU General Public License as published by     *
10 *  the Free Software Foundation; either version 2 of the License, or        *
11 *  (at your option) any later version.                                      *
12 *                                                                           *
13 *  This program is distributed in the hope that it will be useful,          *
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
16 *  GNU General Public License for more details.                             *
17 *                                                                           *
18 *  You should have received a copy of the GNU General Public License along  *
19 *  with this program; if not, write to the Free Software Foundation, Inc.,  *
20 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.              *
21 *                                                                           *
22 \***************************************************************************/
23 
24 #include "jabber.h"
25 #include "sha1.h"
26 
27 void jabber_si_answer_request(file_transfer_t *ft);
28 int jabber_si_send_request(struct im_connection *ic, char *who, struct jabber_transfer *tf);
29 
30 /* file_transfer free() callback */
jabber_si_free_transfer(file_transfer_t * ft)31 void jabber_si_free_transfer(file_transfer_t *ft)
32 {
33 	struct jabber_transfer *tf = ft->data;
34 	struct jabber_data *jd = tf->ic->proto_data;
35 
36 	if (tf->watch_in) {
37 		b_event_remove(tf->watch_in);
38 		tf->watch_in = 0;
39 	}
40 
41 	jd->filetransfers = g_slist_remove(jd->filetransfers, tf);
42 
43 	if (tf->fd != -1) {
44 		closesocket(tf->fd);
45 		tf->fd = -1;
46 	}
47 
48 	if (tf->disco_timeout) {
49 		b_event_remove(tf->disco_timeout);
50 	}
51 
52 	g_free(tf->ini_jid);
53 	g_free(tf->tgt_jid);
54 	g_free(tf->iq_id);
55 	g_free(tf->sid);
56 	g_free(tf);
57 }
58 
59 /* file_transfer canceled() callback */
jabber_si_canceled(file_transfer_t * ft,char * reason)60 void jabber_si_canceled(file_transfer_t *ft, char *reason)
61 {
62 	struct jabber_transfer *tf = ft->data;
63 	struct xt_node *reply, *iqnode;
64 
65 	if (tf->accepted) {
66 		return;
67 	}
68 
69 	iqnode = jabber_make_packet("iq", "error", tf->ini_jid, NULL);
70 	xt_add_attr(iqnode, "id", tf->iq_id);
71 	reply = jabber_make_error_packet(iqnode, "forbidden", "cancel", "403");
72 	xt_free_node(iqnode);
73 
74 	if (!jabber_write_packet(tf->ic, reply)) {
75 		imcb_log(tf->ic, "WARNING: Error generating reply to file transfer request");
76 	}
77 	xt_free_node(reply);
78 
79 }
80 
jabber_si_check_features(struct jabber_transfer * tf,GSList * features)81 int jabber_si_check_features(struct jabber_transfer *tf, GSList *features)
82 {
83 	int foundft = FALSE, foundbt = FALSE, foundsi = FALSE;
84 
85 	while (features) {
86 		if (!strcmp(features->data, XMLNS_FILETRANSFER)) {
87 			foundft = TRUE;
88 		}
89 		if (!strcmp(features->data, XMLNS_BYTESTREAMS)) {
90 			foundbt = TRUE;
91 		}
92 		if (!strcmp(features->data, XMLNS_SI)) {
93 			foundsi = TRUE;
94 		}
95 
96 		features = g_slist_next(features);
97 	}
98 
99 	if (!foundft) {
100 		imcb_file_canceled(tf->ic, tf->ft, "Buddy's client doesn't feature file transfers");
101 	} else if (!foundbt) {
102 		imcb_file_canceled(tf->ic, tf->ft, "Buddy's client doesn't feature byte streams (required)");
103 	} else if (!foundsi) {
104 		imcb_file_canceled(tf->ic, tf->ft, "Buddy's client doesn't feature stream initiation (required)");
105 	}
106 
107 	return foundft && foundbt && foundsi;
108 }
109 
jabber_si_transfer_start(struct jabber_transfer * tf)110 void jabber_si_transfer_start(struct jabber_transfer *tf)
111 {
112 
113 	if (!jabber_si_check_features(tf, tf->bud->features)) {
114 		return;
115 	}
116 
117 	/* send the request to our buddy */
118 	jabber_si_send_request(tf->ic, tf->bud->full_jid, tf);
119 
120 	/* and start the receive logic */
121 	imcb_file_recv_start(tf->ic, tf->ft);
122 
123 }
124 
jabber_si_waitfor_disco(gpointer data,gint fd,b_input_condition cond)125 gboolean jabber_si_waitfor_disco(gpointer data, gint fd, b_input_condition cond)
126 {
127 	struct jabber_transfer *tf = data;
128 	struct jabber_data *jd = tf->ic->proto_data;
129 
130 	tf->disco_timeout_fired++;
131 
132 	if (tf->bud->features && jd->have_streamhosts == 1) {
133 		tf->disco_timeout = 0;
134 		jabber_si_transfer_start(tf);
135 		return FALSE;
136 	}
137 
138 	/* 8 seconds should be enough for server and buddy to respond */
139 	if (tf->disco_timeout_fired < 16) {
140 		return TRUE;
141 	}
142 
143 	if (!tf->bud->features && jd->have_streamhosts != 1) {
144 		imcb_log(tf->ic, "Couldn't get buddy's features nor discover all services of the server");
145 	} else if (!tf->bud->features) {
146 		imcb_log(tf->ic, "Couldn't get buddy's features");
147 	} else {
148 		imcb_log(tf->ic, "Couldn't discover some of the server's services");
149 	}
150 
151 	tf->disco_timeout = 0;
152 	jabber_si_transfer_start(tf);
153 	return FALSE;
154 }
155 
jabber_si_transfer_request(struct im_connection * ic,file_transfer_t * ft,char * who)156 void jabber_si_transfer_request(struct im_connection *ic, file_transfer_t *ft, char *who)
157 {
158 	struct jabber_transfer *tf;
159 	struct jabber_data *jd = ic->proto_data;
160 	struct jabber_buddy *bud;
161 	char *server = jd->server, *s;
162 
163 	if ((s = strchr(who, '=')) && jabber_chat_by_jid(ic, s + 1)) {
164 		bud = jabber_buddy_by_ext_jid(ic, who, 0);
165 	} else {
166 		bud = jabber_buddy_by_jid(ic, who, 0);
167 	}
168 
169 	if (bud == NULL) {
170 		imcb_file_canceled(ic, ft, "Couldn't find buddy (BUG?)");
171 		return;
172 	}
173 
174 	imcb_log(ic, "Trying to send %s(%zd bytes) to %s", ft->file_name, ft->file_size, who);
175 
176 	tf = g_new0(struct jabber_transfer, 1);
177 
178 	tf->ic = ic;
179 	tf->ft = ft;
180 	tf->fd = -1;
181 	tf->ft->data = tf;
182 	tf->ft->free = jabber_si_free_transfer;
183 	tf->bud = bud;
184 	ft->write = jabber_bs_send_write;
185 
186 	jd->filetransfers = g_slist_prepend(jd->filetransfers, tf);
187 
188 	/* query buddy's features and server's streaming proxies if necessary */
189 
190 	if (!tf->bud->features) {
191 		jabber_iq_query_features(ic, bud->full_jid);
192 	}
193 
194 	/* If <auto> is not set don't check for proxies */
195 	if ((jd->have_streamhosts != 1) && (jd->streamhosts == NULL) &&
196 	    (strstr(set_getstr(&ic->acc->set, "proxy"), "<auto>") != NULL)) {
197 		jd->have_streamhosts = 0;
198 		jabber_iq_query_server(ic, server, XMLNS_DISCO_ITEMS);
199 	} else if (jd->streamhosts != NULL) {
200 		jd->have_streamhosts = 1;
201 	}
202 
203 	/* if we had to do a query, wait for the result.
204 	 * Otherwise fire away. */
205 	if (!tf->bud->features || jd->have_streamhosts != 1) {
206 		tf->disco_timeout = b_timeout_add(500, jabber_si_waitfor_disco, tf);
207 	} else {
208 		jabber_si_transfer_start(tf);
209 	}
210 }
211 
212 /*
213  * First function that gets called when a file transfer request comes in.
214  * A lot to parse.
215  *
216  * We choose a stream type from the options given by the initiator.
217  * Then we wait for imcb to call the accept or cancel callbacks.
218  */
jabber_si_handle_request(struct im_connection * ic,struct xt_node * node,struct xt_node * sinode)219 int jabber_si_handle_request(struct im_connection *ic, struct xt_node *node, struct xt_node *sinode)
220 {
221 	struct xt_node *c, *d, *reply;
222 	char *sid, *ini_jid, *tgt_jid, *iq_id, *s, *ext_jid, *size_s;
223 	struct jabber_buddy *bud;
224 	int requestok = FALSE;
225 	char *name, *cmp;
226 	size_t size;
227 	struct jabber_transfer *tf;
228 	struct jabber_data *jd = ic->proto_data;
229 	file_transfer_t *ft;
230 
231 	/* All this means we expect something like this: ( I think )
232 	 * <iq from=... to=... id=...>
233 	 *      <si id=id xmlns=si profile=ft>
234 	 *              <file xmlns=ft/>
235 	 *              <feature xmlns=feature>
236 	 *                      <x xmlns=xdata type=submit>
237 	 *                              <field var=stream-method>
238 	 *
239 	 */
240 	if (!(ini_jid          = xt_find_attr(node, "from")) ||
241 	    !(tgt_jid          = xt_find_attr(node, "to")) ||
242 	    !(iq_id            = xt_find_attr(node, "id")) ||
243 	    !(sid              = xt_find_attr(sinode, "id")) ||
244 	    !(cmp              = xt_find_attr(sinode, "profile")) ||
245 	    !(0               == strcmp(cmp, XMLNS_FILETRANSFER)) ||
246 	    !(d                = xt_find_node(sinode->children, "file")) ||
247 	    !(cmp = xt_find_attr(d, "xmlns")) ||
248 	    !(0               == strcmp(cmp, XMLNS_FILETRANSFER)) ||
249 	    !(name             = xt_find_attr(d, "name")) ||
250 	    !(size_s           = xt_find_attr(d, "size")) ||
251 	    !(1               == sscanf(size_s, "%zd", &size)) ||
252 	    !(d                = xt_find_node(sinode->children, "feature")) ||
253 	    !(cmp              = xt_find_attr(d, "xmlns")) ||
254 	    !(0               == strcmp(cmp, XMLNS_FEATURE)) ||
255 	    !(d                = xt_find_node(d->children, "x")) ||
256 	    !(cmp              = xt_find_attr(d, "xmlns")) ||
257 	    !(0               == strcmp(cmp, XMLNS_XDATA)) ||
258 	    !(cmp              = xt_find_attr(d, "type")) ||
259 	    !(0               == strcmp(cmp, "form")) ||
260 	    !(d                = xt_find_node(d->children, "field")) ||
261 	    !(cmp              = xt_find_attr(d, "var")) ||
262 	    !(0               == strcmp(cmp, "stream-method"))) {
263 		imcb_log(ic, "WARNING: Received incomplete Stream Initiation request");
264 	} else {
265 		/* Check if we support one of the options */
266 
267 		c = d->children;
268 		while ((c = xt_find_node(c, "option"))) {
269 			if ((d = xt_find_node(c->children, "value")) &&
270 			    (d->text != NULL) &&
271 			    (strcmp(d->text, XMLNS_BYTESTREAMS) == 0)) {
272 				requestok = TRUE;
273 				break;
274 			} else {
275 				c = c->next;
276 			}
277 		}
278 
279 		if (!requestok) {
280 			imcb_log(ic, "WARNING: Unsupported file transfer request from %s", ini_jid);
281 		}
282 	}
283 
284 	if (requestok) {
285 		/* Figure out who the transfer should come from... */
286 
287 		ext_jid = ini_jid;
288 		if ((s = strchr(ini_jid, '/'))) {
289 			if ((bud = jabber_buddy_by_jid(ic, ini_jid, GET_BUDDY_EXACT))) {
290 				bud->last_msg = time(NULL);
291 				ext_jid = bud->ext_jid ? : bud->bare_jid;
292 			} else {
293 				*s = 0; /* We need to generate a bare JID now. */
294 			}
295 		}
296 
297 		if (!(ft = imcb_file_send_start(ic, ext_jid, name, size))) {
298 			imcb_log(ic, "WARNING: Error handling transfer request from %s", ini_jid);
299 			requestok = FALSE;
300 		}
301 
302 		if (s) {
303 			*s = '/';
304 		}
305 	}
306 
307 	if (!requestok) {
308 		reply = jabber_make_error_packet(node, "item-not-found", "cancel", NULL);
309 		if (!jabber_write_packet(ic, reply)) {
310 			imcb_log(ic, "WARNING: Error generating reply to file transfer request");
311 		}
312 		xt_free_node(reply);
313 		return XT_HANDLED;
314 	}
315 
316 	/* Request is fine. */
317 
318 	tf = g_new0(struct jabber_transfer, 1);
319 
320 	tf->ini_jid = g_strdup(ini_jid);
321 	tf->tgt_jid = g_strdup(tgt_jid);
322 	tf->iq_id = g_strdup(iq_id);
323 	tf->sid = g_strdup(sid);
324 	tf->ic = ic;
325 	tf->ft = ft;
326 	tf->fd = -1;
327 	tf->ft->data = tf;
328 	tf->ft->accept = jabber_si_answer_request;
329 	tf->ft->free = jabber_si_free_transfer;
330 	tf->ft->canceled = jabber_si_canceled;
331 
332 	jd->filetransfers = g_slist_prepend(jd->filetransfers, tf);
333 
334 	return XT_HANDLED;
335 }
336 
337 /*
338  * imc called the accept callback which probably means that the user accepted this file transfer.
339  * We send our response to the initiator.
340  * In the next step, the initiator will send us a request for the given stream type.
341  * (currently that can only be a SOCKS5 bytestream)
342  */
jabber_si_answer_request(file_transfer_t * ft)343 void jabber_si_answer_request(file_transfer_t *ft)
344 {
345 	struct jabber_transfer *tf = ft->data;
346 	struct xt_node *node, *sinode, *reply;
347 
348 	/* generate response, start with the SI tag */
349 	sinode = xt_new_node("si", NULL, NULL);
350 	xt_add_attr(sinode, "xmlns", XMLNS_SI);
351 	xt_add_attr(sinode, "profile", XMLNS_FILETRANSFER);
352 	xt_add_attr(sinode, "id", tf->sid);
353 
354 	/* now the file tag */
355 	node = xt_new_node("file", NULL, NULL);
356 	xt_add_attr(node, "xmlns", XMLNS_FILETRANSFER);
357 
358 	xt_add_child(sinode, node);
359 
360 	/* and finally the feature tag */
361 	node = xt_new_node("field", NULL, NULL);
362 	xt_add_attr(node, "var", "stream-method");
363 	xt_add_attr(node, "type", "list-single");
364 
365 	/* Currently all we can do. One could also implement in-band (IBB) */
366 	xt_add_child(node, xt_new_node("value", XMLNS_BYTESTREAMS, NULL));
367 
368 	node = xt_new_node("x", NULL, node);
369 	xt_add_attr(node, "xmlns", XMLNS_XDATA);
370 	xt_add_attr(node, "type", "submit");
371 
372 	node = xt_new_node("feature", NULL, node);
373 	xt_add_attr(node, "xmlns", XMLNS_FEATURE);
374 
375 	xt_add_child(sinode, node);
376 
377 	reply = jabber_make_packet("iq", "result", tf->ini_jid, sinode);
378 	xt_add_attr(reply, "id", tf->iq_id);
379 
380 	if (!jabber_write_packet(tf->ic, reply)) {
381 		imcb_log(tf->ic, "WARNING: Error generating reply to file transfer request");
382 	} else {
383 		tf->accepted = TRUE;
384 	}
385 	xt_free_node(reply);
386 }
387 
jabber_si_handle_response(struct im_connection * ic,struct xt_node * node,struct xt_node * orig)388 static xt_status jabber_si_handle_response(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
389 {
390 	struct xt_node *c, *d;
391 	char *ini_jid = NULL, *tgt_jid, *iq_id, *cmp;
392 	GSList *tflist;
393 	struct jabber_transfer *tf = NULL;
394 	struct jabber_data *jd = ic->proto_data;
395 	struct jabber_error *err;
396 
397 	if (!(tgt_jid = xt_find_attr(node, "from")) ||
398 	    !(ini_jid = xt_find_attr(node, "to")) ||
399 	    !(iq_id   = xt_find_attr(node, "id"))) {
400 		imcb_log(ic, "Invalid SI response from=%s to=%s", tgt_jid, ini_jid);
401 		return XT_HANDLED;
402 	}
403 
404 	/* Let's see if we can find out what this bytestream should be for... */
405 
406 	for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) {
407 		struct jabber_transfer *tft = tflist->data;
408 		if ((strcmp(tft->iq_id, iq_id) == 0)) {
409 			tf = tft;
410 			break;
411 		}
412 	}
413 
414 	if (!tf) {
415 		imcb_log(ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid);
416 		return XT_HANDLED;
417 	}
418 
419 	err = jabber_error_parse(xt_find_node(node->children, "error"), XMLNS_STANZA_ERROR);
420 
421 	if (err) {
422 		if (g_strcmp0(err->code, "forbidden") == 0) {
423 			imcb_log(ic, "File %s: %s rejected the transfer", tf->ft->file_name, tgt_jid);
424 		} else {
425 			imcb_log(ic, "Error: Stream initiation request failed: %s (%s)", err->code, err->text);
426 		}
427 		imcb_file_canceled(ic, tf->ft, "Stream initiation request failed");
428 		jabber_error_free(err);
429 		return XT_HANDLED;
430 	}
431 
432 	/* All this means we expect something like this: ( I think )
433 	 * <iq from=... to=... id=...>
434 	 *      <si xmlns=si>
435 	 *      [	<file xmlns=ft/>    ] <-- not necessary
436 	 *              <feature xmlns=feature>
437 	 *                      <x xmlns=xdata type=submit>
438 	 *                              <field var=stream-method>
439 	 *                                      <value>
440 	 */
441 	if (!(c = xt_find_node(node->children, "si")) ||
442 	    !(cmp = xt_find_attr(c, "xmlns")) ||
443 	    !(strcmp(cmp, XMLNS_SI) == 0) ||
444 	    !(d = xt_find_node(c->children, "feature")) ||
445 	    !(cmp = xt_find_attr(d, "xmlns")) ||
446 	    !(strcmp(cmp, XMLNS_FEATURE) == 0) ||
447 	    !(d = xt_find_node(d->children, "x")) ||
448 	    !(cmp = xt_find_attr(d, "xmlns")) ||
449 	    !(strcmp(cmp, XMLNS_XDATA) == 0) ||
450 	    !(cmp = xt_find_attr(d, "type")) ||
451 	    !(strcmp(cmp, "submit") == 0) ||
452 	    !(d = xt_find_node(d->children, "field")) ||
453 	    !(cmp = xt_find_attr(d, "var")) ||
454 	    !(strcmp(cmp, "stream-method") == 0) ||
455 	    !(d = xt_find_node(d->children, "value"))) {
456 		imcb_log(ic, "WARNING: Received incomplete Stream Initiation response");
457 		return XT_HANDLED;
458 	}
459 
460 	if (!(strcmp(d->text, XMLNS_BYTESTREAMS) == 0)) {
461 		/* since we should only have advertised what we can do and the peer should
462 		 * only have chosen what we offered, this should never happen */
463 		imcb_log(ic, "WARNING: Received invalid Stream Initiation response, method %s", d->text);
464 
465 		return XT_HANDLED;
466 	}
467 
468 	tf->ini_jid = g_strdup(ini_jid);
469 	tf->tgt_jid = g_strdup(tgt_jid);
470 
471 	imcb_log(ic, "File %s: %s accepted the transfer!", tf->ft->file_name, tgt_jid);
472 
473 	jabber_bs_send_start(tf);
474 
475 	return XT_HANDLED;
476 }
477 
jabber_si_send_request(struct im_connection * ic,char * who,struct jabber_transfer * tf)478 int jabber_si_send_request(struct im_connection *ic, char *who, struct jabber_transfer *tf)
479 {
480 	struct xt_node *node, *sinode;
481 	struct jabber_buddy *bud;
482 
483 	/* who knows how many bits the future holds :) */
484 	char filesizestr[ 1 + ( int ) (0.301029995663981198f * sizeof(size_t) * 8) ];
485 
486 	const char *methods[] =
487 	{
488 		XMLNS_BYTESTREAMS,
489 		//XMLNS_IBB,
490 		NULL
491 	};
492 	const char **m;
493 	char *s;
494 
495 	/* Maybe we should hash this? */
496 	tf->sid = g_strdup_printf("BitlBeeJabberSID%d", tf->ft->local_id);
497 
498 	if ((s = strchr(who, '=')) && jabber_chat_by_jid(ic, s + 1)) {
499 		bud = jabber_buddy_by_ext_jid(ic, who, 0);
500 	} else {
501 		bud = jabber_buddy_by_jid(ic, who, 0);
502 	}
503 
504 	/* start with the SI tag */
505 	sinode = xt_new_node("si", NULL, NULL);
506 	xt_add_attr(sinode, "xmlns", XMLNS_SI);
507 	xt_add_attr(sinode, "profile", XMLNS_FILETRANSFER);
508 	xt_add_attr(sinode, "id", tf->sid);
509 
510 /*	if( mimetype )
511                 xt_add_attr( node, "mime-type", mimetype ); */
512 
513 	/* now the file tag */
514 /*	if( desc )
515                 node = xt_new_node( "desc", descr, NULL ); */
516 	node = xt_new_node("range", NULL, NULL);
517 
518 	sprintf(filesizestr, "%zd", tf->ft->file_size);
519 	node = xt_new_node("file", NULL, node);
520 	xt_add_attr(node, "xmlns", XMLNS_FILETRANSFER);
521 	xt_add_attr(node, "name", tf->ft->file_name);
522 	xt_add_attr(node, "size", filesizestr);
523 /*	if (hash)
524                 xt_add_attr( node, "hash", hash );
525         if (date)
526                 xt_add_attr( node, "date", date ); */
527 
528 	xt_add_child(sinode, node);
529 
530 	/* and finally the feature tag */
531 	node = xt_new_node("field", NULL, NULL);
532 	xt_add_attr(node, "var", "stream-method");
533 	xt_add_attr(node, "type", "list-single");
534 
535 	for (m = methods; *m; m++) {
536 		xt_add_child(node, xt_new_node("option", NULL, xt_new_node("value", (char *) *m, NULL)));
537 	}
538 
539 	node = xt_new_node("x", NULL, node);
540 	xt_add_attr(node, "xmlns", XMLNS_XDATA);
541 	xt_add_attr(node, "type", "form");
542 
543 	node = xt_new_node("feature", NULL, node);
544 	xt_add_attr(node, "xmlns", XMLNS_FEATURE);
545 
546 	xt_add_child(sinode, node);
547 
548 	/* and we are there... */
549 	node = jabber_make_packet("iq", "set", bud ? bud->full_jid : who, sinode);
550 	jabber_cache_add(ic, node, jabber_si_handle_response);
551 	tf->iq_id = g_strdup(xt_find_attr(node, "id"));
552 
553 	return jabber_write_packet(ic, node);
554 }
555