src/protocols/sametime/meanwhile/session.c

changeset 11943
81ee4bc13c28
parent 11291
5441d2419942
child 12261
672e2d392a73
--- a/src/protocols/sametime/meanwhile/session.c	Wed Nov 02 03:31:38 2005 +0000
+++ b/src/protocols/sametime/meanwhile/session.c	Wed Nov 02 03:39:03 2005 +0000
@@ -19,6 +19,7 @@
 */
 
 #include <glib.h>
+#include <gmp.h>
 #include <string.h>
 
 #include "mw_channel.h"
@@ -48,7 +49,7 @@
   struct mwSessionHandler *handler;
 
   enum mwSessionState state;  /**< session state */
-  guint32 state_info;         /**< additional state info */
+  gpointer state_info;        /**< additional state info */
 
   /* input buffering for an incoming message */
   char *buf;       /**< buffer for incoming message data */
@@ -218,16 +219,8 @@
 }
 
 
-/** set the state of the session, and trigger the session handler's
-    on_stateChange function. Has no effect if the session is already
-    in the specified state (ignores additional state info)
-
-    @param s      the session
-    @param state  the state to set
-    @param info   additional state info
-*/
 static void state(struct mwSession *s, enum mwSessionState state,
-		  guint32 info) {
+		  gpointer info) {
 
   struct mwSessionHandler *sh;
 
@@ -239,14 +232,24 @@
   s->state = state;
   s->state_info = info;
 
-  if(info) {
-    g_message("session state: %s (0x%08x)", state_str(state), info);
-  } else {
+  switch(state) {
+  case mwSession_STOPPING:
+  case mwSession_STOPPED:
+    g_message("session state: %s (0x%08x)", state_str(state),
+	      GPOINTER_TO_UINT(info));
+    break;
+
+  case mwSession_LOGIN_REDIR:
+    g_message("session state: %s (%s)", state_str(state),
+	      (char *)info);
+    break;
+
+  default:
     g_message("session state: %s", state_str(state));
   }
 
   sh = s->handler;
-  if(sh->on_stateChange)
+  if(sh && sh->on_stateChange)
     sh->on_stateChange(s, state, info);
 }
 
@@ -258,6 +261,11 @@
   g_return_if_fail(s != NULL);
   g_return_if_fail(mwSession_isStopped(s));
 
+  if(mwSession_isStarted(s) || mwSession_isStarting(s)) {
+    g_debug("attempted to start session that is already started/starting");
+    return;
+  }
+  
   state(s, mwSession_STARTING, 0);
 
   msg = (struct mwMsgHandshake *) mwMessage_new(mwMessage_HANDSHAKE);
@@ -265,6 +273,13 @@
   msg->minor = GUINT(property_get(s, mwSession_CLIENT_VER_MINOR));
   msg->login_type = GUINT(property_get(s, mwSession_CLIENT_TYPE_ID));
 
+  msg->loclcalc_addr = GUINT(property_get(s, mwSession_CLIENT_IP));
+
+  if(msg->major >= 0x001e && msg->minor >= 0x001d) {
+    msg->unknown_a = 0x0100;
+    msg->local_host = (char *) property_get(s, mwSession_CLIENT_HOST);
+  }
+
   ret = mwSession_send(s, MW_MESSAGE(msg));
   mwMessage_free(MW_MESSAGE(msg));
 
@@ -281,10 +296,13 @@
   struct mwMsgChannelDestroy *msg;
 
   g_return_if_fail(s != NULL);
-  g_return_if_fail(! mwSession_isStopping(s));
-  g_return_if_fail(! mwSession_isStopped(s));
+  
+  if(mwSession_isStopped(s) || mwSession_isStopping(s)) {
+    g_debug("attempted to stop session that is already stopped/stopping");
+    return;
+  }
 
-  state(s, mwSession_STOPPING, reason);
+  state(s, mwSession_STOPPING, GUINT_TO_POINTER(reason));
 
   for(list = l = mwSession_getServices(s); l; l = l->next)
     mwService_stop(MW_SERVICE(l->data));
@@ -305,20 +323,20 @@
   /* close the connection */
   io_close(s);
 
-  state(s, mwSession_STOPPED, reason);
+  state(s, mwSession_STOPPED, GUINT_TO_POINTER(reason));
 }
 
 
 /** compose authentication information into an opaque based on the
-    password */
-static void compose_auth(struct mwOpaque *auth, const char *pass) {
+    password, encrypted via RC2/40 */
+static void compose_auth_rc2_40(struct mwOpaque *auth, const char *pass) {
   char iv[8], key[5];
   struct mwOpaque a, b, z;
   struct mwPutBuffer *p;
 
   /* get an IV and a random five-byte key */
   mwIV_init((char *) iv);
-  rand_key((char *) key, 5);
+  mwKeyRandom((char *) key, 5);
 
   /* the opaque with the key */
   a.len = 5;
@@ -346,6 +364,63 @@
 }
 
 
+static void compose_auth_rc2_128(struct mwOpaque *auth, const char *pass,
+				 guint32 magic, struct mwOpaque *rkey) {
+
+  char iv[8];
+  struct mwOpaque a, b, c;
+  struct mwPutBuffer *p;
+
+  mpz_t private, public;
+  mpz_t remote;
+  mpz_t shared;
+
+  mpz_init(private);
+  mpz_init(public);
+  mpz_init(remote);
+  mpz_init(shared);
+
+  mwIV_init(iv);
+
+  mwDHRandKeypair(private, public);
+  mwDHImportKey(remote, rkey);
+  mwDHCalculateShared(shared, remote, private);
+
+  /* put the password in opaque a */
+  p = mwPutBuffer_new();
+  guint32_put(p, magic);
+  mwString_put(p, pass);
+  mwPutBuffer_finalize(&a, p);
+
+  /* put the shared key in opaque b */
+  mwDHExportKey(shared, &b);
+
+  /* encrypt the password (a) using the shared key (b), put the result
+     in opaque c */
+  mwEncrypt(b.data+(b.len-16), 16, iv, &a, &c);
+
+  /* don't need the shared key anymore, re-use opaque (b) as the
+     export of the public key */
+  mwOpaque_clear(&b);
+  mwDHExportKey(public, &b);
+
+  p = mwPutBuffer_new();
+  guint16_put(p, 0x0001);  /* XXX: unknown */
+  mwOpaque_put(p, &b);
+  mwOpaque_put(p, &c);
+  mwPutBuffer_finalize(auth, p);
+
+  mwOpaque_clear(&a);
+  mwOpaque_clear(&b);
+  mwOpaque_clear(&c);
+
+  mpz_clear(private);
+  mpz_clear(public);
+  mpz_clear(remote);
+  mpz_clear(shared);
+}
+
+
 /** handle the receipt of a handshake_ack message by sending the login
     message */
 static void HANDSHAKE_ACK_recv(struct mwSession *s,
@@ -380,8 +455,21 @@
   log->name = g_strdup(property_get(s, mwSession_AUTH_USER_ID));
 
   /** @todo default to password for now. later use token optionally */
-  log->auth_type = mwAuthType_ENCRYPT;
-  compose_auth(&log->auth_data, property_get(s, mwSession_AUTH_PASSWORD));
+  {
+    const char *pw;
+    pw = (const char *) property_get(s, mwSession_AUTH_PASSWORD);
+   
+    if(msg->data.len >= 64) {
+      /* good login encryption */
+      log->auth_type = mwAuthType_RC2_128;
+      compose_auth_rc2_128(&log->auth_data, pw, msg->magic, &msg->data);
+
+    } else {
+      /* BAD login encryption */
+      log->auth_type = mwAuthType_RC2_40;
+      compose_auth_rc2_40(&log->auth_data, pw);
+    }
+  }
   
   /* send the login message */
   ret = mwSession_send(s, MW_MESSAGE(log));
@@ -524,14 +612,18 @@
 }
 
 
-static void LOGIN_REDIRECT_recv(struct mwSession *s,
-				struct mwMsgLoginRedirect *msg) {
+static void ANNOUNCE_recv(struct mwSession *s, struct mwMsgAnnounce *msg) {
   struct mwSessionHandler *sh = s->handler;
 
-  state(s, mwSession_LOGIN_REDIR, 0);
+  if(sh && sh->on_announce)
+    sh->on_announce(s, &msg->sender, msg->may_reply, msg->text);
+}
+
 
-  if(sh && sh->on_loginRedirect)
-    sh->on_loginRedirect(s, msg->host);
+static void LOGIN_REDIRECT_recv(struct mwSession *s,
+				struct mwMsgLoginRedirect *msg) {
+
+  state(s, mwSession_LOGIN_REDIR, msg->host);
 }
 
 
@@ -544,7 +636,7 @@
 static void session_process(struct mwSession *s,
 			    const char *buf, gsize len) {
 
-  struct mwOpaque o = { len, (char *) buf };
+  struct mwOpaque o = { .len = len, .data = (char *) buf };
   struct mwGetBuffer *b;
   struct mwMessage *msg;
 
@@ -559,6 +651,13 @@
 
   /* attempt to parse the message. */
   msg = mwMessage_get(b);
+
+  if(mwGetBuffer_error(b)) {
+    mw_mailme_opaque(&o, "parsing of message failed");
+  }
+
+  mwGetBuffer_free(b);
+
   g_return_if_fail(msg != NULL);
 
   /* handle each of the appropriate incoming types of mwMessage */
@@ -574,17 +673,12 @@
     CASE(SET_USER_STATUS, mwMsgSetUserStatus);
     CASE(SENSE_SERVICE, mwMsgSenseService);
     CASE(ADMIN, mwMsgAdmin);
+    CASE(ANNOUNCE, mwMsgAnnounce);
     
   default:
     g_warning("unknown message type 0x%04x, no handler", msg->type);
   }
 
-  if(mwGetBuffer_error(b)) {
-    struct mwOpaque o = { .data = (char *) buf, .len = len };
-    mw_debug_mailme(&o, "parsing of message type 0x%04x failed", msg->type);
-  }
-
-  mwGetBuffer_free(b);
   mwMessage_free(msg);
 }
 
@@ -592,7 +686,7 @@
 #undef CASE
 
 
-#define ADVANCE(b, n, count) (b += count, n -= count)
+#define ADVANCE(b, n, count) { b += count; n -= count; }
 
 
 /* handle input to complete an existing buffer */
@@ -739,9 +833,11 @@
   /* g_message(" session_recv: session = %p, b = %p, n = %u",
 	    s, b, n); */
   
-  if(n && (s->buf_len == 0) && (*b & 0x80)) {
-    /* keep-alive and series bytes are ignored */
-    ADVANCE(b, n, 1);
+  if(s->buf_len == 0) {
+    while(n && (*b & 0x80)) {
+      /* keep-alive and series bytes are ignored */
+      ADVANCE(b, n, 1);
+    }
   }
 
   if(n == 0) {
@@ -765,9 +861,6 @@
 
   g_return_if_fail(s != NULL);
 
-  /* g_message(" mwSession_recv: session = %p, b = %p, n = %u",
-	    s, b, n); */
-
   while(n > 0) {
     remain = session_recv(s, b, n);
     b += (n - remain);
@@ -779,7 +872,6 @@
 int mwSession_send(struct mwSession *s, struct mwMessage *msg) {
   struct mwPutBuffer *b;
   struct mwOpaque o;
-  gsize len;
   int ret = 0;
 
   g_return_val_if_fail(s != NULL, -1);
@@ -799,7 +891,6 @@
   mwPutBuffer_finalize(&o, b);
 
   /* then we use that opaque's data and length to write to the socket */
-  len = o.len;
   ret = io_write(s, o.data, o.len);
   mwOpaque_clear(&o);
 
@@ -845,6 +936,30 @@
 }
 
 
+int mwSession_sendAnnounce(struct mwSession *s, gboolean may_reply,
+			   const char *text, const GList *recipients) {
+
+  struct mwMsgAnnounce *msg;
+  int ret;
+
+  g_return_val_if_fail(s != NULL, -1);
+  g_return_val_if_fail(mwSession_isStarted(s), -1);
+  
+  msg = (struct mwMsgAnnounce *) mwMessage_new(mwMessage_ANNOUNCE);
+
+  msg->recipients = (GList *) recipients;
+  msg->may_reply = may_reply;
+  msg->text = g_strdup(text);
+
+  ret = mwSession_send(s, MW_MESSAGE(msg));
+
+  msg->recipients = NULL;  /* don't kill our recipients param */
+  mwMessage_free(MW_MESSAGE(msg));
+
+  return ret;
+}
+
+
 struct mwSessionHandler *mwSession_getHandler(struct mwSession *s) {
   g_return_val_if_fail(s != NULL, NULL);
   return s->handler;
@@ -917,7 +1032,7 @@
 }
 
 
-guint32 mwSession_getStateInfo(struct mwSession *s) {
+gpointer mwSession_getStateInfo(struct mwSession *s) {
   g_return_val_if_fail(s != NULL, 0);
   return s->state_info;
 }

mercurial