|
Packit |
16808d |
|
|
Packit |
16808d |
/*
|
|
Packit |
16808d |
Meanwhile - Unofficial Lotus Sametime Community Client Library
|
|
Packit |
16808d |
Copyright (C) 2004 Christopher (siege) O'Brien
|
|
Packit |
16808d |
|
|
Packit |
16808d |
This library is free software; you can redistribute it and/or
|
|
Packit |
16808d |
modify it under the terms of the GNU Library General Public
|
|
Packit |
16808d |
License as published by the Free Software Foundation; either
|
|
Packit |
16808d |
version 2 of the License, or (at your option) any later version.
|
|
Packit |
16808d |
|
|
Packit |
16808d |
This library is distributed in the hope that it will be useful,
|
|
Packit |
16808d |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
16808d |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
16808d |
Library General Public License for more details.
|
|
Packit |
16808d |
|
|
Packit |
16808d |
You should have received a copy of the GNU Library General Public
|
|
Packit |
16808d |
License along with this library; if not, write to the Free
|
|
Packit |
16808d |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
Packit |
16808d |
*/
|
|
Packit |
16808d |
|
|
Packit |
16808d |
#include <glib.h>
|
|
Packit |
16808d |
#include <string.h>
|
|
Packit |
16808d |
|
|
Packit |
16808d |
#include "mw_channel.h"
|
|
Packit |
16808d |
#include "mw_cipher.h"
|
|
Packit |
16808d |
#include "mw_debug.h"
|
|
Packit |
16808d |
#include "mw_error.h"
|
|
Packit |
16808d |
#include "mw_message.h"
|
|
Packit |
16808d |
#include "mw_service.h"
|
|
Packit |
16808d |
#include "mw_session.h"
|
|
Packit |
16808d |
#include "mw_util.h"
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/** @todo reorganize this file, stuff is just strewn about */
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwChannel {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/** session this channel belongs to */
|
|
Packit |
16808d |
struct mwSession *session;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
enum mwChannelState state;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/** creator for incoming channel, target for outgoing channel */
|
|
Packit |
16808d |
struct mwLoginInfo user;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* similar to data from the CreateCnl message in 8.4.1.7 */
|
|
Packit |
16808d |
guint32 reserved; /**< special, unknown meaning */
|
|
Packit |
16808d |
guint32 id; /**< channel ID */
|
|
Packit |
16808d |
guint32 service; /**< service ID */
|
|
Packit |
16808d |
guint32 proto_type; /**< service protocol type */
|
|
Packit |
16808d |
guint32 proto_ver; /**< service protocol version */
|
|
Packit |
16808d |
guint32 options; /**< channel options */
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwOpaque addtl_create;
|
|
Packit |
16808d |
struct mwOpaque addtl_accept;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/** all those supported ciphers */
|
|
Packit |
16808d |
GHashTable *supported;
|
|
Packit |
16808d |
guint16 offered_policy; /**< @see enum mwEncryptPolicy */
|
|
Packit |
16808d |
guint16 policy; /**< @see enum mwEncryptPolicy */
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/** cipher information determined at channel acceptance */
|
|
Packit |
16808d |
struct mwCipherInstance *cipher;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/** statistics table */
|
|
Packit |
16808d |
GHashTable *stats;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
GSList *outgoing_queue; /**< queued outgoing messages */
|
|
Packit |
16808d |
GSList *incoming_queue; /**< queued incoming messages */
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mw_datum srvc_data; /**< service-specific data */
|
|
Packit |
16808d |
};
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwChannelSet {
|
|
Packit |
16808d |
struct mwSession *session; /**< owning session */
|
|
Packit |
16808d |
GHashTable *map; /**< map of all channels, by ID */
|
|
Packit |
16808d |
guint32 counter; /**< counter for outgoing ID */
|
|
Packit |
16808d |
};
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void flush_channel(struct mwChannel *);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static const char *state_str(enum mwChannelState state) {
|
|
Packit |
16808d |
switch(state) {
|
|
Packit |
16808d |
case mwChannel_NEW: return "new";
|
|
Packit |
16808d |
case mwChannel_INIT: return "initializing";
|
|
Packit |
16808d |
case mwChannel_WAIT: return "waiting";
|
|
Packit |
16808d |
case mwChannel_OPEN: return "open";
|
|
Packit |
16808d |
case mwChannel_DESTROY: return "closing";
|
|
Packit |
16808d |
case mwChannel_ERROR: return "error";
|
|
Packit |
16808d |
|
|
Packit |
16808d |
case mwChannel_UNKNOWN: /* fall through */
|
|
Packit |
16808d |
default: return "UNKNOWN";
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void state(struct mwChannel *chan, enum mwChannelState state,
|
|
Packit |
16808d |
guint32 err_code) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_return_if_fail(chan != NULL);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(chan->state == state) return;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
chan->state = state;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(err_code) {
|
|
Packit |
16808d |
g_message("channel 0x%08x state: %s (0x%08x)",
|
|
Packit |
16808d |
chan->id, state_str(state), err_code);
|
|
Packit |
16808d |
} else {
|
|
Packit |
16808d |
g_message("channel 0x%08x state: %s", chan->id, state_str(state));
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static gpointer get_stat(struct mwChannel *chan,
|
|
Packit |
16808d |
enum mwChannelStatField field) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
return g_hash_table_lookup(chan->stats, (gpointer) field);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void set_stat(struct mwChannel *chan, enum mwChannelStatField field,
|
|
Packit |
16808d |
gpointer val) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_hash_table_insert(chan->stats, (gpointer) field, val);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
#define incr_stat(chan, field, incr) \
|
|
Packit |
16808d |
set_stat(chan, field, get_stat(chan, field) + incr)
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
#define timestamp_stat(chan, field) \
|
|
Packit |
16808d |
set_stat(chan, field, (gpointer) time(NULL))
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void sup_free(gpointer a) {
|
|
Packit |
16808d |
mwCipherInstance_free(a);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static struct mwCipherInstance *
|
|
Packit |
16808d |
get_supported(struct mwChannel *chan, guint16 id) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
guint32 cid = (guint32) id;
|
|
Packit |
16808d |
return g_hash_table_lookup(chan->supported, GUINT_TO_POINTER(cid));
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void put_supported(struct mwChannel *chan,
|
|
Packit |
16808d |
struct mwCipherInstance *ci) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwCipher *cipher = mwCipherInstance_getCipher(ci);
|
|
Packit |
16808d |
guint32 cid = (guint32) mwCipher_getType(cipher);
|
|
Packit |
16808d |
g_hash_table_insert(chan->supported, GUINT_TO_POINTER(cid), ci);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwChannel *mwChannel_newIncoming(struct mwChannelSet *cs, guint32 id) {
|
|
Packit |
16808d |
struct mwChannel *chan;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_return_val_if_fail(cs != NULL, NULL);
|
|
Packit |
16808d |
g_return_val_if_fail(cs->session != NULL, NULL);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
chan = g_new0(struct mwChannel, 1);
|
|
Packit |
16808d |
chan->state = mwChannel_NEW;
|
|
Packit |
16808d |
chan->session = cs->session;
|
|
Packit |
16808d |
chan->id = id;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
chan->stats = g_hash_table_new(g_direct_hash, g_direct_equal);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
chan->supported = g_hash_table_new_full(g_direct_hash, g_direct_equal,
|
|
Packit |
16808d |
NULL, sup_free);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_hash_table_insert(cs->map, GUINT_TO_POINTER(id), chan);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
state(chan, mwChannel_WAIT, 0);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
return chan;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwChannel *mwChannel_newOutgoing(struct mwChannelSet *cs) {
|
|
Packit |
16808d |
guint32 id;
|
|
Packit |
16808d |
struct mwChannel *chan;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_return_val_if_fail(cs != NULL, NULL);
|
|
Packit |
16808d |
g_return_val_if_fail(cs->map != NULL, NULL);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* grab the next id, and try to make sure there isn't already a
|
|
Packit |
16808d |
channel using it */
|
|
Packit |
16808d |
do {
|
|
Packit |
16808d |
id = ++cs->counter;
|
|
Packit |
16808d |
} while(g_hash_table_lookup(cs->map, GUINT_TO_POINTER(id)));
|
|
Packit |
16808d |
|
|
Packit |
16808d |
chan = mwChannel_newIncoming(cs, id);
|
|
Packit |
16808d |
state(chan, mwChannel_INIT, 0);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
return chan;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
guint32 mwChannel_getId(struct mwChannel *chan) {
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, 0);
|
|
Packit |
16808d |
return chan->id;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwSession *mwChannel_getSession(struct mwChannel *chan) {
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, NULL);
|
|
Packit |
16808d |
return chan->session;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
guint32 mwChannel_getServiceId(struct mwChannel *chan) {
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, 0);
|
|
Packit |
16808d |
return chan->service;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwService *mwChannel_getService(struct mwChannel *chan) {
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, NULL);
|
|
Packit |
16808d |
return mwSession_getService(chan->session, chan->service);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
void mwChannel_setService(struct mwChannel *chan, struct mwService *srvc) {
|
|
Packit |
16808d |
g_return_if_fail(chan != NULL);
|
|
Packit |
16808d |
g_return_if_fail(srvc != NULL);
|
|
Packit |
16808d |
g_return_if_fail(chan->state == mwChannel_INIT);
|
|
Packit |
16808d |
chan->service = mwService_getType(srvc);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
gpointer mwChannel_getServiceData(struct mwChannel *chan) {
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, NULL);
|
|
Packit |
16808d |
return mw_datum_get(&chan->srvc_data);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
void mwChannel_setServiceData(struct mwChannel *chan,
|
|
Packit |
16808d |
gpointer data, GDestroyNotify clean) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_return_if_fail(chan != NULL);
|
|
Packit |
16808d |
mw_datum_set(&chan->srvc_data, data, clean);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
void mwChannel_removeServiceData(struct mwChannel *chan) {
|
|
Packit |
16808d |
g_return_if_fail(chan != NULL);
|
|
Packit |
16808d |
mw_datum_clear(&chan->srvc_data);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
guint32 mwChannel_getProtoType(struct mwChannel *chan) {
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, 0x00);
|
|
Packit |
16808d |
return chan->proto_type;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
void mwChannel_setProtoType(struct mwChannel *chan, guint32 proto_type) {
|
|
Packit |
16808d |
g_return_if_fail(chan != NULL);
|
|
Packit |
16808d |
g_return_if_fail(chan->state == mwChannel_INIT);
|
|
Packit |
16808d |
chan->proto_type = proto_type;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
guint32 mwChannel_getProtoVer(struct mwChannel *chan) {
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, 0x00);
|
|
Packit |
16808d |
return chan->proto_ver;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
void mwChannel_setProtoVer(struct mwChannel *chan, guint32 proto_ver) {
|
|
Packit |
16808d |
g_return_if_fail(chan != NULL);
|
|
Packit |
16808d |
g_return_if_fail(chan->state == mwChannel_INIT);
|
|
Packit |
16808d |
chan->proto_ver = proto_ver;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
guint16 mwChannel_getEncryptPolicy(struct mwChannel *chan) {
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, 0x00);
|
|
Packit |
16808d |
return chan->policy;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
guint32 mwChannel_getOptions(struct mwChannel *chan) {
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, 0x00);
|
|
Packit |
16808d |
return chan->options;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
void mwChannel_setOptions(struct mwChannel *chan, guint32 options) {
|
|
Packit |
16808d |
g_return_if_fail(chan != NULL);
|
|
Packit |
16808d |
g_return_if_fail(chan->state == mwChannel_INIT);
|
|
Packit |
16808d |
chan->options = options;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwLoginInfo *mwChannel_getUser(struct mwChannel *chan) {
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, NULL);
|
|
Packit |
16808d |
return &chan->user;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwOpaque *mwChannel_getAddtlCreate(struct mwChannel *chan) {
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, NULL);
|
|
Packit |
16808d |
return &chan->addtl_create;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwOpaque *mwChannel_getAddtlAccept(struct mwChannel *chan) {
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, NULL);
|
|
Packit |
16808d |
return &chan->addtl_accept;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwCipherInstance *
|
|
Packit |
16808d |
mwChannel_getCipherInstance(struct mwChannel *chan) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, NULL);
|
|
Packit |
16808d |
return chan->cipher;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
enum mwChannelState mwChannel_getState(struct mwChannel *chan) {
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, mwChannel_UNKNOWN);
|
|
Packit |
16808d |
return chan->state;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
gpointer mwChannel_getStatistic(struct mwChannel *chan,
|
|
Packit |
16808d |
enum mwChannelStatField stat) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, 0);
|
|
Packit |
16808d |
g_return_val_if_fail(chan->stats != NULL, 0);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
return get_stat(chan, stat);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* send a channel create message */
|
|
Packit |
16808d |
int mwChannel_create(struct mwChannel *chan) {
|
|
Packit |
16808d |
struct mwMsgChannelCreate *msg;
|
|
Packit |
16808d |
GList *list, *l;
|
|
Packit |
16808d |
int ret;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, -1);
|
|
Packit |
16808d |
g_return_val_if_fail(chan->state == mwChannel_INIT, -1);
|
|
Packit |
16808d |
g_return_val_if_fail(mwChannel_isOutgoing(chan), -1);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
msg = (struct mwMsgChannelCreate *)
|
|
Packit |
16808d |
mwMessage_new(mwMessage_CHANNEL_CREATE);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
msg->channel = chan->id;
|
|
Packit |
16808d |
msg->target.user = g_strdup(chan->user.user_id);
|
|
Packit |
16808d |
msg->target.community = g_strdup(chan->user.community);
|
|
Packit |
16808d |
msg->service = chan->service;
|
|
Packit |
16808d |
msg->proto_type = chan->proto_type;
|
|
Packit |
16808d |
msg->proto_ver = chan->proto_ver;
|
|
Packit |
16808d |
msg->options = chan->options;
|
|
Packit |
16808d |
mwOpaque_clone(&msg->addtl, &chan->addtl_create);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
list = mwChannel_getSupportedCipherInstances(chan);
|
|
Packit |
16808d |
if(list) {
|
|
Packit |
16808d |
/* offer what we have */
|
|
Packit |
16808d |
for(l = list; l; l = l->next) {
|
|
Packit |
16808d |
struct mwEncryptItem *ei = mwCipherInstance_offer(l->data);
|
|
Packit |
16808d |
msg->encrypt.items = g_list_append(msg->encrypt.items, ei);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* we're easy to get along with */
|
|
Packit |
16808d |
chan->offered_policy = mwEncrypt_WHATEVER;
|
|
Packit |
16808d |
g_list_free(list);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
} else {
|
|
Packit |
16808d |
/* we apparently don't support anything */
|
|
Packit |
16808d |
chan->offered_policy = mwEncrypt_NONE;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
msg->encrypt.mode = chan->offered_policy;
|
|
Packit |
16808d |
msg->encrypt.extra = chan->offered_policy;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
ret = mwSession_send(chan->session, MW_MESSAGE(msg));
|
|
Packit |
16808d |
mwMessage_free(MW_MESSAGE(msg));
|
|
Packit |
16808d |
|
|
Packit |
16808d |
state(chan, (ret)? mwChannel_ERROR: mwChannel_WAIT, ret);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
return ret;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void channel_open(struct mwChannel *chan) {
|
|
Packit |
16808d |
state(chan, mwChannel_OPEN, 0);
|
|
Packit |
16808d |
timestamp_stat(chan, mwChannelStat_OPENED_AT);
|
|
Packit |
16808d |
flush_channel(chan);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
int mwChannel_accept(struct mwChannel *chan) {
|
|
Packit |
16808d |
struct mwSession *session;
|
|
Packit |
16808d |
struct mwMsgChannelAccept *msg;
|
|
Packit |
16808d |
struct mwCipherInstance *ci;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
int ret;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, -1);
|
|
Packit |
16808d |
g_return_val_if_fail(mwChannel_isIncoming(chan), -1);
|
|
Packit |
16808d |
g_return_val_if_fail(chan->state == mwChannel_WAIT, -1);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
session = chan->session;
|
|
Packit |
16808d |
g_return_val_if_fail(session != NULL, -1);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
msg = (struct mwMsgChannelAccept *)
|
|
Packit |
16808d |
mwMessage_new(mwMessage_CHANNEL_ACCEPT);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
msg->head.channel = chan->id;
|
|
Packit |
16808d |
msg->service = chan->service;
|
|
Packit |
16808d |
msg->proto_type = chan->proto_type;
|
|
Packit |
16808d |
msg->proto_ver = chan->proto_ver;
|
|
Packit |
16808d |
mwOpaque_clone(&msg->addtl, &chan->addtl_accept);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
ci = chan->cipher;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(! ci) {
|
|
Packit |
16808d |
/* automatically select a cipher if one hasn't been already */
|
|
Packit |
16808d |
|
|
Packit |
16808d |
switch(chan->offered_policy) {
|
|
Packit |
16808d |
case mwEncrypt_NONE:
|
|
Packit |
16808d |
mwChannel_selectCipherInstance(chan, NULL);
|
|
Packit |
16808d |
break;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
case mwEncrypt_RC2_40:
|
|
Packit |
16808d |
ci = get_supported(chan, mwCipher_RC2_40);
|
|
Packit |
16808d |
mwChannel_selectCipherInstance(chan, ci);
|
|
Packit |
16808d |
break;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
case mwEncrypt_RC2_128:
|
|
Packit |
16808d |
ci = get_supported(chan, mwCipher_RC2_128);
|
|
Packit |
16808d |
mwChannel_selectCipherInstance(chan, ci);
|
|
Packit |
16808d |
break;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
case mwEncrypt_WHATEVER:
|
|
Packit |
16808d |
case mwEncrypt_ALL:
|
|
Packit |
16808d |
default:
|
|
Packit |
16808d |
{
|
|
Packit |
16808d |
GList *l, *ll;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
l = mwChannel_getSupportedCipherInstances(chan);
|
|
Packit |
16808d |
if(l) {
|
|
Packit |
16808d |
/* nobody selected a cipher, so we'll just pick the last in
|
|
Packit |
16808d |
the list of available ones */
|
|
Packit |
16808d |
for(ll = l; ll->next; ll = ll->next);
|
|
Packit |
16808d |
ci = ll->data;
|
|
Packit |
16808d |
g_list_free(l);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
mwChannel_selectCipherInstance(chan, ci);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
} else {
|
|
Packit |
16808d |
/* this may cause breakage, but there's really nothing else
|
|
Packit |
16808d |
we can do. They want something we can't provide. If they
|
|
Packit |
16808d |
don't like it, then they'll error the channel out */
|
|
Packit |
16808d |
mwChannel_selectCipherInstance(chan, NULL);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
msg->encrypt.mode = chan->policy; /* set in selectCipherInstance */
|
|
Packit |
16808d |
msg->encrypt.extra = chan->offered_policy;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(chan->cipher) {
|
|
Packit |
16808d |
msg->encrypt.item = mwCipherInstance_accept(chan->cipher);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
ret = mwSession_send(session, MW_MESSAGE(msg));
|
|
Packit |
16808d |
mwMessage_free(MW_MESSAGE(msg));
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(ret) {
|
|
Packit |
16808d |
state(chan, mwChannel_ERROR, ret);
|
|
Packit |
16808d |
} else {
|
|
Packit |
16808d |
channel_open(chan);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
return ret;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void channel_free(struct mwChannel *chan) {
|
|
Packit |
16808d |
struct mwSession *s;
|
|
Packit |
16808d |
struct mwMessage *msg;
|
|
Packit |
16808d |
GSList *l;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* maybe no warning in the future */
|
|
Packit |
16808d |
g_return_if_fail(chan != NULL);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
s = chan->session;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
mwLoginInfo_clear(&chan->user);
|
|
Packit |
16808d |
mwOpaque_clear(&chan->addtl_create);
|
|
Packit |
16808d |
mwOpaque_clear(&chan->addtl_accept);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(chan->supported) {
|
|
Packit |
16808d |
g_hash_table_destroy(chan->supported);
|
|
Packit |
16808d |
chan->supported = NULL;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(chan->stats) {
|
|
Packit |
16808d |
g_hash_table_destroy(chan->stats);
|
|
Packit |
16808d |
chan->stats = NULL;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
mwCipherInstance_free(chan->cipher);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* clean up the outgoing queue */
|
|
Packit |
16808d |
for(l = chan->outgoing_queue; l; l = l->next) {
|
|
Packit |
16808d |
msg = (struct mwMessage *) l->data;
|
|
Packit |
16808d |
l->data = NULL;
|
|
Packit |
16808d |
mwMessage_free(msg);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
g_slist_free(chan->outgoing_queue);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* clean up the incoming queue */
|
|
Packit |
16808d |
for(l = chan->incoming_queue; l; l = l->next) {
|
|
Packit |
16808d |
msg = (struct mwMessage *) l->data;
|
|
Packit |
16808d |
l->data = NULL;
|
|
Packit |
16808d |
mwMessage_free(msg);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
g_slist_free(chan->incoming_queue);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_free(chan);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
int mwChannel_destroy(struct mwChannel *chan,
|
|
Packit |
16808d |
guint32 reason, struct mwOpaque *info) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwMsgChannelDestroy *msg;
|
|
Packit |
16808d |
struct mwSession *session;
|
|
Packit |
16808d |
struct mwChannelSet *cs;
|
|
Packit |
16808d |
int ret;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* may make this not a warning in the future */
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, 0);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
state(chan, reason? mwChannel_ERROR: mwChannel_DESTROY, reason);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
session = chan->session;
|
|
Packit |
16808d |
g_return_val_if_fail(session != NULL, -1);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
cs = mwSession_getChannels(session);
|
|
Packit |
16808d |
g_return_val_if_fail(cs != NULL, -1);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* compose the message */
|
|
Packit |
16808d |
msg = (struct mwMsgChannelDestroy *)
|
|
Packit |
16808d |
mwMessage_new(mwMessage_CHANNEL_DESTROY);
|
|
Packit |
16808d |
msg->head.channel = chan->id;
|
|
Packit |
16808d |
msg->reason = reason;
|
|
Packit |
16808d |
if(info) mwOpaque_clone(&msg->data, info);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* remove the channel from the channel set */
|
|
Packit |
16808d |
g_hash_table_remove(cs->map, GUINT_TO_POINTER(chan->id));
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* send the message */
|
|
Packit |
16808d |
ret = mwSession_send(session, (struct mwMessage *) msg);
|
|
Packit |
16808d |
mwMessage_free(MW_MESSAGE(msg));
|
|
Packit |
16808d |
|
|
Packit |
16808d |
return ret;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void queue_outgoing(struct mwChannel *chan,
|
|
Packit |
16808d |
struct mwMsgChannelSend *msg) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_info("queue_outgoing, channel 0x%08x", chan->id);
|
|
Packit |
16808d |
chan->outgoing_queue = g_slist_append(chan->outgoing_queue, msg);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static int channel_send(struct mwChannel *chan,
|
|
Packit |
16808d |
struct mwMsgChannelSend *msg) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
int ret = 0;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* if the channel is open, send and free the message. Otherwise,
|
|
Packit |
16808d |
queue the message to be sent once the channel is finally
|
|
Packit |
16808d |
opened */
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(chan->state == mwChannel_OPEN) {
|
|
Packit |
16808d |
ret = mwSession_send(chan->session, (struct mwMessage *) msg);
|
|
Packit |
16808d |
mwMessage_free(MW_MESSAGE(msg));
|
|
Packit |
16808d |
|
|
Packit |
16808d |
} else {
|
|
Packit |
16808d |
queue_outgoing(chan, msg);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
return ret;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
int mwChannel_sendEncrypted(struct mwChannel *chan,
|
|
Packit |
16808d |
guint32 type, struct mwOpaque *data,
|
|
Packit |
16808d |
gboolean encrypt) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwMsgChannelSend *msg;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, -1);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
msg = (struct mwMsgChannelSend *) mwMessage_new(mwMessage_CHANNEL_SEND);
|
|
Packit |
16808d |
msg->head.channel = chan->id;
|
|
Packit |
16808d |
msg->type = type;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
mwOpaque_clone(&msg->data, data);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(encrypt && chan->cipher) {
|
|
Packit |
16808d |
msg->head.options = mwMessageOption_ENCRYPT;
|
|
Packit |
16808d |
mwCipherInstance_encrypt(chan->cipher, &msg->data);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
return channel_send(chan, msg);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
int mwChannel_send(struct mwChannel *chan, guint32 type,
|
|
Packit |
16808d |
struct mwOpaque *data) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
return mwChannel_sendEncrypted(chan, type, data, TRUE);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void queue_incoming(struct mwChannel *chan,
|
|
Packit |
16808d |
struct mwMsgChannelSend *msg) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* we clone the message, because session_process will clear it once
|
|
Packit |
16808d |
we return */
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwMsgChannelSend *m = g_new0(struct mwMsgChannelSend, 1);
|
|
Packit |
16808d |
m->head.type = msg->head.type;
|
|
Packit |
16808d |
m->head.options = msg->head.options;
|
|
Packit |
16808d |
m->head.channel = msg->head.channel;
|
|
Packit |
16808d |
mwOpaque_clone(&m->head.attribs, &msg->head.attribs);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
m->type = msg->type;
|
|
Packit |
16808d |
mwOpaque_clone(&m->data, &msg->data);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_info("queue_incoming, channel 0x%08x", chan->id);
|
|
Packit |
16808d |
chan->incoming_queue = g_slist_append(chan->incoming_queue, m);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void channel_recv(struct mwChannel *chan,
|
|
Packit |
16808d |
struct mwMsgChannelSend *msg) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwService *srvc;
|
|
Packit |
16808d |
srvc = mwChannel_getService(chan);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
incr_stat(chan, mwChannelStat_MSG_RECV, 1);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(msg->head.options & mwMessageOption_ENCRYPT) {
|
|
Packit |
16808d |
struct mwOpaque data = { 0, 0 };
|
|
Packit |
16808d |
mwOpaque_clone(&data, &msg->data);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
mwCipherInstance_decrypt(chan->cipher, &data);
|
|
Packit |
16808d |
mwService_recv(srvc, chan, msg->type, &data);
|
|
Packit |
16808d |
mwOpaque_clear(&data);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
} else {
|
|
Packit |
16808d |
mwService_recv(srvc, chan, msg->type, &msg->data);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void flush_channel(struct mwChannel *chan) {
|
|
Packit |
16808d |
GSList *l;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
for(l = chan->incoming_queue; l; l = l->next) {
|
|
Packit |
16808d |
struct mwMsgChannelSend *msg = (struct mwMsgChannelSend *) l->data;
|
|
Packit |
16808d |
l->data = NULL;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
channel_recv(chan, msg);
|
|
Packit |
16808d |
mwMessage_free(MW_MESSAGE(msg));
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
g_slist_free(chan->incoming_queue);
|
|
Packit |
16808d |
chan->incoming_queue = NULL;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
for(l = chan->outgoing_queue; l; l = l->next) {
|
|
Packit |
16808d |
struct mwMessage *msg = (struct mwMessage *) l->data;
|
|
Packit |
16808d |
l->data = NULL;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
mwSession_send(chan->session, msg);
|
|
Packit |
16808d |
mwMessage_free(msg);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
g_slist_free(chan->outgoing_queue);
|
|
Packit |
16808d |
chan->outgoing_queue = NULL;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
void mwChannel_recv(struct mwChannel *chan, struct mwMsgChannelSend *msg) {
|
|
Packit |
16808d |
if(chan->state == mwChannel_OPEN) {
|
|
Packit |
16808d |
channel_recv(chan, msg);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
} else {
|
|
Packit |
16808d |
queue_incoming(chan, msg);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwChannel *mwChannel_find(struct mwChannelSet *cs, guint32 chan) {
|
|
Packit |
16808d |
g_return_val_if_fail(cs != NULL, NULL);
|
|
Packit |
16808d |
g_return_val_if_fail(cs->map != NULL, NULL);
|
|
Packit |
16808d |
return g_hash_table_lookup(cs->map, GUINT_TO_POINTER(chan));
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
void mwChannelSet_free(struct mwChannelSet *cs) {
|
|
Packit |
16808d |
if(! cs) return;
|
|
Packit |
16808d |
if(cs->map) g_hash_table_destroy(cs->map);
|
|
Packit |
16808d |
g_free(cs);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwChannelSet *mwChannelSet_new(struct mwSession *s) {
|
|
Packit |
16808d |
struct mwChannelSet *cs = g_new0(struct mwChannelSet, 1);
|
|
Packit |
16808d |
cs->session = s;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* for some reason, g_int_hash/g_int_equal cause a SIGSEGV */
|
|
Packit |
16808d |
cs->map = g_hash_table_new_full(g_direct_hash, g_direct_equal,
|
|
Packit |
16808d |
NULL, (GDestroyNotify) channel_free);
|
|
Packit |
16808d |
return cs;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
void mwChannel_recvCreate(struct mwChannel *chan,
|
|
Packit |
16808d |
struct mwMsgChannelCreate *msg) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwSession *session;
|
|
Packit |
16808d |
GList *list;
|
|
Packit |
16808d |
struct mwService *srvc;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_return_if_fail(chan != NULL);
|
|
Packit |
16808d |
g_return_if_fail(msg != NULL);
|
|
Packit |
16808d |
g_return_if_fail(chan->id == msg->channel);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
session = chan->session;
|
|
Packit |
16808d |
g_return_if_fail(session != NULL);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(mwChannel_isOutgoing(chan)) {
|
|
Packit |
16808d |
g_warning("channel 0x%08x not an incoming channel", chan->id);
|
|
Packit |
16808d |
mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL);
|
|
Packit |
16808d |
return;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
chan->offered_policy = msg->encrypt.mode;
|
|
Packit |
16808d |
g_message("channel offered with encrypt policy 0x%04x", chan->policy);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
for(list = msg->encrypt.items; list; list = list->next) {
|
|
Packit |
16808d |
struct mwEncryptItem *ei = list->data;
|
|
Packit |
16808d |
struct mwCipher *cipher;
|
|
Packit |
16808d |
struct mwCipherInstance *ci;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_message("channel offered cipher id 0x%04x", ei->id);
|
|
Packit |
16808d |
cipher = mwSession_getCipher(session, ei->id);
|
|
Packit |
16808d |
if(! cipher) {
|
|
Packit |
16808d |
g_message("no such cipher found in session");
|
|
Packit |
16808d |
continue;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
ci = mwCipher_newInstance(cipher, chan);
|
|
Packit |
16808d |
mwCipherInstance_offered(ci, ei);
|
|
Packit |
16808d |
mwChannel_addSupportedCipherInstance(chan, ci);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
mwLoginInfo_clone(&chan->user, &msg->creator);
|
|
Packit |
16808d |
chan->service = msg->service;
|
|
Packit |
16808d |
chan->proto_type = msg->proto_type;
|
|
Packit |
16808d |
chan->proto_ver = msg->proto_ver;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
srvc = mwSession_getService(session, msg->service);
|
|
Packit |
16808d |
if(srvc) {
|
|
Packit |
16808d |
mwService_recvCreate(srvc, chan, msg);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
} else {
|
|
Packit |
16808d |
mwChannel_destroy(chan, ERR_SERVICE_NO_SUPPORT, NULL);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
void mwChannel_recvAccept(struct mwChannel *chan,
|
|
Packit |
16808d |
struct mwMsgChannelAccept *msg) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwService *srvc;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_return_if_fail(chan != NULL);
|
|
Packit |
16808d |
g_return_if_fail(msg != NULL);
|
|
Packit |
16808d |
g_return_if_fail(chan->id == msg->head.channel);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(mwChannel_isIncoming(chan)) {
|
|
Packit |
16808d |
g_warning("channel 0x%08x not an outgoing channel", chan->id);
|
|
Packit |
16808d |
mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL);
|
|
Packit |
16808d |
return;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(chan->state != mwChannel_WAIT) {
|
|
Packit |
16808d |
g_warning("channel 0x%08x state not WAIT: %s",
|
|
Packit |
16808d |
chan->id, state_str(chan->state));
|
|
Packit |
16808d |
mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL);
|
|
Packit |
16808d |
return;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
mwLoginInfo_clone(&chan->user, &msg->acceptor);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
srvc = mwSession_getService(chan->session, chan->service);
|
|
Packit |
16808d |
if(! srvc) {
|
|
Packit |
16808d |
g_warning("no service: 0x%08x", chan->service);
|
|
Packit |
16808d |
mwChannel_destroy(chan, ERR_SERVICE_NO_SUPPORT, NULL);
|
|
Packit |
16808d |
return;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
chan->policy = msg->encrypt.mode;
|
|
Packit |
16808d |
g_message("channel accepted with encrypt policy 0x%04x", chan->policy);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(! msg->encrypt.mode || ! msg->encrypt.item) {
|
|
Packit |
16808d |
/* no mode or no item means no encryption */
|
|
Packit |
16808d |
mwChannel_selectCipherInstance(chan, NULL);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
} else {
|
|
Packit |
16808d |
guint16 cid = msg->encrypt.item->id;
|
|
Packit |
16808d |
struct mwCipherInstance *ci = get_supported(chan, cid);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
if(! ci) {
|
|
Packit |
16808d |
g_warning("not an offered cipher: 0x%04x", cid);
|
|
Packit |
16808d |
mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL);
|
|
Packit |
16808d |
return;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
mwCipherInstance_accepted(ci, msg->encrypt.item);
|
|
Packit |
16808d |
mwChannel_selectCipherInstance(chan, ci);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* mark it as open for the service */
|
|
Packit |
16808d |
state(chan, mwChannel_OPEN, 0);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* let the service know */
|
|
Packit |
16808d |
mwService_recvAccept(srvc, chan, msg);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
/* flush it if the service didn't just immediately close it */
|
|
Packit |
16808d |
if(mwChannel_isState(chan, mwChannel_OPEN)) {
|
|
Packit |
16808d |
channel_open(chan);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
void mwChannel_recvDestroy(struct mwChannel *chan,
|
|
Packit |
16808d |
struct mwMsgChannelDestroy *msg) {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
struct mwChannelSet *cs;
|
|
Packit |
16808d |
struct mwService *srvc;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_return_if_fail(chan != NULL);
|
|
Packit |
16808d |
g_return_if_fail(msg != NULL);
|
|
Packit |
16808d |
g_return_if_fail(chan->id == msg->head.channel);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
state(chan, msg->reason? mwChannel_ERROR: mwChannel_DESTROY, msg->reason);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
srvc = mwChannel_getService(chan);
|
|
Packit |
16808d |
if(srvc) mwService_recvDestroy(srvc, chan, msg);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
cs = mwSession_getChannels(chan->session);
|
|
Packit |
16808d |
g_return_if_fail(cs != NULL);
|
|
Packit |
16808d |
g_return_if_fail(cs->map != NULL);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_hash_table_remove(cs->map, GUINT_TO_POINTER(chan->id));
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
void mwChannel_populateSupportedCipherInstances(struct mwChannel *chan) {
|
|
Packit |
16808d |
struct mwSession *session;
|
|
Packit |
16808d |
GList *list;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_return_if_fail(chan != NULL);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
session = chan->session;
|
|
Packit |
16808d |
g_return_if_fail(session != NULL);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
for(list = mwSession_getCiphers(session); list; list = list->next) {
|
|
Packit |
16808d |
struct mwCipherInstance *ci = mwCipher_newInstance(list->data, chan);
|
|
Packit |
16808d |
if(! ci) continue;
|
|
Packit |
16808d |
put_supported(chan, ci);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
void mwChannel_addSupportedCipherInstance(struct mwChannel *chan,
|
|
Packit |
16808d |
struct mwCipherInstance *ci) {
|
|
Packit |
16808d |
g_return_if_fail(chan != NULL);
|
|
Packit |
16808d |
g_message("channel 0x%08x added cipher %s", chan->id,
|
|
Packit |
16808d |
NSTR(mwCipher_getName(mwCipherInstance_getCipher(ci))));
|
|
Packit |
16808d |
put_supported(chan, ci);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
static void collect(gpointer a, gpointer b, gpointer c) {
|
|
Packit |
16808d |
GList **list = c;
|
|
Packit |
16808d |
*list = g_list_append(*list, b);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
GList *mwChannel_getSupportedCipherInstances(struct mwChannel *chan) {
|
|
Packit |
16808d |
GList *list = NULL;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_return_val_if_fail(chan != NULL, NULL);
|
|
Packit |
16808d |
g_hash_table_foreach(chan->supported, collect, &list);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
return list;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|
|
Packit |
16808d |
void mwChannel_selectCipherInstance(struct mwChannel *chan,
|
|
Packit |
16808d |
struct mwCipherInstance *ci) {
|
|
Packit |
16808d |
struct mwCipher *c;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_return_if_fail(chan != NULL);
|
|
Packit |
16808d |
g_return_if_fail(chan->supported != NULL);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
chan->cipher = ci;
|
|
Packit |
16808d |
if(ci) {
|
|
Packit |
16808d |
guint cid;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
c = mwCipherInstance_getCipher(ci);
|
|
Packit |
16808d |
cid = mwCipher_getType(c);
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_hash_table_steal(chan->supported, GUINT_TO_POINTER(cid));
|
|
Packit |
16808d |
|
|
Packit |
16808d |
switch(mwCipher_getType(c)) {
|
|
Packit |
16808d |
case mwCipher_RC2_40:
|
|
Packit |
16808d |
chan->policy = mwEncrypt_RC2_40;
|
|
Packit |
16808d |
break;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
case mwCipher_RC2_128:
|
|
Packit |
16808d |
chan->policy = mwEncrypt_RC2_128;
|
|
Packit |
16808d |
break;
|
|
Packit |
16808d |
|
|
Packit |
16808d |
default:
|
|
Packit |
16808d |
/* unsure if this is bad */
|
|
Packit |
16808d |
chan->policy = mwEncrypt_WHATEVER;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_message("channel 0x%08x selected cipher %s",
|
|
Packit |
16808d |
chan->id, NSTR(mwCipher_getName(c)));
|
|
Packit |
16808d |
|
|
Packit |
16808d |
} else {
|
|
Packit |
16808d |
|
|
Packit |
16808d |
chan->policy = mwEncrypt_NONE;
|
|
Packit |
16808d |
g_message("channel 0x%08x selected no cipher", chan->id);
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
g_hash_table_destroy(chan->supported);
|
|
Packit |
16808d |
chan->supported = NULL;
|
|
Packit |
16808d |
}
|
|
Packit |
16808d |
|
|
Packit |
16808d |
|