src/protocols/sametime/meanwhile/session.c

changeset 11943
81ee4bc13c28
parent 11291
5441d2419942
child 12261
672e2d392a73
equal deleted inserted replaced
11942:e392054bc95b 11943:81ee4bc13c28
17 License along with this library; if not, write to the Free 17 License along with this library; if not, write to the Free
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21 #include <glib.h> 21 #include <glib.h>
22 #include <gmp.h>
22 #include <string.h> 23 #include <string.h>
23 24
24 #include "mw_channel.h" 25 #include "mw_channel.h"
25 #include "mw_cipher.h" 26 #include "mw_cipher.h"
26 #include "mw_debug.h" 27 #include "mw_debug.h"
46 47
47 /** provides I/O and callback functions */ 48 /** provides I/O and callback functions */
48 struct mwSessionHandler *handler; 49 struct mwSessionHandler *handler;
49 50
50 enum mwSessionState state; /**< session state */ 51 enum mwSessionState state; /**< session state */
51 guint32 state_info; /**< additional state info */ 52 gpointer state_info; /**< additional state info */
52 53
53 /* input buffering for an incoming message */ 54 /* input buffering for an incoming message */
54 char *buf; /**< buffer for incoming message data */ 55 char *buf; /**< buffer for incoming message data */
55 gsize buf_len; /**< length of buf */ 56 gsize buf_len; /**< length of buf */
56 gsize buf_used; /**< offset to last-used byte of buf */ 57 gsize buf_used; /**< offset to last-used byte of buf */
216 217
217 s->handler->io_close(s); 218 s->handler->io_close(s);
218 } 219 }
219 220
220 221
221 /** set the state of the session, and trigger the session handler's
222 on_stateChange function. Has no effect if the session is already
223 in the specified state (ignores additional state info)
224
225 @param s the session
226 @param state the state to set
227 @param info additional state info
228 */
229 static void state(struct mwSession *s, enum mwSessionState state, 222 static void state(struct mwSession *s, enum mwSessionState state,
230 guint32 info) { 223 gpointer info) {
231 224
232 struct mwSessionHandler *sh; 225 struct mwSessionHandler *sh;
233 226
234 g_return_if_fail(s != NULL); 227 g_return_if_fail(s != NULL);
235 g_return_if_fail(s->handler != NULL); 228 g_return_if_fail(s->handler != NULL);
237 if(mwSession_isState(s, state)) return; 230 if(mwSession_isState(s, state)) return;
238 231
239 s->state = state; 232 s->state = state;
240 s->state_info = info; 233 s->state_info = info;
241 234
242 if(info) { 235 switch(state) {
243 g_message("session state: %s (0x%08x)", state_str(state), info); 236 case mwSession_STOPPING:
244 } else { 237 case mwSession_STOPPED:
238 g_message("session state: %s (0x%08x)", state_str(state),
239 GPOINTER_TO_UINT(info));
240 break;
241
242 case mwSession_LOGIN_REDIR:
243 g_message("session state: %s (%s)", state_str(state),
244 (char *)info);
245 break;
246
247 default:
245 g_message("session state: %s", state_str(state)); 248 g_message("session state: %s", state_str(state));
246 } 249 }
247 250
248 sh = s->handler; 251 sh = s->handler;
249 if(sh->on_stateChange) 252 if(sh && sh->on_stateChange)
250 sh->on_stateChange(s, state, info); 253 sh->on_stateChange(s, state, info);
251 } 254 }
252 255
253 256
254 void mwSession_start(struct mwSession *s) { 257 void mwSession_start(struct mwSession *s) {
256 int ret; 259 int ret;
257 260
258 g_return_if_fail(s != NULL); 261 g_return_if_fail(s != NULL);
259 g_return_if_fail(mwSession_isStopped(s)); 262 g_return_if_fail(mwSession_isStopped(s));
260 263
264 if(mwSession_isStarted(s) || mwSession_isStarting(s)) {
265 g_debug("attempted to start session that is already started/starting");
266 return;
267 }
268
261 state(s, mwSession_STARTING, 0); 269 state(s, mwSession_STARTING, 0);
262 270
263 msg = (struct mwMsgHandshake *) mwMessage_new(mwMessage_HANDSHAKE); 271 msg = (struct mwMsgHandshake *) mwMessage_new(mwMessage_HANDSHAKE);
264 msg->major = GUINT(property_get(s, mwSession_CLIENT_VER_MAJOR)); 272 msg->major = GUINT(property_get(s, mwSession_CLIENT_VER_MAJOR));
265 msg->minor = GUINT(property_get(s, mwSession_CLIENT_VER_MINOR)); 273 msg->minor = GUINT(property_get(s, mwSession_CLIENT_VER_MINOR));
266 msg->login_type = GUINT(property_get(s, mwSession_CLIENT_TYPE_ID)); 274 msg->login_type = GUINT(property_get(s, mwSession_CLIENT_TYPE_ID));
267 275
276 msg->loclcalc_addr = GUINT(property_get(s, mwSession_CLIENT_IP));
277
278 if(msg->major >= 0x001e && msg->minor >= 0x001d) {
279 msg->unknown_a = 0x0100;
280 msg->local_host = (char *) property_get(s, mwSession_CLIENT_HOST);
281 }
282
268 ret = mwSession_send(s, MW_MESSAGE(msg)); 283 ret = mwSession_send(s, MW_MESSAGE(msg));
269 mwMessage_free(MW_MESSAGE(msg)); 284 mwMessage_free(MW_MESSAGE(msg));
270 285
271 if(ret) { 286 if(ret) {
272 mwSession_stop(s, CONNECTION_BROKEN); 287 mwSession_stop(s, CONNECTION_BROKEN);
279 void mwSession_stop(struct mwSession *s, guint32 reason) { 294 void mwSession_stop(struct mwSession *s, guint32 reason) {
280 GList *list, *l = NULL; 295 GList *list, *l = NULL;
281 struct mwMsgChannelDestroy *msg; 296 struct mwMsgChannelDestroy *msg;
282 297
283 g_return_if_fail(s != NULL); 298 g_return_if_fail(s != NULL);
284 g_return_if_fail(! mwSession_isStopping(s)); 299
285 g_return_if_fail(! mwSession_isStopped(s)); 300 if(mwSession_isStopped(s) || mwSession_isStopping(s)) {
286 301 g_debug("attempted to stop session that is already stopped/stopping");
287 state(s, mwSession_STOPPING, reason); 302 return;
303 }
304
305 state(s, mwSession_STOPPING, GUINT_TO_POINTER(reason));
288 306
289 for(list = l = mwSession_getServices(s); l; l = l->next) 307 for(list = l = mwSession_getServices(s); l; l = l->next)
290 mwService_stop(MW_SERVICE(l->data)); 308 mwService_stop(MW_SERVICE(l->data));
291 g_list_free(list); 309 g_list_free(list);
292 310
303 session_buf_free(s); 321 session_buf_free(s);
304 322
305 /* close the connection */ 323 /* close the connection */
306 io_close(s); 324 io_close(s);
307 325
308 state(s, mwSession_STOPPED, reason); 326 state(s, mwSession_STOPPED, GUINT_TO_POINTER(reason));
309 } 327 }
310 328
311 329
312 /** compose authentication information into an opaque based on the 330 /** compose authentication information into an opaque based on the
313 password */ 331 password, encrypted via RC2/40 */
314 static void compose_auth(struct mwOpaque *auth, const char *pass) { 332 static void compose_auth_rc2_40(struct mwOpaque *auth, const char *pass) {
315 char iv[8], key[5]; 333 char iv[8], key[5];
316 struct mwOpaque a, b, z; 334 struct mwOpaque a, b, z;
317 struct mwPutBuffer *p; 335 struct mwPutBuffer *p;
318 336
319 /* get an IV and a random five-byte key */ 337 /* get an IV and a random five-byte key */
320 mwIV_init((char *) iv); 338 mwIV_init((char *) iv);
321 rand_key((char *) key, 5); 339 mwKeyRandom((char *) key, 5);
322 340
323 /* the opaque with the key */ 341 /* the opaque with the key */
324 a.len = 5; 342 a.len = 5;
325 a.data = key; 343 a.data = key;
326 344
341 mwOpaque_put(p, &b); 359 mwOpaque_put(p, &b);
342 mwPutBuffer_finalize(auth, p); 360 mwPutBuffer_finalize(auth, p);
343 361
344 /* this is the only one to clear, as the other uses a static buffer */ 362 /* this is the only one to clear, as the other uses a static buffer */
345 mwOpaque_clear(&b); 363 mwOpaque_clear(&b);
364 }
365
366
367 static void compose_auth_rc2_128(struct mwOpaque *auth, const char *pass,
368 guint32 magic, struct mwOpaque *rkey) {
369
370 char iv[8];
371 struct mwOpaque a, b, c;
372 struct mwPutBuffer *p;
373
374 mpz_t private, public;
375 mpz_t remote;
376 mpz_t shared;
377
378 mpz_init(private);
379 mpz_init(public);
380 mpz_init(remote);
381 mpz_init(shared);
382
383 mwIV_init(iv);
384
385 mwDHRandKeypair(private, public);
386 mwDHImportKey(remote, rkey);
387 mwDHCalculateShared(shared, remote, private);
388
389 /* put the password in opaque a */
390 p = mwPutBuffer_new();
391 guint32_put(p, magic);
392 mwString_put(p, pass);
393 mwPutBuffer_finalize(&a, p);
394
395 /* put the shared key in opaque b */
396 mwDHExportKey(shared, &b);
397
398 /* encrypt the password (a) using the shared key (b), put the result
399 in opaque c */
400 mwEncrypt(b.data+(b.len-16), 16, iv, &a, &c);
401
402 /* don't need the shared key anymore, re-use opaque (b) as the
403 export of the public key */
404 mwOpaque_clear(&b);
405 mwDHExportKey(public, &b);
406
407 p = mwPutBuffer_new();
408 guint16_put(p, 0x0001); /* XXX: unknown */
409 mwOpaque_put(p, &b);
410 mwOpaque_put(p, &c);
411 mwPutBuffer_finalize(auth, p);
412
413 mwOpaque_clear(&a);
414 mwOpaque_clear(&b);
415 mwOpaque_clear(&c);
416
417 mpz_clear(private);
418 mpz_clear(public);
419 mpz_clear(remote);
420 mpz_clear(shared);
346 } 421 }
347 422
348 423
349 /** handle the receipt of a handshake_ack message by sending the login 424 /** handle the receipt of a handshake_ack message by sending the login
350 message */ 425 message */
378 log = (struct mwMsgLogin *) mwMessage_new(mwMessage_LOGIN); 453 log = (struct mwMsgLogin *) mwMessage_new(mwMessage_LOGIN);
379 log->login_type = GUINT(property_get(s, mwSession_CLIENT_TYPE_ID)); 454 log->login_type = GUINT(property_get(s, mwSession_CLIENT_TYPE_ID));
380 log->name = g_strdup(property_get(s, mwSession_AUTH_USER_ID)); 455 log->name = g_strdup(property_get(s, mwSession_AUTH_USER_ID));
381 456
382 /** @todo default to password for now. later use token optionally */ 457 /** @todo default to password for now. later use token optionally */
383 log->auth_type = mwAuthType_ENCRYPT; 458 {
384 compose_auth(&log->auth_data, property_get(s, mwSession_AUTH_PASSWORD)); 459 const char *pw;
460 pw = (const char *) property_get(s, mwSession_AUTH_PASSWORD);
461
462 if(msg->data.len >= 64) {
463 /* good login encryption */
464 log->auth_type = mwAuthType_RC2_128;
465 compose_auth_rc2_128(&log->auth_data, pw, msg->magic, &msg->data);
466
467 } else {
468 /* BAD login encryption */
469 log->auth_type = mwAuthType_RC2_40;
470 compose_auth_rc2_40(&log->auth_data, pw);
471 }
472 }
385 473
386 /* send the login message */ 474 /* send the login message */
387 ret = mwSession_send(s, MW_MESSAGE(log)); 475 ret = mwSession_send(s, MW_MESSAGE(log));
388 mwMessage_free(MW_MESSAGE(log)); 476 mwMessage_free(MW_MESSAGE(log));
389 477
522 if(sh && sh->on_admin) 610 if(sh && sh->on_admin)
523 sh->on_admin(s, msg->text); 611 sh->on_admin(s, msg->text);
524 } 612 }
525 613
526 614
615 static void ANNOUNCE_recv(struct mwSession *s, struct mwMsgAnnounce *msg) {
616 struct mwSessionHandler *sh = s->handler;
617
618 if(sh && sh->on_announce)
619 sh->on_announce(s, &msg->sender, msg->may_reply, msg->text);
620 }
621
622
527 static void LOGIN_REDIRECT_recv(struct mwSession *s, 623 static void LOGIN_REDIRECT_recv(struct mwSession *s,
528 struct mwMsgLoginRedirect *msg) { 624 struct mwMsgLoginRedirect *msg) {
529 struct mwSessionHandler *sh = s->handler; 625
530 626 state(s, mwSession_LOGIN_REDIR, msg->host);
531 state(s, mwSession_LOGIN_REDIR, 0);
532
533 if(sh && sh->on_loginRedirect)
534 sh->on_loginRedirect(s, msg->host);
535 } 627 }
536 628
537 629
538 #define CASE(var, type) \ 630 #define CASE(var, type) \
539 case mwMessage_ ## var: \ 631 case mwMessage_ ## var: \
542 634
543 635
544 static void session_process(struct mwSession *s, 636 static void session_process(struct mwSession *s,
545 const char *buf, gsize len) { 637 const char *buf, gsize len) {
546 638
547 struct mwOpaque o = { len, (char *) buf }; 639 struct mwOpaque o = { .len = len, .data = (char *) buf };
548 struct mwGetBuffer *b; 640 struct mwGetBuffer *b;
549 struct mwMessage *msg; 641 struct mwMessage *msg;
550 642
551 g_return_if_fail(s != NULL); 643 g_return_if_fail(s != NULL);
552 g_return_if_fail(buf != NULL); 644 g_return_if_fail(buf != NULL);
557 /* wrap up buf */ 649 /* wrap up buf */
558 b = mwGetBuffer_wrap(&o); 650 b = mwGetBuffer_wrap(&o);
559 651
560 /* attempt to parse the message. */ 652 /* attempt to parse the message. */
561 msg = mwMessage_get(b); 653 msg = mwMessage_get(b);
654
655 if(mwGetBuffer_error(b)) {
656 mw_mailme_opaque(&o, "parsing of message failed");
657 }
658
659 mwGetBuffer_free(b);
660
562 g_return_if_fail(msg != NULL); 661 g_return_if_fail(msg != NULL);
563 662
564 /* handle each of the appropriate incoming types of mwMessage */ 663 /* handle each of the appropriate incoming types of mwMessage */
565 switch(msg->type) { 664 switch(msg->type) {
566 CASE(HANDSHAKE_ACK, mwMsgHandshakeAck); 665 CASE(HANDSHAKE_ACK, mwMsgHandshakeAck);
572 CASE(CHANNEL_ACCEPT, mwMsgChannelAccept); 671 CASE(CHANNEL_ACCEPT, mwMsgChannelAccept);
573 CASE(SET_PRIVACY_LIST, mwMsgSetPrivacyList); 672 CASE(SET_PRIVACY_LIST, mwMsgSetPrivacyList);
574 CASE(SET_USER_STATUS, mwMsgSetUserStatus); 673 CASE(SET_USER_STATUS, mwMsgSetUserStatus);
575 CASE(SENSE_SERVICE, mwMsgSenseService); 674 CASE(SENSE_SERVICE, mwMsgSenseService);
576 CASE(ADMIN, mwMsgAdmin); 675 CASE(ADMIN, mwMsgAdmin);
676 CASE(ANNOUNCE, mwMsgAnnounce);
577 677
578 default: 678 default:
579 g_warning("unknown message type 0x%04x, no handler", msg->type); 679 g_warning("unknown message type 0x%04x, no handler", msg->type);
580 } 680 }
581 681
582 if(mwGetBuffer_error(b)) {
583 struct mwOpaque o = { .data = (char *) buf, .len = len };
584 mw_debug_mailme(&o, "parsing of message type 0x%04x failed", msg->type);
585 }
586
587 mwGetBuffer_free(b);
588 mwMessage_free(msg); 682 mwMessage_free(msg);
589 } 683 }
590 684
591 685
592 #undef CASE 686 #undef CASE
593 687
594 688
595 #define ADVANCE(b, n, count) (b += count, n -= count) 689 #define ADVANCE(b, n, count) { b += count; n -= count; }
596 690
597 691
598 /* handle input to complete an existing buffer */ 692 /* handle input to complete an existing buffer */
599 static gsize session_recv_cont(struct mwSession *s, const char *b, gsize n) { 693 static gsize session_recv_cont(struct mwSession *s, const char *b, gsize n) {
600 694
737 obscenely long message (even if it never actually sends it) */ 831 obscenely long message (even if it never actually sends it) */
738 832
739 /* g_message(" session_recv: session = %p, b = %p, n = %u", 833 /* g_message(" session_recv: session = %p, b = %p, n = %u",
740 s, b, n); */ 834 s, b, n); */
741 835
742 if(n && (s->buf_len == 0) && (*b & 0x80)) { 836 if(s->buf_len == 0) {
743 /* keep-alive and series bytes are ignored */ 837 while(n && (*b & 0x80)) {
744 ADVANCE(b, n, 1); 838 /* keep-alive and series bytes are ignored */
839 ADVANCE(b, n, 1);
840 }
745 } 841 }
746 842
747 if(n == 0) { 843 if(n == 0) {
748 return 0; 844 return 0;
749 845
762 void mwSession_recv(struct mwSession *s, const char *buf, gsize n) { 858 void mwSession_recv(struct mwSession *s, const char *buf, gsize n) {
763 char *b = (char *) buf; 859 char *b = (char *) buf;
764 gsize remain = 0; 860 gsize remain = 0;
765 861
766 g_return_if_fail(s != NULL); 862 g_return_if_fail(s != NULL);
767
768 /* g_message(" mwSession_recv: session = %p, b = %p, n = %u",
769 s, b, n); */
770 863
771 while(n > 0) { 864 while(n > 0) {
772 remain = session_recv(s, b, n); 865 remain = session_recv(s, b, n);
773 b += (n - remain); 866 b += (n - remain);
774 n = remain; 867 n = remain;
777 870
778 871
779 int mwSession_send(struct mwSession *s, struct mwMessage *msg) { 872 int mwSession_send(struct mwSession *s, struct mwMessage *msg) {
780 struct mwPutBuffer *b; 873 struct mwPutBuffer *b;
781 struct mwOpaque o; 874 struct mwOpaque o;
782 gsize len;
783 int ret = 0; 875 int ret = 0;
784 876
785 g_return_val_if_fail(s != NULL, -1); 877 g_return_val_if_fail(s != NULL, -1);
786 878
787 /* writing nothing is easy */ 879 /* writing nothing is easy */
797 mwOpaque_put(b, &o); 889 mwOpaque_put(b, &o);
798 mwOpaque_clear(&o); 890 mwOpaque_clear(&o);
799 mwPutBuffer_finalize(&o, b); 891 mwPutBuffer_finalize(&o, b);
800 892
801 /* then we use that opaque's data and length to write to the socket */ 893 /* then we use that opaque's data and length to write to the socket */
802 len = o.len;
803 ret = io_write(s, o.data, o.len); 894 ret = io_write(s, o.data, o.len);
804 mwOpaque_clear(&o); 895 mwOpaque_clear(&o);
805 896
806 /* ensure we could actually write the message */ 897 /* ensure we could actually write the message */
807 if(! ret) { 898 if(! ret) {
843 934
844 return ret; 935 return ret;
845 } 936 }
846 937
847 938
939 int mwSession_sendAnnounce(struct mwSession *s, gboolean may_reply,
940 const char *text, const GList *recipients) {
941
942 struct mwMsgAnnounce *msg;
943 int ret;
944
945 g_return_val_if_fail(s != NULL, -1);
946 g_return_val_if_fail(mwSession_isStarted(s), -1);
947
948 msg = (struct mwMsgAnnounce *) mwMessage_new(mwMessage_ANNOUNCE);
949
950 msg->recipients = (GList *) recipients;
951 msg->may_reply = may_reply;
952 msg->text = g_strdup(text);
953
954 ret = mwSession_send(s, MW_MESSAGE(msg));
955
956 msg->recipients = NULL; /* don't kill our recipients param */
957 mwMessage_free(MW_MESSAGE(msg));
958
959 return ret;
960 }
961
962
848 struct mwSessionHandler *mwSession_getHandler(struct mwSession *s) { 963 struct mwSessionHandler *mwSession_getHandler(struct mwSession *s) {
849 g_return_val_if_fail(s != NULL, NULL); 964 g_return_val_if_fail(s != NULL, NULL);
850 return s->handler; 965 return s->handler;
851 } 966 }
852 967
915 g_return_val_if_fail(s != NULL, mwSession_UNKNOWN); 1030 g_return_val_if_fail(s != NULL, mwSession_UNKNOWN);
916 return s->state; 1031 return s->state;
917 } 1032 }
918 1033
919 1034
920 guint32 mwSession_getStateInfo(struct mwSession *s) { 1035 gpointer mwSession_getStateInfo(struct mwSession *s) {
921 g_return_val_if_fail(s != NULL, 0); 1036 g_return_val_if_fail(s != NULL, 0);
922 return s->state_info; 1037 return s->state_info;
923 } 1038 }
924 1039
925 1040

mercurial