From: fatbob313 Date: Wed, 26 Aug 2009 20:00:32 +0000 (+0000) Subject: Initial import X-Git-Url: http://git.code-monkey.de/?p=umurmur.git;a=commitdiff_plain;h=6a6908d7031a79b5767d86a4da056f65a742ac9f Initial import --- diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e2ed946 --- /dev/null +++ b/Makefile @@ -0,0 +1,53 @@ +include $(TOPDIR)/rules.mk + +# Name and release number of this package +PKG_NAME:=umurmur +PKG_VERSION:=0.1.1 +PKG_RELEASE:=4 + + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + + +define Package/umurmur + SECTION:=net + CATEGORY:=Network + TITLE:=uMurmur + DEPENDS:=+libopenssl +libconfig +endef + + +# Uncomment portion below for Kamikaze and delete DESCRIPTION variable above +define Package/umurmur/description + Minimalistic Mumble server daemon. +endef + +TARGET_CFLAGS := \ + -DWRT_TARGET \ + $(TARGET_CFLAGS) + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +define Build/CompileTarget + CFLAGS="$(TARGET_CFLAGS)" LDFLAGS="$(TARGET_LDFLAGS)"\ + $(MAKE) -C $(PKG_BUILD_DIR)/umurmur.$(1)/umurmur \ + all +endef + +define Package/umurmur/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/umurmurd $(1)/usr/bin/ + $(INSTALL_DIR) $(1)/etc + $(INSTALL_BIN) ./files/umurmur.conf $(1)/etc/umurmur.conf + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/umurmur.init $(1)/etc/init.d/umurmur + $(INSTALL_DIR) $(1)/etc/umurmur +endef + +$(eval $(call BuildPackage,umurmur)) + diff --git a/files/umurmur.conf b/files/umurmur.conf new file mode 100644 index 0000000..42b5e99 --- /dev/null +++ b/files/umurmur.conf @@ -0,0 +1,31 @@ +max_bandwidth = 5000; +welcometext = "Welcome to uMurmur!"; +certificate = "/etc/umurmur/cert.crt"; +private_key = "/etc/umurmur/key.key"; +password = ""; +max_users = 10; + +# Root channel must always be defined first. +# If a channel has a parent, the parent must be defined before the child channel(s). +channels = ( { + name = "Root"; + parent = ""; + description = "The Root of all channels"; + }, + { + name = "Lobby"; + parent = "Root"; + description = "Lobby channel"; + }, + { + name = "Red team"; + parent = "Lobby"; + description = "The Red team channel"; + }, + { + name = "Blue team"; + parent = "Lobby"; + description = "The Blue team channel"; + } +); +default_channel = "COH"; diff --git a/files/umurmur.init b/files/umurmur.init new file mode 100644 index 0000000..44d7802 --- /dev/null +++ b/files/umurmur.init @@ -0,0 +1,15 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2006-2008 OpenWrt.org + +START=90 + +PIDFILE="/var/run/umurmurd.pid" + +start() { + stop + /usr/bin/umurmurd -p $PIDFILE +} + +stop() { + [ -f "$PIDFILE" ] && kill $(cat "$PIDFILE") 2>/dev/null >/dev/null +} \ No newline at end of file diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..e66f475 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,22 @@ +# build helloworld executable when user executes "make" + +SRCS:=client.c main.c messages.c pds.c server.c ssl.c log.c conf.c crypt.c timer.c messagehandler.c channel.c +OBJS:=$(patsubst %.c, %.o, $(SRCS)) +CFLAGS:=$(CFLAGS) -Wall -Os -g +LDFLAGS:=$(LDFLAGS) -lcrypto -lssl -lconfig + +umurmurd:$(OBJS) depend.mak + $(CC) $(LDFLAGS) $(OBJS) -o umurmurd + +# remove object files and executable when user executes "make clean" +clean: + rm *.o umurmurd + +all: umurmur + +$(OBJS): Makefile + +depend.mak: + $(CC) -M $(SRCS) > depend.mak + +include depend.mak \ No newline at end of file diff --git a/src/channel.c b/src/channel.c new file mode 100644 index 0000000..e4ec9ad --- /dev/null +++ b/src/channel.c @@ -0,0 +1,217 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include "log.h" +#include "list.h" +#include "client.h" +#include "channel.h" +#include "conf.h" + + +static int nextchanId; +static channel_t *rootChan; +channel_t *defaultChan; +declare_list(channels); /* A flat list of the channels */ + +static channel_t *createChannel(int id, const char *name, const char *desc) +{ + channel_t *ch; + + ch = malloc(sizeof(channel_t)); + if (ch == NULL) + Log_fatal("out of memory"); + memset(ch, 0, sizeof(channel_t)); + ch->id = id; + strncpy(ch->name, name, MAX_TEXT); + strncpy(ch->desc, desc, MAX_TEXT); + init_list_entry(&ch->subs); + init_list_entry(&ch->node); + init_list_entry(&ch->clients); + init_list_entry(&ch->flatlist_node); + return ch; +} + +#if 0 +/* Might be used when tree travesal becomes neccessary */ +static channel_t *first_subchannel(channel_t *ch) +{ + if (list_empty(&ch->subs)) + return NULL; + else + return list_get_entry(list_get_first(&ch->subs), channel_t, node); +} + +static channel_t *next_channel(channel_t *ch) +{ + if (list_get_next(&ch->node) == &list_get_entry(&ch->node, channel_t, node)->parent->subs) + return NULL; + else + return list_get_entry(list_get_next(&ch->node), channel_t, node); +} +#endif + +void Chan_iterate(channel_t **channelpptr) +{ + channel_t *ch = *channelpptr; + + if (!list_empty(&channels)) { + if (ch == NULL) + ch = list_get_entry(list_get_first(&channels), channel_t, flatlist_node); + else { + if (list_get_next(&ch->flatlist_node) == &channels) + ch = NULL; + else + ch = list_get_entry(list_get_next(&ch->flatlist_node), channel_t, flatlist_node); + } + if (ch) + Log_debug("Channel %d", ch->id); + } + + *channelpptr = ch; +} + +void Chan_init() +{ + int i; + conf_channel_t chdesc; + const char *defaultChannelName; + + defaultChannelName = getStrConf(DEAFULT_CHANNEL); + + for (i = 0; ; i++) { + if (Conf_getNextChannel(&chdesc, i) < 0) { + if (i == 0) + Log_fatal("No valid channels found in configuration file. Exiting."); + break; + } + if (i == 0) { + rootChan = createChannel(0, chdesc.name, chdesc.description); + list_add_tail(&rootChan->flatlist_node, &channels); + if (strcmp(defaultChannelName, chdesc.name) == 0) + defaultChan = rootChan; + } + else { + channel_t *ch, *ch_itr = NULL; + ch = Chan_createChannel(chdesc.name, chdesc.description); + + if (strcmp(defaultChannelName, chdesc.name) == 0) { + Log_info("Setting default channel %s", ch->name); + defaultChan = ch; + } + + do { + Chan_iterate(&ch_itr); + } while (ch_itr != NULL && strcmp(ch_itr->name, chdesc.parent) != 0); + + if (ch_itr == NULL) + Log_fatal("Error in channel configuration: parent not found"); + else { + Chan_addChannel(ch_itr, ch); + Log_info("Adding channel %s parent %s", ch->name, chdesc.parent); + } + } + } + if (defaultChan == NULL) + defaultChan = rootChan; +} + +void Chan_free() +{ + struct dlist *itr, *save; + + list_iterate_safe(itr, save, &channels) { + Log_debug("Free channel %s", list_get_entry(itr, channel_t, flatlist_node)->name); + free(list_get_entry(itr, channel_t, flatlist_node)); + } +} + +channel_t *Chan_createChannel(const char *name, const char *desc) +{ + /* Get an ID */ + nextchanId += 1; + return createChannel(nextchanId, name, desc); +} + +void Chan_freeChannel(channel_t *ch) +{ + list_del(&ch->node); + list_del(&ch->flatlist_node); + free(ch); +} + +void Chan_addChannel(channel_t *parent, channel_t *ch) +{ + list_add_tail(&ch->node, &parent->subs); + ch->parent = parent; + list_add_tail(&ch->flatlist_node, &channels); +} + + +void Chan_playerJoin(channel_t *ch, client_t *client) +{ + /* Only allowed in one channel at a time */ + Log_debug("Add player %s to channel %s", client->playerName, ch->name); + + if (client->channel) + list_del(&client->chan_node); + list_add_tail(&client->chan_node, &ch->clients); + client->channel = (void *)ch; + +} + +void Chan_playerJoin_id(int channelid, client_t *client) +{ + channel_t *ch_itr = NULL; + do { + Chan_iterate(&ch_itr); + } while (ch_itr != NULL && ch_itr->id != channelid); + if (ch_itr == NULL) + Log_warn("Channel id %d not found - ignoring.", channelid); + else + Chan_playerJoin(ch_itr, client); + +} + +void Chan_addChannel_id(int parentId, channel_t *ch) +{ + channel_t *ch_itr = NULL; + do { + Chan_iterate(&ch_itr); + } while (ch_itr != NULL && ch_itr->id != parentId); + if (ch_itr == NULL) + Log_warn("Channel id %d not found - ignoring.", parentId); + else + list_add_tail(&ch->node, &ch_itr->subs); +} + +void Chan_removeChannel(channel_t *ch) +{ + list_del(&ch->node); +} diff --git a/src/channel.h b/src/channel.h new file mode 100644 index 0000000..3fdd940 --- /dev/null +++ b/src/channel.h @@ -0,0 +1,61 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CHANNEL_H_8939873 +#define CHANNEL_H_8939873 + +#include "log.h" +#include "list.h" +#include "client.h" + +typedef struct channel { + int id; + char name[MAX_TEXT]; + char desc[MAX_TEXT]; + struct channel *parent; + struct dlist node; + struct dlist subs; + struct dlist clients; + struct dlist flatlist_node; +} channel_t; + +void Chan_init(); +void Chan_free(); +void Chan_addChannel(channel_t *parent, channel_t *sub); +void Chan_removeChannel(channel_t *c); +void Chan_addClient(channel_t *c, client_t *client); +void Chan_removeClient(channel_t *c, client_t *client); +void Chan_playerJoin(channel_t *ch, client_t *client); +void Chan_playerJoin_id(int channelid, client_t *client); +void Chan_iterate(channel_t **channelpptr); +channel_t *Chan_createChannel(const char *name, const char *desc); +void Chan_freeChannel(channel_t *ch); + +#endif diff --git a/src/client.c b/src/client.c new file mode 100644 index 0000000..94da524 --- /dev/null +++ b/src/client.c @@ -0,0 +1,619 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include +#include +#include "log.h" +#include "list.h" +#include "client.h" +#include "ssl.h" +#include "messages.h" +#include "messagehandler.h" +#include "pds.h" +#include "conf.h" +#include "channel.h" + + + +static int Client_read(client_t *client); +static int Client_write(client_t *client); +static int Client_voiceMsg(client_t *client, pds_t *pds); +static int Client_send_udp(client_t *client, uint8_t *data, int len); +static void Client_voiceMsg_tunnel(client_t *client, message_t *msg); + +declare_list(clients); +static int clientcount; /* = 0 */ +static int session = 1; +static int maxBandwidth; + +extern int udpsock; + +void Client_init() +{ + maxBandwidth = getIntConf(MAX_BANDWIDTH); +} + +int Client_count() +{ + return clientcount; +} + +int Client_getfds(struct pollfd *pollfds) +{ + struct dlist *itr; + int i = 0; + list_iterate(itr, &clients) { + client_t *c; + c = list_get_entry(itr, client_t, node); + pollfds[i].fd = c->tcpfd; + pollfds[i].events = POLLIN | POLLHUP | POLLERR; + if (c->txsize > 0 || c->readBlockedOnWrite) /* Data waiting to be sent? */ + pollfds[i].events |= POLLOUT; + i++; + } + return i; +} + +void Client_janitor() +{ + struct dlist *itr; + int bwTop = maxBandwidth + maxBandwidth / 4; + list_iterate(itr, &clients) { + client_t *c; + c = list_get_entry(itr, client_t, node); + Log_debug("Client %s BW available %d", c->playerName, c->availableBandwidth); + c->availableBandwidth += maxBandwidth; + if (c->availableBandwidth > bwTop) + c->availableBandwidth = bwTop; + + if (Timer_isElapsed(&c->lastActivity, 1000000LL * INACTICITY_TIMEOUT)) + Client_close(c); + } +} + +int Client_add(int fd, struct sockaddr_in *remote) +{ + client_t *newclient; + + newclient = malloc(sizeof(client_t)); + if (newclient == NULL) + Log_fatal("Out of memory"); + memset(newclient, 0, sizeof(client_t)); + + newclient->tcpfd = fd; + memcpy(&newclient->remote_tcp, remote, sizeof(struct sockaddr_in)); + newclient->ssl = SSL_newconnection(newclient->tcpfd, &newclient->SSLready); + if (newclient->ssl == NULL) { + Log_warn("SSL negotiation failed"); + free(newclient); + return -1; + } + newclient->availableBandwidth = maxBandwidth; + Timer_init(&newclient->lastActivity); + newclient->sessionId = session++; /* XXX - more elaborate? */ + + init_list_entry(&newclient->txMsgQueue); + init_list_entry(&newclient->chan_node); + init_list_entry(&newclient->node); + + list_add_tail(&newclient->node, &clients); + clientcount++; + return 0; +} + +void Client_free(client_t *client) +{ + struct dlist *itr, *save; + message_t *sendmsg; + + Log_info("Disconnect client ID %d addr %s port %d", client->sessionId, + inet_ntoa(client->remote_tcp.sin_addr), + ntohs(client->remote_tcp.sin_port)); + + if (client->authenticated) { + sendmsg = Msg_create(ServerLeave); + sendmsg->sessionId = client->sessionId; + Client_send_message_except(client, sendmsg); + } + list_iterate_safe(itr, save, &client->txMsgQueue) { + list_del(&list_get_entry(itr, message_t, node)->node); + Msg_free(list_get_entry(itr, message_t, node)); + } + + list_del(&client->node); + list_del(&client->chan_node); + if (client->ssl) + SSL_free(client->ssl); + close(client->tcpfd); + clientcount--; + free(client); +} + +void Client_close(client_t *client) +{ + SSL_shutdown(client->ssl); + client->shutdown_wait = true; +} + +void Client_disconnect_all() +{ + struct dlist *itr, *save; + + list_iterate_safe(itr, save, &clients) { + Client_free(list_get_entry(itr, client_t, node)); + } +} + +int Client_read_fd(int fd) +{ + struct dlist *itr; + client_t *client = NULL; + + list_iterate(itr, &clients) { + if(fd == list_get_entry(itr, client_t, node)->tcpfd) { + client = list_get_entry(itr, client_t, node); + break; + } + } + if (client == NULL) + Log_fatal("No client found for fd %d", fd); + + return Client_read(client); +} + +int Client_read(client_t *client) +{ + int rc; + + Timer_restart(&client->lastActivity); + + if (client->writeBlockedOnRead) { + client->writeBlockedOnRead = false; + Log_debug("Client_read: writeBlockedOnRead == true"); + return Client_write(client); + } + + if (client->shutdown_wait) { + Client_free(client); + return 0; + } + if (!client->SSLready) { + int rc; + rc = SSL_nonblockaccept(client->ssl, &client->SSLready); + if (rc < 0) { + Client_free(client); + return -1; + } + } + + do { + errno = 0; + if (!client->msgsize) + rc = SSL_read(client->ssl, client->rxbuf, 3 - client->rxcount); + else if (client->drainleft > 0) + rc = SSL_read(client->ssl, client->rxbuf, client->drainleft > BUFSIZE ? BUFSIZE : client->drainleft); + else + rc = SSL_read(client->ssl, &client->rxbuf[client->rxcount], client->msgsize); + if (rc > 0) { + message_t *msg; + if (client->drainleft > 0) + client->drainleft -= rc; + else { + client->rxcount += rc; + if (!client->msgsize && rc >= 3) + client->msgsize = ((client->rxbuf[0] & 0xff) << 16) | + ((client->rxbuf[1] & 0xff) << 8) | + (client->rxbuf[2] & 0xff); + if (client->msgsize > BUFSIZE - 3 && client->drainleft == 0) { + Log_warn("Too big message received (%d). Discarding.", client->msgsize); + client->rxcount = client->msgsize = 0; + client->drainleft = client->msgsize; + } + else if (client->rxcount == client->msgsize + 3) { /* Got all of the message */ + msg = Msg_networkToMessage(&client->rxbuf[3], client->msgsize); + /* pass messsage to handler */ + if (msg) { + if (msg->messageType == Speex) /* Tunneled voice message */ + Client_voiceMsg_tunnel(client, msg); + else + Mh_handle_message(client, msg); + } + client->rxcount = client->msgsize = 0; + } + } + } else /* rc <= 0 */ { + if (SSL_get_error(client->ssl, rc) == SSL_ERROR_WANT_READ) { + return 0; + } + else if (SSL_get_error(client->ssl, rc) == SSL_ERROR_WANT_WRITE) { + client->readBlockedOnWrite = true; + return 0; + } + else if (SSL_get_error(client->ssl, rc) == SSL_ERROR_ZERO_RETURN) { + Log_warn("Error: Zero return - closing"); + if (!client->shutdown_wait) + Client_close(client); + } + else { + if (SSL_get_error(client->ssl, rc) == SSL_ERROR_SYSCALL) { + /* Hmm. This is where we end up when the client closes its connection. + * Kind of strange... + */ + Log_info("Connection closed by peer"); + } + else { + Log_warn("SSL error: %d - Closing connection.", SSL_get_error(client->ssl, rc)); + } + Client_free(client); + return -1; + } + } + } while (SSL_pending(client->ssl)); + return 0; +} + +int Client_write_fd(int fd) +{ + struct dlist *itr; + client_t *client = NULL; + + list_iterate(itr, &clients) { + if(fd == list_get_entry(itr, client_t, node)->tcpfd) { + client = list_get_entry(itr, client_t, node); + break; + } + } + if (client == NULL) + Log_fatal("No client found for fd %d", fd); + Client_write(client); + return 0; +} + +int Client_write(client_t *client) +{ + int rc; + + if (client->readBlockedOnWrite) { + client->readBlockedOnWrite = false; + Log_debug("Client_write: readBlockedOnWrite == true"); + return Client_read(client); + } + rc = SSL_write(client->ssl, &client->txbuf[client->txcount], client->txsize - client->txcount); + if (rc > 0) { + client->txcount += rc; + if (client->txcount == client->txsize) + client->txsize = client->txcount = 0; + } + else if (rc < 0) { + if (SSL_get_error(client->ssl, rc) == SSL_ERROR_WANT_READ) { + client->writeBlockedOnRead = true; + return 0; + } + else if (SSL_get_error(client->ssl, rc) == SSL_ERROR_WANT_WRITE) { + return 0; + } + else { + if (SSL_get_error(client->ssl, rc) == SSL_ERROR_SYSCALL) + Log_warn("Client_write: Error: %s - Closing connection", strerror(errno)); + else + Log_warn("Client_write: SSL error: %d - Closing connection.", SSL_get_error(client->ssl, rc)); + Client_free(client); + return -1; + } + } + if (client->txsize == 0 && !list_empty(&client->txMsgQueue)) { + message_t *msg; + msg = list_get_entry(list_get_first(&client->txMsgQueue), message_t, node); + list_del(list_get_first(&client->txMsgQueue)); + client->txQueueCount--; + Client_send_message(client, msg); + } + return 0; +} + +int Client_send_message(client_t *client, message_t *msg) +{ + if (!client->authenticated || !client->SSLready) { + Msg_free(msg); + return 0; + } + if (client->txsize != 0) { + /* Queue message */ + if ((client->txQueueCount > 5 && msg->messageType == Speex) || + client->txQueueCount > 30) { + Msg_free(msg); + return -1; + } + client->txQueueCount++; + list_add_tail(&msg->node, &client->txMsgQueue); + } else { + int len; + memset(client->txbuf, 0, BUFSIZE); + len = Msg_messageToNetwork(msg, &client->txbuf[3], BUFSIZE - 3); + doAssert(len < BUFSIZE - 3); + + client->txbuf[0] = (len >> 16) & 0xff; + client->txbuf[1] = (len >> 8) & 0xff; + client->txbuf[2] = len & 0xff; + client->txsize = len + 3; + client->txcount = 0; + Client_write(client); + Msg_free(msg); + } + return 0; +} + +client_t *Client_iterate(client_t **client_itr) +{ + client_t *c = *client_itr; + + if (c == NULL && !list_empty(&clients)) { + c = list_get_entry(list_get_first(&clients), client_t, node); + } else { + if (list_get_next(&c->node) == &clients) + c = NULL; + else + c = list_get_entry(list_get_next(&c->node), client_t, node); + } + *client_itr = c; + return c; +} + + +int Client_send_message_except(client_t *client, message_t *msg) +{ + client_t *itr = NULL; + int count = 0; + + Msg_inc_ref(msg); /* Make sure a reference is held during the whole iteration. */ + while (Client_iterate(&itr) != NULL) { + if (itr != client) { + if (count++ > 0) + Msg_inc_ref(msg); /* One extra reference for each new copy */ + Log_debug("Msg %d to %s refcount %d", msg->messageType, itr->playerName, msg->refcount); + Client_send_message(itr, msg); + } + } + Msg_free(msg); /* Free our reference to the message */ + + if (count == 0) + Msg_free(msg); /* If only 1 client is connected then no message is passed + * to Client_send_message(). Free it here. */ + + return 0; +} + +static bool_t checkDecrypt(client_t *client, const uint8_t *encrypted, uint8_t *plain, unsigned int len) +{ + if (CryptState_isValid(&client->cryptState) && + CryptState_decrypt(&client->cryptState, encrypted, plain, len)) + return true; + + if (Timer_elapsed(&client->cryptState.tLastGood) > 5000000ULL) { + if (Timer_elapsed(&client->cryptState.tLastRequest) > 5000000ULL) { + message_t *sendmsg; + Timer_restart(&client->cryptState.tLastRequest); + + sendmsg = Msg_create(CryptSync); + sendmsg->sessionId = client->sessionId; + sendmsg->payload.cryptSync.empty = true; + Log_info("Requesting voice channel crypt resync"); + Client_send_message(client, sendmsg); + } + } + return false; +} + +int Client_read_udp() +{ + int len; + struct sockaddr_in from; + socklen_t fromlen = sizeof(struct sockaddr_in); + uint64_t key; + client_t *itr; + int msgType = 0; + uint32_t sessionId = 0; + pds_t *pds; + +#if defined(__LP64__) + uint8_t encbuff[512 + 8]; + uint8_t *encrypted = encbuff + 4; +#else + uint8_t encrypted[512]; +#endif + uint8_t buffer[512]; + + len = recvfrom(udpsock, encrypted, 512, MSG_TRUNC, (struct sockaddr *)&from, &fromlen); + if (len == 0) { + return -1; + } else if (len < 0) { + return -1; + } else if (len < 6) { + // 4 bytes crypt header + type + session + return 0; + } else if (len > 512) { + return 0; + } + + key = (((uint64_t)from.sin_addr.s_addr) << 16) ^ from.sin_port; + pds = Pds_create(buffer, len - 4); + itr = NULL; + + while (Client_iterate(&itr) != NULL) { + if (itr->key == key) { + if (!checkDecrypt(itr, encrypted, buffer, len)) + goto out; + msgType = Pds_get_numval(pds); + sessionId = Pds_get_numval(pds); + if (itr->sessionId != sessionId) + goto out; + break; + } + } + if (itr == NULL) { /* Unknown peer */ + while (Client_iterate(&itr) != NULL) { + pds->offset = 0; + if (itr->remote_tcp.sin_addr.s_addr == from.sin_addr.s_addr) { + if (checkDecrypt(itr, encrypted, buffer, len)) { + msgType = Pds_get_numval(pds); + sessionId = Pds_get_numval(pds); + if (itr->sessionId == sessionId) { /* Found matching client */ + itr->key = key; + Log_info("New UDP connection from %s port %d sessionId %d", inet_ntoa(from.sin_addr), ntohs(from.sin_port), sessionId); + memcpy(&itr->remote_udp, &from, sizeof(struct sockaddr_in)); + break; + } + } + else Log_warn("Bad cryptstate from peer"); + } + } /* while */ + } + if (itr == NULL) { + goto out; + } + len -= 4; + if (msgType != Speex && msgType != Ping) + goto out; + + if (msgType == Ping) { + Client_send_udp(itr, buffer, len); + } + else { + Client_voiceMsg(itr, pds); + } + +out: + Pds_free(pds); + return 0; +} + +static void Client_voiceMsg_tunnel(client_t *client, message_t *msg) +{ + uint8_t buf[512]; + pds_t *pds = Pds_create(buf, 512); + + Pds_add_numval(pds, msg->messageType); + Pds_add_numval(pds, msg->sessionId); + Pds_add_numval(pds, msg->payload.speex.seq); + Pds_append_data_nosize(pds, msg->payload.speex.data, msg->payload.speex.size); + if (!pds->bOk) + Log_warn("Large Speex message from TCP"); /* XXX - pds resize? */ + pds->maxsize = pds->offset; + Client_voiceMsg(client, pds); + Pds_free(pds); +} + +static int Client_voiceMsg(client_t *client, pds_t *pds) +{ + int seq, flags, msgType, sessionId, packetsize; + channel_t *ch = (channel_t *)client->channel; + struct dlist *itr; + + if (!client->authenticated || client->mute) + return 0; + + + pds->offset = 0; + msgType = Pds_get_numval(pds); + sessionId = Pds_get_numval(pds); + seq = Pds_get_numval(pds); + flags = Pds_get_numval(pds); + + packetsize = 20 + 8 + 4 + pds->maxsize - pds->offset; + if (client->availableBandwidth - packetsize < 0) + return 0; /* Discard */ + + client->availableBandwidth -= packetsize; + + pds->offset = 0; + + if (flags & LoopBack) { + Client_send_udp(client, pds->data, pds->maxsize); + return 0; + } + if (ch == NULL) + return 0; + + list_iterate(itr, &ch->clients) { + client_t *c; + c = list_get_entry(itr, client_t, chan_node); + if (c != client && !c->deaf) { + Client_send_udp(c, pds->data, pds->maxsize); + } + } + return 0; +} + + +static int Client_send_udp(client_t *client, uint8_t *data, int len) +{ + uint8_t *buf, *mbuf; + message_t *sendmsg; + + if (client->remote_udp.sin_port != 0 && CryptState_isValid(&client->cryptState)) { +#if defined(__LP64__) + buf = mbuf = malloc(len + 4 + 16); + buf += 4; +#else + mbuf = buf = malloc(len + 4); +#endif + if (mbuf == NULL) + Log_fatal("Out of memory"); + + CryptState_encrypt(&client->cryptState, data, buf, len); + + sendto(udpsock, buf, len + 4, 0, (struct sockaddr *)&client->remote_udp, sizeof(struct sockaddr_in)); + + free(mbuf); + } else { + pds_t *pds = Pds_create(data, len); + + sendmsg = Msg_create(Pds_get_numval(pds)); + sendmsg->sessionId = Pds_get_numval(pds); + + if (sendmsg->messageType == Speex || sendmsg->messageType == Ping) { + if (sendmsg->messageType == Speex) { + sendmsg->payload.speex.seq = Pds_get_numval(pds); + sendmsg->payload.speex.size = pds->maxsize - pds->offset; + doAssert(pds->maxsize - pds->offset <= SPEEX_DATA_SIZE); + memcpy(sendmsg->payload.speex.data, data + pds->offset, pds->maxsize - pds->offset); + } else { /* Ping */ + sendmsg->payload.ping.timestamp = Pds_get_numval(pds); + } + Client_send_message(client, sendmsg); + } else { + Log_warn("TCP fallback: Unsupported message type %d", sendmsg->messageType); + Msg_free(sendmsg); + } + Pds_free(pds); + } + return 0; +} diff --git a/src/client.h b/src/client.h new file mode 100644 index 0000000..b7460b6 --- /dev/null +++ b/src/client.h @@ -0,0 +1,98 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CLIENT_H_45786678 +#define CLIENT_H_45786678 + +#include +#include +#include /* close() */ +#include +#include /* socket() */ +#include /* IPPROTO_TCP */ +#include /* inet_addr() */ +#include /* errno */ +#include + +#include "list.h" +#include "types.h" +#include "messages.h" +#include "crypt.h" +#include "timer.h" + +#define BUFSIZE 2048 +#define UDP_BUFSIZE 512 +#define INACTICITY_TIMEOUT 15 /* Seconds */ + +#define IS_AUTH(_a_) ((_a_)->authenticated) + +typedef struct { + int tcpfd; + SSL *ssl; + bool_t SSLready; + bool_t shutdown_wait; + cryptState_t cryptState; + bool_t readBlockedOnWrite, writeBlockedOnRead; + + struct sockaddr_in remote_tcp; + struct sockaddr_in remote_udp; + uint8_t rxbuf[BUFSIZE], txbuf[BUFSIZE]; + uint32_t rxcount, msgsize, drainleft, txcount, txsize; + int sessionId; + uint64_t key; + char playerName[MAX_TEXT]; + int playerId; + bool_t authenticated, deaf, mute; + int availableBandwidth; + etimer_t lastActivity; + struct dlist node; + struct dlist txMsgQueue; + int txQueueCount; + /* Channel */ + void *channel; /*Ugly... */ + struct dlist chan_node; +} client_t; + + +void Client_init(); +int Client_getfds(struct pollfd *pollfds); +void Client_janitor(); +int Client_add(int fd, struct sockaddr_in *remote); +int Client_read_fd(int fd); +int Client_write_fd(int fd); +int Client_send_message(client_t *client, message_t *msg); +int Client_count(void); +void Client_close(client_t *client); +client_t *Client_iterate(client_t **client); +int Client_send_message_except(client_t *client, message_t *msg); +int Client_read_udp(void); +void Client_disconnect_all(); + +#endif diff --git a/src/conf.c b/src/conf.c new file mode 100644 index 0000000..540928b --- /dev/null +++ b/src/conf.c @@ -0,0 +1,214 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include +#include + +#ifdef WRT_TARGET +#include +#else +#include +#endif + +#include "types.h" +#include "conf.h" +#include "log.h" + +static config_t configuration; + +#define DEFAULT_CONFIG "/etc/umurmur.conf" +#define DEFAULT_WELCOME "Welcome to uMurmur!" +#define DEFAULT_MAX_CLIENTS 10 +#define DEFAULT_MAX_BANDWIDTH 5000 +#define DEFAULT_BINDPORT 64738 + +const char defaultconfig[] = DEFAULT_CONFIG; + +int Conf_init(const char *conffile) +{ + const char *conf; + + config_init(&configuration); + if (conffile == NULL) + conf = defaultconfig; + else + conf = conffile; + if (config_read_file(&configuration, conf) != CONFIG_TRUE) { + fprintf(stderr, "Error in config file %s: %s at line %d\n", conffile, + config_error_text(&configuration), config_error_line(&configuration)); + exit(1); + } + return 0; +} + +void Conf_deinit() +{ + config_destroy(&configuration); +} + +const char *getStrConf(param_t param) +{ + config_setting_t *setting = NULL; + const char *strsetting = NULL; + + switch (param) { + case CERTIFICATE: + setting = config_lookup(&configuration, "certificate"); + if (!setting) + return "/etc/umurmur/certificate.crt"; + else { + if ((strsetting = config_setting_get_string(setting)) != NULL) + return strsetting; + else + return "/etc/umurmur/certificate.crt"; + } + break; + case KEY: + setting = config_lookup(&configuration, "private_key"); + if (!setting) + return "/etc/umurmur/private_key.key"; + else { + if ((strsetting = config_setting_get_string(setting)) != NULL) + return strsetting; + else + return "/etc/umurmur/private_key.key"; + } + break; + case PASSPHRASE: + setting = config_lookup(&configuration, "password"); + if (!setting) + return ""; + else { + if ((strsetting = config_setting_get_string(setting)) != NULL) + return strsetting; + else + return ""; + } + break; + case BINDADDR: + setting = config_lookup(&configuration, "bindaddr"); + if (!setting) + return ""; + else { + if ((strsetting = config_setting_get_string(setting)) != NULL) + return strsetting; + else + return ""; + } + break; + case WELCOMETEXT: + setting = config_lookup(&configuration, "welcometext"); + if (!setting) + return DEFAULT_WELCOME; + else { + if ((strsetting = config_setting_get_string(setting)) != NULL) + return strsetting; + else + return DEFAULT_WELCOME; + } + break; + case DEAFULT_CHANNEL: + setting = config_lookup(&configuration, "default_channel"); + if (!setting) + return ""; + else { + if ((strsetting = config_setting_get_string(setting)) != NULL) + return strsetting; + else + return ""; + } + break; + default: + doAssert(false); + break; + } + return NULL; +} + +int getIntConf(param_t param) +{ + config_setting_t *setting = NULL; + + switch (param) { + case BINDPORT: + setting = config_lookup(&configuration, "bindport"); + if (!setting) + return DEFAULT_BINDPORT; + else { + return config_setting_get_int(setting); + } + break; + case MAX_BANDWIDTH: + setting = config_lookup(&configuration, "max_bandwidth"); + if (!setting) + return DEFAULT_MAX_BANDWIDTH; + else { + return config_setting_get_int(setting); + } + break; + case MAX_CLIENTS: + setting = config_lookup(&configuration, "max_users"); + if (!setting) + return DEFAULT_MAX_CLIENTS; + else { + return config_setting_get_int(setting); + } + break; + default: + doAssert(false); + } +} + +int Conf_getNextChannel(conf_channel_t *chdesc, int index) +{ + config_setting_t *setting = NULL; + char configstr[64]; + + sprintf(configstr, "channels.[%d].name", index); + setting = config_lookup(&configuration, configstr); + if (setting == NULL) + return -1; + strncpy(chdesc->name, config_setting_get_string(setting), MAX_TEXT); + + sprintf(configstr, "channels.[%d].parent", index); + setting = config_lookup(&configuration, configstr); + if (setting == NULL) + return -1; + strncpy(chdesc->parent, config_setting_get_string(setting), MAX_TEXT); + + sprintf(configstr, "channels.[%d].description", index); + setting = config_lookup(&configuration, configstr); + if (setting == NULL) + return -1; + strncpy(chdesc->description, config_setting_get_string(setting), MAX_TEXT); + + return 0; +} diff --git a/src/conf.h b/src/conf.h new file mode 100644 index 0000000..a42daad --- /dev/null +++ b/src/conf.h @@ -0,0 +1,61 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CONF_H_24564356 +#define CONF_H_24564356 + +#include "messages.h" + +typedef enum param { + CERTIFICATE, + KEY, + PASSPHRASE, + BINDPORT, + BINDADDR, + WELCOMETEXT, + MAX_BANDWIDTH, + MAX_CLIENTS, + DEAFULT_CHANNEL, +} param_t; + +typedef struct { + char parent[MAX_TEXT]; + char name[MAX_TEXT]; + char description[MAX_TEXT]; +} conf_channel_t; + +int Conf_init(const char *conffile); +void Conf_deinit(); + +const char *getStrConf(param_t param); +int getIntConf(param_t param); +int Conf_getNextChannel(conf_channel_t *chdesc, int index); + +#endif diff --git a/src/crypt.c b/src/crypt.c new file mode 100644 index 0000000..a7eda57 --- /dev/null +++ b/src/crypt.c @@ -0,0 +1,329 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + * This code implements OCB-AES128. + * In the US, OCB is covered by patents. The inventor has given a license + * to all programs distributed under the GPL. + * uMurmur is BSD (revised) licensed, meaning you can use the code in a + * closed-source program. If you do, you'll have to either replace + * OCB with something else or get yourself a license. + */ + +#include +#include +#include "crypt.h" +#include "log.h" +static void CryptState_ocb_encrypt(cryptState_t *cs, const unsigned char *plain, unsigned char *encrypted, unsigned int len, const unsigned char *nonce, unsigned char *tag); +static void CryptState_ocb_decrypt(cryptState_t *cs, const unsigned char *encrypted, unsigned char *plain, unsigned int len, const unsigned char *nonce, unsigned char *tag); + +void CryptState_init(cryptState_t *cs) +{ + memset(cs->decrypt_history, 0, 0xff); + memset(cs->raw_key, 0, AES_BLOCK_SIZE); + memset(cs->encrypt_iv, 0, AES_BLOCK_SIZE); + memset(cs->decrypt_iv, 0, AES_BLOCK_SIZE); + cs->bInit = false; + cs->uiGood = cs->uiLate = cs->uiLost = cs->uiResync = 0; + cs->uiRemoteGood = cs->uiRemoteLate = cs->uiRemoteLost = cs->uiRemoteResync = 0; + Timer_init(&cs->tLastGood); + Timer_init(&cs->tLastRequest); +} + +bool_t CryptState_isValid(cryptState_t *cs) +{ + return cs->bInit; +} + +void CryptState_genKey(cryptState_t *cs) { + RAND_bytes(cs->raw_key, AES_BLOCK_SIZE); + RAND_bytes(cs->encrypt_iv, AES_BLOCK_SIZE); + RAND_bytes(cs->decrypt_iv, AES_BLOCK_SIZE); + AES_set_encrypt_key(cs->raw_key, 128, &cs->encrypt_key); + AES_set_decrypt_key(cs->raw_key, 128, &cs->decrypt_key); + cs->bInit = true; +} + +void CryptState_setKey(cryptState_t *cs, const unsigned char *rkey, const unsigned char *eiv, const unsigned char *div) +{ + memcpy(cs->raw_key, rkey, AES_BLOCK_SIZE); + memcpy(cs->encrypt_iv, eiv, AES_BLOCK_SIZE); + memcpy(cs->decrypt_iv, div, AES_BLOCK_SIZE); + AES_set_encrypt_key(cs->raw_key, 128, &cs->encrypt_key); + AES_set_decrypt_key(cs->raw_key, 128, &cs->decrypt_key); + cs->bInit = true; +} + +void CryptState_setDecryptIV(cryptState_t *cs, const unsigned char *iv) +{ + memcpy(cs->decrypt_iv, iv, AES_BLOCK_SIZE); +} + +void CryptState_encrypt(cryptState_t *cs, const unsigned char *source, unsigned char *dst, unsigned int plain_length) +{ + unsigned char tag[AES_BLOCK_SIZE]; + int i; + // First, increase our IV. + for (i = 0; i < AES_BLOCK_SIZE; i++) + if (++cs->encrypt_iv[i]) + break; + + CryptState_ocb_encrypt(cs, source, dst+4, plain_length, cs->encrypt_iv, tag); + + dst[0] = cs->encrypt_iv[0]; + dst[1] = tag[0]; + dst[2] = tag[1]; + dst[3] = tag[2]; +} + +bool_t CryptState_decrypt(cryptState_t *cs, const unsigned char *source, unsigned char *dst, unsigned int crypted_length) +{ + if (crypted_length < 4) + return false; + + unsigned int plain_length = crypted_length - 4; + + unsigned char saveiv[AES_BLOCK_SIZE]; + unsigned char ivbyte = source[0]; + bool_t restore = false; + unsigned char tag[AES_BLOCK_SIZE]; + + int lost = 0; + int late = 0; + + memcpy(saveiv, cs->decrypt_iv, AES_BLOCK_SIZE); + + if (((cs->decrypt_iv[0] + 1) & 0xFF) == ivbyte) { + // In order as expected. + if (ivbyte > cs->decrypt_iv[0]) { + cs->decrypt_iv[0] = ivbyte; + } else if (ivbyte < cs->decrypt_iv[0]) { + int i; + cs->decrypt_iv[0] = ivbyte; + for (i = 1; i < AES_BLOCK_SIZE; i++) + if (++cs->decrypt_iv[i]) + break; + } else { + return false; + } + } else { + // This is either out of order or a repeat. + + int diff = ivbyte - cs->decrypt_iv[0]; + if (diff > 128) + diff = diff-256; + else if (diff < -128) + diff = diff+256; + + if ((ivbyte < cs->decrypt_iv[0]) && (diff > -30) && (diff < 0)) { + // Late packet, but no wraparound. + late = 1; + lost = -1; + cs->decrypt_iv[0] = ivbyte; + restore = true; + } else if ((ivbyte > cs->decrypt_iv[0]) && (diff > -30) && (diff < 0)) { + int i; + // Last was 0x02, here comes 0xff from last round + late = 1; + lost = -1; + cs->decrypt_iv[0] = ivbyte; + for (i = 1; i < AES_BLOCK_SIZE; i++) + if (cs->decrypt_iv[i]--) + break; + restore = true; + } else if ((ivbyte > cs->decrypt_iv[0]) && (diff > 0)) { + // Lost a few packets, but beyond that we're good. + lost = ivbyte - cs->decrypt_iv[0] - 1; + cs->decrypt_iv[0] = ivbyte; + } else if ((ivbyte < cs->decrypt_iv[0]) && (diff > 0)) { + int i; + // Lost a few packets, and wrapped around + lost = 256 - cs->decrypt_iv[0] + ivbyte - 1; + cs->decrypt_iv[0] = ivbyte; + for (i = 1; i < AES_BLOCK_SIZE; i++) + if (++cs->decrypt_iv[i]) + break; + } else { + return false; + } + + if (cs->decrypt_history[cs->decrypt_iv[0]] == cs->decrypt_iv[1]) { + memcpy(cs->decrypt_iv, saveiv, AES_BLOCK_SIZE); + return false; + } + } + + CryptState_ocb_decrypt(cs, source+4, dst, plain_length, cs->decrypt_iv, tag); + + if (memcmp(tag, source+1, 3) != 0) { + memcpy(cs->decrypt_iv, saveiv, AES_BLOCK_SIZE); + return false; + } + cs->decrypt_history[cs->decrypt_iv[0]] = cs->decrypt_iv[1]; + + if (restore) + memcpy(cs->decrypt_iv, saveiv, AES_BLOCK_SIZE); + + cs->uiGood++; + cs->uiLate += late; + cs->uiLost += lost; + + Timer_restart(&cs->tLastGood); + return true; +} + +#if defined(__LP64__) +#define BLOCKSIZE 2 +#define SHIFTBITS 63 +typedef uint64_t subblock; + +#if __BYTE_ORDER == __BIG_ENDIAN +#define SWAPPED(x) (x) +#else +#ifdef __x86_64__ +#define SWAPPED(x) ({register uint64_t __out, __in = (x); __asm__("bswap %q0" : "=r"(__out) : "0"(__in)); __out;}) +#else +#include +#define SWAPPED(x) bswap_64(x) +#endif +#endif + +#else + +#define BLOCKSIZE 4 +#define SHIFTBITS 31 +typedef uint32_t subblock; +#define SWAPPED(x) htonl(x) + +#endif + +#define HIGHBIT (1<> SHIFTBITS; + int i; + for (i=0;i> SHIFTBITS)); + block[BLOCKSIZE-1] = SWAPPED((SWAPPED(block[BLOCKSIZE-1]) << 1) ^(carry * 0x87)); +} + +static void inline S3(subblock *block) { + subblock carry = SWAPPED(block[0]) >> SHIFTBITS; + int i; + for (i=0;i> SHIFTBITS)); + block[BLOCKSIZE-1] ^= SWAPPED((SWAPPED(block[BLOCKSIZE-1]) << 1) ^(carry * 0x87)); +} + +static void inline ZERO(subblock *block) { + int i; + for (i=0;iencrypt_key); + ZERO(checksum); + + while (len > AES_BLOCK_SIZE) { + S2(delta); + XOR(tmp, delta, (const subblock *)(plain)); + AESencrypt(tmp, tmp, &cs->encrypt_key); + XOR((subblock *)(encrypted), delta, tmp); + XOR(checksum, checksum, (subblock *)(plain)); + len -= AES_BLOCK_SIZE; + plain += AES_BLOCK_SIZE; + encrypted += AES_BLOCK_SIZE; + } + + S2(delta); + ZERO(tmp); + tmp[BLOCKSIZE - 1] = SWAPPED(len * 8); + XOR(tmp, tmp, delta); + AESencrypt(tmp, pad, &cs->encrypt_key); + memcpy(tmp, plain, len); + memcpy((unsigned char *)tmp + len, (unsigned char *)pad + len, AES_BLOCK_SIZE - len); + XOR(checksum, checksum, tmp); + XOR(tmp, pad, tmp); + memcpy(encrypted, tmp, len); + + S3(delta); + XOR(tmp, delta, checksum); + AESencrypt(tmp, tag, &cs->encrypt_key); +} + +void CryptState_ocb_decrypt(cryptState_t *cs, const unsigned char *encrypted, unsigned char *plain, unsigned int len, const unsigned char *nonce, unsigned char *tag) { + subblock checksum[BLOCKSIZE], delta[BLOCKSIZE], tmp[BLOCKSIZE], pad[BLOCKSIZE]; + + // Initialize + AESencrypt(nonce, delta, &cs->encrypt_key); + ZERO(checksum); + + while (len > AES_BLOCK_SIZE) { + S2(delta); + XOR(tmp, delta, (const subblock *)(encrypted)); + AESdecrypt(tmp, tmp, &cs->decrypt_key); + XOR((subblock *)(plain), delta, tmp); + XOR(checksum, checksum, (const subblock *)(plain)); + len -= AES_BLOCK_SIZE; + plain += AES_BLOCK_SIZE; + encrypted += AES_BLOCK_SIZE; + } + + S2(delta); + ZERO(tmp); + tmp[BLOCKSIZE - 1] = SWAPPED(len * 8); + XOR(tmp, tmp, delta); + AESencrypt(tmp, pad, &cs->encrypt_key); + memset(tmp, 0, AES_BLOCK_SIZE); + memcpy(tmp, encrypted, len); + XOR(tmp, tmp, pad); + XOR(checksum, checksum, tmp); + memcpy(plain, tmp, len); + + S3(delta); + XOR(tmp, delta, checksum); + AESencrypt(tmp, tag, &cs->encrypt_key); +} diff --git a/src/crypt.h b/src/crypt.h new file mode 100644 index 0000000..e227ed2 --- /dev/null +++ b/src/crypt.h @@ -0,0 +1,71 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef _CRYPTSTATE_H +#define _CRYPTSTATE_H + +#include +#include +#include +#include "timer.h" +#include "types.h" + +typedef struct CryptState { + uint8_t raw_key[AES_BLOCK_SIZE]; + uint8_t encrypt_iv[AES_BLOCK_SIZE]; + uint8_t decrypt_iv[AES_BLOCK_SIZE]; + uint8_t decrypt_history[0x100]; + + unsigned int uiGood; + unsigned int uiLate; + unsigned int uiLost; + unsigned int uiResync; + + unsigned int uiRemoteGood; + unsigned int uiRemoteLate; + unsigned int uiRemoteLost; + unsigned int uiRemoteResync; + + AES_KEY encrypt_key; + AES_KEY decrypt_key; + etimer_t tLastGood; + etimer_t tLastRequest; + bool_t bInit; +} cryptState_t; + +void CryptState_init(cryptState_t *cs); +bool_t CryptState_isValid(cryptState_t *cs); +void CryptState_genKey(cryptState_t *cs); +void CryptState_setKey(cryptState_t *cs, const unsigned char *rkey, const unsigned char *eiv, const unsigned char *div); +void CryptState_setDecryptIV(cryptState_t *cs, const unsigned char *iv); + +bool_t CryptState_decrypt(cryptState_t *cs, const unsigned char *source, unsigned char *dst, unsigned int crypted_length); +void CryptState_encrypt(cryptState_t *cs, const unsigned char *source, unsigned char *dst, unsigned int plain_length); +#endif diff --git a/src/depend.mak b/src/depend.mak new file mode 100644 index 0000000..7243217 --- /dev/null +++ b/src/depend.mak @@ -0,0 +1,418 @@ +client.o: client.c /usr/include/sys/poll.h /usr/include/features.h \ + /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/bits/poll.h /usr/include/sys/socket.h \ + /usr/include/sys/uio.h /usr/include/sys/types.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/time.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/byteswap.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/sigset.h \ + /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/uio.h \ + /usr/include/bits/socket.h /usr/include/bits/sockaddr.h \ + /usr/include/asm/socket.h /usr/include/asm/sockios.h \ + /usr/include/errno.h /usr/include/bits/errno.h \ + /usr/include/linux/errno.h /usr/include/asm/errno.h \ + /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ + log.h types.h list.h client.h /usr/include/openssl/ssl.h \ + /usr/include/openssl/e_os2.h /usr/include/openssl/opensslconf.h \ + /usr/include/openssl/opensslconf-x86_64.h /usr/include/openssl/comp.h \ + /usr/include/openssl/crypto.h /usr/include/stdlib.h \ + /usr/include/alloca.h /usr/include/stdio.h /usr/include/libio.h \ + /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/openssl/stack.h /usr/include/openssl/safestack.h \ + /usr/include/openssl/opensslv.h /usr/include/openssl/ossl_typ.h \ + /usr/include/openssl/symhacks.h /usr/include/openssl/bio.h \ + /usr/include/openssl/x509.h /usr/include/openssl/buffer.h \ + /usr/include/openssl/evp.h /usr/include/openssl/objects.h \ + /usr/include/openssl/obj_mac.h /usr/include/openssl/asn1.h \ + /usr/include/openssl/bn.h /usr/include/openssl/rsa.h \ + /usr/include/openssl/dsa.h /usr/include/openssl/dh.h \ + /usr/include/openssl/sha.h /usr/include/openssl/x509_vfy.h \ + /usr/include/openssl/lhash.h /usr/include/openssl/pkcs7.h \ + /usr/include/openssl/pem.h /usr/include/openssl/pem2.h \ + /usr/include/openssl/kssl.h /usr/include/ctype.h /usr/include/krb5.h \ + /usr/include/krb5/krb5.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/limits.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/posix2_lim.h /usr/include/et/com_err.h \ + /usr/include/openssl/ssl2.h /usr/include/openssl/ssl3.h \ + /usr/include/openssl/pq_compat.h /usr/include/openssl/tls1.h \ + /usr/include/openssl/dtls1.h /usr/include/openssl/pqueue.h \ + /usr/include/string.h /usr/include/openssl/ssl23.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h /usr/include/netinet/in.h /usr/include/bits/in.h \ + /usr/include/arpa/inet.h messages.h /usr/include/openssl/aes.h crypt.h \ + /usr/include/openssl/rand.h timer.h ssl.h /usr/include/openssl/x509v3.h \ + /usr/include/openssl/conf.h messagehandler.h pds.h conf.h channel.h +main.o: main.c /usr/include/stdio.h /usr/include/features.h \ + /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/unistd.h /usr/include/bits/posix_opt.h \ + /usr/include/bits/confname.h /usr/include/getopt.h \ + /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/sigset.h /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ + /usr/include/sys/stat.h /usr/include/bits/stat.h /usr/include/fcntl.h \ + /usr/include/bits/fcntl.h /usr/include/signal.h \ + /usr/include/bits/signum.h /usr/include/bits/siginfo.h \ + /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h \ + /usr/include/bits/sigstack.h /usr/include/bits/sigthread.h \ + /usr/include/sched.h /usr/include/bits/sched.h /usr/include/errno.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h server.h ssl.h \ + /usr/include/openssl/x509v3.h /usr/include/openssl/bio.h \ + /usr/include/openssl/e_os2.h /usr/include/openssl/opensslconf.h \ + /usr/include/openssl/opensslconf-x86_64.h /usr/include/openssl/crypto.h \ + /usr/include/stdlib.h /usr/include/alloca.h \ + /usr/include/openssl/stack.h /usr/include/openssl/safestack.h \ + /usr/include/openssl/opensslv.h /usr/include/openssl/ossl_typ.h \ + /usr/include/openssl/symhacks.h /usr/include/openssl/x509.h \ + /usr/include/openssl/buffer.h /usr/include/openssl/evp.h \ + /usr/include/openssl/objects.h /usr/include/openssl/obj_mac.h \ + /usr/include/openssl/asn1.h /usr/include/openssl/bn.h \ + /usr/include/openssl/rsa.h /usr/include/openssl/dsa.h \ + /usr/include/openssl/dh.h /usr/include/openssl/sha.h \ + /usr/include/openssl/x509_vfy.h /usr/include/openssl/lhash.h \ + /usr/include/openssl/pkcs7.h /usr/include/openssl/conf.h \ + /usr/include/openssl/ssl.h /usr/include/openssl/comp.h \ + /usr/include/openssl/pem.h /usr/include/openssl/pem2.h \ + /usr/include/openssl/kssl.h /usr/include/ctype.h /usr/include/krb5.h \ + /usr/include/krb5/krb5.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/limits.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/posix2_lim.h /usr/include/et/com_err.h \ + /usr/include/openssl/ssl2.h /usr/include/openssl/ssl3.h \ + /usr/include/openssl/pq_compat.h /usr/include/openssl/tls1.h \ + /usr/include/openssl/dtls1.h /usr/include/openssl/pqueue.h \ + /usr/include/string.h /usr/include/openssl/ssl23.h types.h channel.h \ + log.h list.h client.h /usr/include/stdint.h /usr/include/bits/wchar.h \ + /usr/include/sys/socket.h /usr/include/sys/uio.h \ + /usr/include/bits/uio.h /usr/include/bits/socket.h \ + /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ + /usr/include/asm/sockios.h /usr/include/netinet/in.h \ + /usr/include/bits/in.h /usr/include/arpa/inet.h /usr/include/sys/poll.h \ + /usr/include/bits/poll.h messages.h /usr/include/openssl/aes.h crypt.h \ + /usr/include/openssl/rand.h timer.h conf.h +messages.o: messages.c /usr/include/stdlib.h /usr/include/features.h \ + /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \ + /usr/include/sys/types.h /usr/include/bits/types.h \ + /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/sigset.h /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ + /usr/include/alloca.h /usr/include/stdio.h /usr/include/libio.h \ + /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/string.h messages.h /usr/include/stdint.h \ + /usr/include/bits/wchar.h /usr/include/openssl/aes.h \ + /usr/include/openssl/opensslconf.h \ + /usr/include/openssl/opensslconf-x86_64.h list.h types.h pds.h log.h +pds.o: pds.c /usr/include/string.h /usr/include/features.h \ + /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \ + /usr/include/stdlib.h /usr/include/sys/types.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/time.h /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/byteswap.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/sigset.h \ + /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h /usr/include/alloca.h pds.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h types.h log.h +server.o: server.c /usr/include/stdio.h /usr/include/features.h \ + /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/sys/time.h /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/sigset.h /usr/include/sys/poll.h \ + /usr/include/bits/poll.h /usr/include/netinet/tcp.h \ + /usr/include/sys/types.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ + /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ + /usr/include/sys/socket.h /usr/include/sys/uio.h \ + /usr/include/bits/uio.h /usr/include/bits/socket.h \ + /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ + /usr/include/asm/sockios.h /usr/include/errno.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h /usr/include/string.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/limits.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/posix2_lim.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h /usr/include/fcntl.h /usr/include/bits/fcntl.h \ + client.h /usr/include/openssl/ssl.h /usr/include/openssl/e_os2.h \ + /usr/include/openssl/opensslconf.h \ + /usr/include/openssl/opensslconf-x86_64.h /usr/include/openssl/comp.h \ + /usr/include/openssl/crypto.h /usr/include/stdlib.h \ + /usr/include/alloca.h /usr/include/openssl/stack.h \ + /usr/include/openssl/safestack.h /usr/include/openssl/opensslv.h \ + /usr/include/openssl/ossl_typ.h /usr/include/openssl/symhacks.h \ + /usr/include/openssl/bio.h /usr/include/openssl/x509.h \ + /usr/include/openssl/buffer.h /usr/include/openssl/evp.h \ + /usr/include/openssl/objects.h /usr/include/openssl/obj_mac.h \ + /usr/include/openssl/asn1.h /usr/include/openssl/bn.h \ + /usr/include/openssl/rsa.h /usr/include/openssl/dsa.h \ + /usr/include/openssl/dh.h /usr/include/openssl/sha.h \ + /usr/include/openssl/x509_vfy.h /usr/include/openssl/lhash.h \ + /usr/include/openssl/pkcs7.h /usr/include/openssl/pem.h \ + /usr/include/openssl/pem2.h /usr/include/openssl/kssl.h \ + /usr/include/ctype.h /usr/include/krb5.h /usr/include/krb5/krb5.h \ + /usr/include/et/com_err.h /usr/include/openssl/ssl2.h \ + /usr/include/openssl/ssl3.h /usr/include/openssl/pq_compat.h \ + /usr/include/openssl/tls1.h /usr/include/openssl/dtls1.h \ + /usr/include/openssl/pqueue.h /usr/include/openssl/ssl23.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h \ + /usr/include/netinet/in.h /usr/include/bits/in.h \ + /usr/include/arpa/inet.h list.h types.h messages.h \ + /usr/include/openssl/aes.h crypt.h /usr/include/openssl/rand.h timer.h \ + conf.h log.h +ssl.o: ssl.c /usr/include/openssl/x509v3.h /usr/include/openssl/bio.h \ + /usr/include/openssl/e_os2.h /usr/include/openssl/opensslconf.h \ + /usr/include/openssl/opensslconf-x86_64.h /usr/include/stdio.h \ + /usr/include/features.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/openssl/crypto.h /usr/include/stdlib.h \ + /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/sigset.h /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ + /usr/include/alloca.h /usr/include/openssl/stack.h \ + /usr/include/openssl/safestack.h /usr/include/openssl/opensslv.h \ + /usr/include/openssl/ossl_typ.h /usr/include/openssl/symhacks.h \ + /usr/include/openssl/x509.h /usr/include/openssl/buffer.h \ + /usr/include/openssl/evp.h /usr/include/openssl/objects.h \ + /usr/include/openssl/obj_mac.h /usr/include/openssl/asn1.h \ + /usr/include/openssl/bn.h /usr/include/openssl/rsa.h \ + /usr/include/openssl/dsa.h /usr/include/openssl/dh.h \ + /usr/include/openssl/sha.h /usr/include/openssl/x509_vfy.h \ + /usr/include/openssl/lhash.h /usr/include/openssl/pkcs7.h \ + /usr/include/openssl/conf.h /usr/include/openssl/ssl.h \ + /usr/include/openssl/comp.h /usr/include/openssl/pem.h \ + /usr/include/openssl/pem2.h /usr/include/openssl/kssl.h \ + /usr/include/ctype.h /usr/include/krb5.h /usr/include/krb5/krb5.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/limits.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/posix2_lim.h /usr/include/et/com_err.h \ + /usr/include/openssl/ssl2.h /usr/include/openssl/ssl3.h \ + /usr/include/openssl/pq_compat.h /usr/include/openssl/tls1.h \ + /usr/include/openssl/dtls1.h /usr/include/openssl/pqueue.h \ + /usr/include/string.h /usr/include/openssl/ssl23.h \ + /usr/include/openssl/err.h /usr/include/errno.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h conf.h messages.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h \ + /usr/include/openssl/aes.h list.h types.h log.h ssl.h +log.o: log.c /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \ + /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/byteswap.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/sigset.h \ + /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ + /usr/include/syslog.h /usr/include/sys/syslog.h \ + /usr/include/bits/syslog-path.h /usr/include/string.h log.h types.h +conf.o: conf.c /usr/include/stdio.h /usr/include/features.h \ + /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/byteswap.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/sigset.h \ + /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ + /usr/include/string.h /usr/include/libconfig.h types.h conf.h \ + messages.h /usr/include/stdint.h /usr/include/bits/wchar.h \ + /usr/include/openssl/aes.h /usr/include/openssl/opensslconf.h \ + /usr/include/openssl/opensslconf-x86_64.h list.h log.h +crypt.o: crypt.c /usr/include/string.h /usr/include/features.h \ + /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \ + /usr/include/arpa/inet.h /usr/include/netinet/in.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h \ + /usr/include/sys/socket.h /usr/include/sys/uio.h \ + /usr/include/sys/types.h /usr/include/bits/types.h \ + /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/sigset.h /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ + /usr/include/bits/uio.h /usr/include/bits/socket.h \ + /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ + /usr/include/asm/sockios.h /usr/include/bits/in.h crypt.h \ + /usr/include/openssl/rand.h /usr/include/stdlib.h /usr/include/alloca.h \ + /usr/include/openssl/ossl_typ.h /usr/include/openssl/e_os2.h \ + /usr/include/openssl/opensslconf.h \ + /usr/include/openssl/opensslconf-x86_64.h /usr/include/openssl/aes.h \ + timer.h types.h log.h +timer.o: timer.c /usr/include/sys/time.h /usr/include/features.h \ + /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/time.h /usr/include/bits/time.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/sigset.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h /usr/include/stdio.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h timer.h \ + types.h +messagehandler.o: messagehandler.c /usr/include/string.h \ + /usr/include/features.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \ + /usr/include/openssl/aes.h /usr/include/openssl/opensslconf.h \ + /usr/include/openssl/opensslconf-x86_64.h log.h types.h list.h client.h \ + /usr/include/openssl/ssl.h /usr/include/openssl/e_os2.h \ + /usr/include/openssl/comp.h /usr/include/openssl/crypto.h \ + /usr/include/stdlib.h /usr/include/sys/types.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/time.h /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/byteswap.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/sigset.h \ + /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ + /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ + /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/openssl/stack.h /usr/include/openssl/safestack.h \ + /usr/include/openssl/opensslv.h /usr/include/openssl/ossl_typ.h \ + /usr/include/openssl/symhacks.h /usr/include/openssl/bio.h \ + /usr/include/openssl/x509.h /usr/include/openssl/buffer.h \ + /usr/include/openssl/evp.h /usr/include/openssl/objects.h \ + /usr/include/openssl/obj_mac.h /usr/include/openssl/asn1.h \ + /usr/include/openssl/bn.h /usr/include/openssl/rsa.h \ + /usr/include/openssl/dsa.h /usr/include/openssl/dh.h \ + /usr/include/openssl/sha.h /usr/include/openssl/x509_vfy.h \ + /usr/include/openssl/lhash.h /usr/include/openssl/pkcs7.h \ + /usr/include/openssl/pem.h /usr/include/openssl/pem2.h \ + /usr/include/openssl/kssl.h /usr/include/ctype.h /usr/include/krb5.h \ + /usr/include/krb5/krb5.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/limits.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/posix2_lim.h /usr/include/et/com_err.h \ + /usr/include/openssl/ssl2.h /usr/include/openssl/ssl3.h \ + /usr/include/openssl/pq_compat.h /usr/include/openssl/tls1.h \ + /usr/include/openssl/dtls1.h /usr/include/openssl/pqueue.h \ + /usr/include/openssl/ssl23.h /usr/include/stdint.h \ + /usr/include/bits/wchar.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h /usr/include/sys/socket.h /usr/include/sys/uio.h \ + /usr/include/bits/uio.h /usr/include/bits/socket.h \ + /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ + /usr/include/asm/sockios.h /usr/include/netinet/in.h \ + /usr/include/bits/in.h /usr/include/arpa/inet.h /usr/include/errno.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h /usr/include/sys/poll.h \ + /usr/include/bits/poll.h messages.h crypt.h /usr/include/openssl/rand.h \ + timer.h channel.h conf.h +channel.o: channel.c log.h types.h list.h client.h \ + /usr/include/openssl/ssl.h /usr/include/openssl/e_os2.h \ + /usr/include/openssl/opensslconf.h \ + /usr/include/openssl/opensslconf-x86_64.h /usr/include/openssl/comp.h \ + /usr/include/openssl/crypto.h /usr/include/stdlib.h \ + /usr/include/features.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stddef.h \ + /usr/include/sys/types.h /usr/include/bits/types.h \ + /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/sigset.h /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ + /usr/include/alloca.h /usr/include/stdio.h /usr/include/libio.h \ + /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/openssl/stack.h /usr/include/openssl/safestack.h \ + /usr/include/openssl/opensslv.h /usr/include/openssl/ossl_typ.h \ + /usr/include/openssl/symhacks.h /usr/include/openssl/bio.h \ + /usr/include/openssl/x509.h /usr/include/openssl/buffer.h \ + /usr/include/openssl/evp.h /usr/include/openssl/objects.h \ + /usr/include/openssl/obj_mac.h /usr/include/openssl/asn1.h \ + /usr/include/openssl/bn.h /usr/include/openssl/rsa.h \ + /usr/include/openssl/dsa.h /usr/include/openssl/dh.h \ + /usr/include/openssl/sha.h /usr/include/openssl/x509_vfy.h \ + /usr/include/openssl/lhash.h /usr/include/openssl/pkcs7.h \ + /usr/include/openssl/pem.h /usr/include/openssl/pem2.h \ + /usr/include/openssl/kssl.h /usr/include/ctype.h /usr/include/krb5.h \ + /usr/include/krb5/krb5.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/limits.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/posix2_lim.h /usr/include/et/com_err.h \ + /usr/include/openssl/ssl2.h /usr/include/openssl/ssl3.h \ + /usr/include/openssl/pq_compat.h /usr/include/openssl/tls1.h \ + /usr/include/openssl/dtls1.h /usr/include/openssl/pqueue.h \ + /usr/include/string.h /usr/include/openssl/ssl23.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h /usr/include/sys/socket.h /usr/include/sys/uio.h \ + /usr/include/bits/uio.h /usr/include/bits/socket.h \ + /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ + /usr/include/asm/sockios.h /usr/include/netinet/in.h \ + /usr/include/bits/in.h /usr/include/arpa/inet.h /usr/include/errno.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h /usr/include/sys/poll.h \ + /usr/include/bits/poll.h messages.h /usr/include/openssl/aes.h crypt.h \ + /usr/include/openssl/rand.h timer.h channel.h conf.h diff --git a/src/list.h b/src/list.h new file mode 100644 index 0000000..37ec739 --- /dev/null +++ b/src/list.h @@ -0,0 +1,57 @@ +#ifndef LIST_H_87698769870987 +#define LIST_H_87698769870987 + +struct dlist { + struct dlist *next, *prev; +}; + +#define init_list_entry(ptr) \ + do { \ + (ptr)->prev = ptr; (ptr)->next = ptr; } \ + while(0); +#define declare_list(_name_) struct dlist _name_ = {&(_name_), &(_name_) } + +static inline void list_add_head(struct dlist *new, struct dlist *list) +{ + list->next->prev = new; + new->prev = list; + new->next = list->next; + list->next = new; +} + +static inline void list_add_tail(struct dlist *new, struct dlist *list) +{ + list->prev->next = new; + new->prev = list->prev; + new->next = list; + list->prev = new; +} +static inline void list_del(struct dlist *entry) +{ + entry->next->prev = entry->prev; + entry->prev->next = entry->next; +} + +static inline int list_empty(struct dlist *list) +{ + return list->next == list; +} + +#define list_get_first(listhead) \ + ((listhead)->next) + +#define list_get_next(_entry_) \ + ((_entry_)->next) + +#define list_get_entry(entry, type, structmember) \ + ((type *) ((char *)(entry) - (unsigned long)(&((type *)0)->structmember))) + +#define list_iterate(entry, listhead) \ + for(entry = (listhead)->next; entry != (listhead); entry = entry->next) + +#define list_iterate_safe(entry, save, listhead) \ + for(entry = (listhead)->next, save = entry->next; entry != (listhead); \ + entry = save, save = save->next) + + +#endif /* #ifndef LIST_H_87698769870987 */ diff --git a/src/log.c b/src/log.c new file mode 100644 index 0000000..f3bfea6 --- /dev/null +++ b/src/log.c @@ -0,0 +1,141 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include + +#include "log.h" + +#define BUFSIZE 254 + +static bool_t termprint; + +void Log_init(bool_t terminal) +{ + termprint = terminal; + if (!termprint) + openlog("uMurmud", LOG_PID, LOG_DAEMON); +} + +void Log_free() +{ + if (!termprint) + closelog(); +} + + +void logthis(const char *logstring, ...) +{ + va_list argp; + char buf[BUFSIZE + 2]; + + va_start(argp, logstring); + vsnprintf(&buf[0], BUFSIZE, logstring, argp); + va_end(argp); + strcat(buf, "\n"); + if (termprint) + fprintf(stderr, "%s", buf); /* XXX - other targets for logging */ + else + syslog(LOG_INFO, buf); +} + +void Log_warn(const char *logstring, ...) +{ + va_list argp; + char buf[BUFSIZE + 2]; + int offset = 0; + + va_start(argp, logstring); + offset = sprintf(buf, "WARN: "); + vsnprintf(&buf[offset], BUFSIZE - offset, logstring, argp); + va_end(argp); + strcat(buf, "\n"); + if (termprint) + fprintf(stderr, "%s", buf); /* XXX - other targets for logging */ + else + syslog(LOG_ALERT, buf); +} + +void Log_info(const char *logstring, ...) +{ + va_list argp; + char buf[BUFSIZE + 2]; + int offset = 0; + + va_start(argp, logstring); + offset = sprintf(buf, "INFO: "); + vsnprintf(&buf[offset], BUFSIZE - offset, logstring, argp); + va_end(argp); + strcat(buf, "\n"); + if (termprint) + fprintf(stderr, "%s", buf); /* XXX - other targets for logging */ + else + syslog(LOG_ALERT, buf); +} + +#ifdef DEBUG +void Log_debug(const char *logstring, ...) +{ + va_list argp; + char buf[BUFSIZE + 2]; + int offset = 0; + + va_start(argp, logstring); + offset = sprintf(buf, "DEBUG: "); + vsnprintf(&buf[offset], BUFSIZE - offset, logstring, argp); + va_end(argp); + strcat(buf, "\n"); + if (termprint) + fprintf(stderr, "%s", buf); /* XXX - other targets for logging */ + else + syslog(LOG_INFO, buf); +} +#endif + +void Log_fatal(const char *logstring, ...) +{ + va_list argp; + char buf[BUFSIZE + 2]; + int offset = 0; + va_start(argp, logstring); + offset = sprintf(buf, "FATAL: "); + vsnprintf(&buf[offset], BUFSIZE - offset, logstring, argp); + va_end(argp); + strcat(buf, "\n"); + if (termprint) + fprintf(stderr, "%s", buf); /* XXX - other targets for logging */ + else + syslog(LOG_INFO, buf); + exit(1); +} diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..66a2949 --- /dev/null +++ b/src/log.h @@ -0,0 +1,60 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef LOG_H_2435642356 +#define LOG_H_2435642356 + +#include "types.h" + +#define doAssert(_cond_) do { \ + if (!(_cond_)) { \ + logthis("Assertion failed in %s: Line: %d Function: %s", __FILE__, __LINE__, __FUNCTION__); \ + abort(); \ + } \ + } while (0) + + +void logthis(const char *logstring, ...); + +#ifdef DEBUG +void Log_debug(const char *logstring, ...); +#else +#define Log_debug(_args_, ...) ((void)0) +#endif + +void Log_warn(const char *logstring, ...); +void Log_info(const char *logstring, ...); +void Log_fatal(const char *logstring, ...); + +void Log_init(bool_t terminal); +void Log_free(); + +#endif + diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..6892907 --- /dev/null +++ b/src/main.c @@ -0,0 +1,197 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "server.h" +#include "ssl.h" +#include "channel.h" +#include "log.h" +#include "client.h" +#include "conf.h" + +#define UMURMUR_VERSION "0.1.0" + +void lockfile(const char *pidfile) +{ + int lfp; + char str[16]; + + lfp = open(pidfile, O_RDWR|O_CREAT, 0640); + + if (lfp < 0) + Log_fatal("Cannot open PID-file %s for writing", pidfile); + sprintf(str,"%d\n",getpid()); + write(lfp, str, strlen(str)); /* record pid to lockfile */ + Log_info("PID-file: %s", pidfile); +} + + +void signal_handler(int sig) +{ + switch(sig) { + case SIGHUP: + /* XXX - do stuff? */ + Log_info("HUP signal"); + break; + case SIGTERM: + Log_info("TERM signal. Shutting down."); + Server_shutdown(); + break; + } +} + +void daemonize() +{ + int i; + + if (getppid() == 1) + return; /* already a daemon */ + i = fork(); + if ( i < 0) { + fprintf(stderr, "Fork error. Exiting\n"); + exit(1); /* fork error */ + } + if ( i > 0) + exit(0); /* parent exits */ + + /* child (daemon) continues */ + setsid(); /* obtain a new process group */ + for (i = getdtablesize(); i >= 0; --i) + close(i); /* close all descriptors */ + + i = open("/dev/null",O_RDWR); + dup(i); + dup(i); + + umask(027); /* set newly created file permissions */ + chdir("/"); + +} + +void setscheduler() +{ + int rc; + struct sched_param sp; + + sp.sched_priority = sched_get_priority_min(SCHED_RR); /* Should suffice */ + Log_info("Setting SCHED_RR prio %d", sp.sched_priority); + rc = sched_setscheduler(0, SCHED_RR, &sp); + if (rc < 0) + Log_warn("Failed to set scheduler: %s", strerror(errno)); +} + +void printhelp() +{ + printf("uMurmur version %s. Mumble protocol %d\n", UMURMUR_VERSION, MESSAGE_STREAM_VERSION); + printf("Usage: umurmurd [-d] [-p ] [-c ] [-h]\n"); + printf(" -d - Do not deamonize\n"); + printf(" -p - Write PID to this file\n"); + printf(" -c - Specify configuration file\n"); + printf(" -h - Print this help\n"); + exit(0); +} + +int main(int argc, char **argv) +{ + bool_t nodaemon = false; + char *conffile = NULL, *pidfile = NULL; + int c; + + /* Arguments */ + while ((c = getopt(argc, argv, "dp:c:h")) != EOF) { + switch(c) { + case 'c': + conffile = optarg; + break; + case 'p': + pidfile = optarg; + break; + case 'd': + nodaemon = true; + break; + case 'h': + printhelp(); + break; + default: + fprintf(stderr, "Unrecognized option\n"); + printhelp(); + break; + } + } + + if (Conf_init(conffile) != 0) { + fprintf(stderr, "Configuration error\n"); + exit(1); + } + + if (!nodaemon) { + Log_init(false); + daemonize(); + if (pidfile != NULL) + lockfile(pidfile); + } + else + Log_init(true); + + signal(SIGCHLD, SIG_IGN); /* ignore child */ + signal(SIGTSTP, SIG_IGN); /* ignore tty signals */ + signal(SIGTTOU, SIG_IGN); + signal(SIGTTIN, SIG_IGN); + signal(SIGHUP, signal_handler); /* catch hangup signal */ + signal(SIGTERM, signal_handler); /* catch kill signal */ + + /* Initializing */ + SSL_init(); + Chan_init(); + Client_init(); + + setscheduler(); + Server_run(); + + SSL_deinit(); + Chan_free(); + Log_free(); + Conf_deinit(); + + if (pidfile != NULL) + unlink(pidfile); + + return 0; +} diff --git a/src/messagehandler.c b/src/messagehandler.c new file mode 100644 index 0000000..8cca053 --- /dev/null +++ b/src/messagehandler.c @@ -0,0 +1,351 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include + +#include "log.h" +#include "list.h" +#include "client.h" +#include "messages.h" +#include "crypt.h" +#include "channel.h" +#include "conf.h" + +extern channel_t *defaultChan; + +static void sendServerReject(client_t *client, const char *reason, rejectType_t type) +{ + message_t *msg = Msg_create(ServerReject); + msg->sessionId = client->sessionId; + strcpy(msg->payload.serverReject.reason, reason); + msg->payload.serverReject.type = type; + Client_send_message(client, msg); +} + +static void sendPermissionDenied(client_t *client, const char *reason) +{ + message_t *msg = Msg_create(PermissionDenied); + msg->sessionId = client->sessionId; + strncpy(msg->payload.permissionDenied.reason, reason, MAX_TEXT); + Client_send_message(client, msg); +} + +void Mh_handle_message(client_t *client, message_t *msg) +{ + message_t *sendmsg; + channel_t *ch_itr = NULL; + client_t *client_itr; + + switch (msg->messageType) { + case ServerAuthenticate: + /* + * 1. Check stuff, Serverreject if not ok + * 2. Setup UDP encryption -> MessageCryptSetup + * 3. (Enter channel) + * 4. MessageChannelAdd + MessageChannelDescUpdate for all channels + * 5. (MessageChannelLink) + * 6. MessageServerJoin + * 7. MessagePlayerMove + * 8. MessageServerJoin for all connected users + * 9. PlayerDeaf/PlayerMute/PlayerSelfMuteDeaf for all users it applies to + * 10. MessageServerSync + */ + if (msg->payload.serverAuthenticate.version != MESSAGE_STREAM_VERSION) { + char buf[64]; + sprintf(buf, "Wrong version of mumble protocol (client: %d, server: %d)", + msg->payload.serverAuthenticate.version, MESSAGE_STREAM_VERSION); + sendServerReject(client, buf, WrongVersion); + goto disconnect; + } + + client_itr = NULL; + while (Client_iterate(&client_itr) != NULL) { + if (!IS_AUTH(client_itr)) + continue; + if (strncmp(client_itr->playerName, msg->payload.serverAuthenticate.userName, MAX_TEXT) == 0) { + char buf[64]; + sprintf(buf, "Username already in use"); + sendServerReject(client, buf, UsernameInUse); + goto disconnect; + } + } + + if (strncmp(getStrConf(PASSPHRASE), msg->payload.serverAuthenticate.password, MAX_TEXT) != 0) { + char buf[64]; + sprintf(buf, "Wrong server password"); + sendServerReject(client, buf, WrongServerPW); + goto disconnect; + } + + if (strlen(msg->payload.serverAuthenticate.userName) == 0) { /* XXX - other invalid names? */ + char buf[64]; + sprintf(buf, "Invalid username"); + sendServerReject(client, buf, InvalidUsername); + goto disconnect; + } + + if (Client_count() >= getIntConf(MAX_CLIENTS)) { + char buf[64]; + sprintf(buf, "Server is full (max %d users)", getIntConf(MAX_CLIENTS)); + sendServerReject(client, buf, ServerFull); + goto disconnect; + } + + /* Name & password */ + strncpy(client->playerName, msg->payload.serverAuthenticate.userName, MAX_TEXT); + client->playerId = client->sessionId; + + client->authenticated = true; + + /* XXX - Kick ghost */ + + /* Setup UDP encryption */ + CryptState_init(&client->cryptState); + CryptState_genKey(&client->cryptState); + sendmsg = Msg_create(CryptSetup); + sendmsg->sessionId = client->sessionId; + memcpy(sendmsg->payload.cryptSetup.key, client->cryptState.raw_key, AES_BLOCK_SIZE); + memcpy(sendmsg->payload.cryptSetup.serverNonce, client->cryptState.encrypt_iv, AES_BLOCK_SIZE); + memcpy(sendmsg->payload.cryptSetup.clientNonce, client->cryptState.decrypt_iv, AES_BLOCK_SIZE); + Client_send_message(client, sendmsg); + + /* Channel stuff */ + Chan_playerJoin(defaultChan, client); /* Join default channel */ + + /* Iterate channels and send channel info */ + ch_itr = NULL; + Chan_iterate(&ch_itr); + do { + sendmsg = Msg_create(ChannelAdd); + sendmsg->sessionId = 0; + sendmsg->payload.channelAdd.id = ch_itr->id; + if (ch_itr->id == 0) + sendmsg->payload.channelAdd.parentId = -1; + else + sendmsg->payload.channelAdd.parentId = ch_itr->parent->id; + strcpy(sendmsg->payload.channelAdd.name, ch_itr->name); + Client_send_message(client, sendmsg); + + sendmsg = Msg_create(ChannelDescUpdate); + sendmsg->sessionId = 0; + sendmsg->payload.channelDescUpdate.id = ch_itr->id; + strcpy(sendmsg->payload.channelDescUpdate.desc, ch_itr->desc); + Client_send_message(client, sendmsg); + + Chan_iterate(&ch_itr); + } while (ch_itr != NULL); + + /* Not supporting channel link for now */ + + /* Server join for connecting user */ + sendmsg = Msg_create(ServerJoin); + sendmsg->sessionId = client->sessionId; + sendmsg->payload.serverJoin.id = client->playerId; + strcpy(sendmsg->payload.serverJoin.playerName, client->playerName); + Client_send_message_except(client, sendmsg); + + /* Player move for connecting user */ + if (((channel_t *)client->channel)->id != 0) { + sendmsg = Msg_create(PlayerMove); + sendmsg->sessionId = client->sessionId; + sendmsg->payload.playerMove.victim = client->playerId; + sendmsg->payload.playerMove.channel = ((channel_t *)client->channel)->id; + Client_send_message_except(client, sendmsg); + } + client_itr = NULL; + while (Client_iterate(&client_itr) != NULL) { + if (!IS_AUTH(client_itr)) + continue; + sendmsg = Msg_create(ServerJoin); + sendmsg->sessionId = client_itr->sessionId; + sendmsg->payload.serverJoin.id = client_itr->playerId; + strncpy(sendmsg->payload.serverJoin.playerName, client_itr->playerName, MAX_TEXT); + Client_send_message(client, sendmsg); + + sendmsg = Msg_create(PlayerMove); + sendmsg->sessionId = client_itr->sessionId; + sendmsg->payload.playerMove.victim = client_itr->playerId; + sendmsg->payload.playerMove.channel = ((channel_t *)client_itr->channel)->id; + Client_send_message(client, sendmsg); + } + + sendmsg = Msg_create(ServerSync); + sendmsg->sessionId = client->sessionId; + strcpy(sendmsg->payload.serverSync.welcomeText, getStrConf(WELCOMETEXT)); + sendmsg->payload.serverSync.maxBandwidth = getIntConf(MAX_BANDWIDTH); + Client_send_message(client, sendmsg); + + Log_info("Player %s authenticated", client->playerName); + + break; + + case PingStats: + client->cryptState.uiRemoteGood = msg->payload.pingStats.good; + client->cryptState.uiRemoteLate = msg->payload.pingStats.late; + client->cryptState.uiRemoteLost = msg->payload.pingStats.lost; + client->cryptState.uiRemoteResync = msg->payload.pingStats.resync; + + Log_debug("Pingstats <-: %d %d %d %d", + client->cryptState.uiRemoteGood, client->cryptState.uiRemoteLate, + client->cryptState.uiRemoteLost, client->cryptState.uiRemoteResync); + + /* Ignoring the double values since they don't seem to be used */ + sendmsg = Msg_create(PingStats); + sendmsg->sessionId = client->sessionId; + sendmsg->payload.pingStats.timestamp = msg->payload.pingStats.timestamp; + + sendmsg->payload.pingStats.good = client->cryptState.uiGood; + sendmsg->payload.pingStats.late = client->cryptState.uiLate; + sendmsg->payload.pingStats.lost = client->cryptState.uiLost; + sendmsg->payload.pingStats.resync = client->cryptState.uiResync; + + Client_send_message(client, sendmsg); + Log_debug("Pingstats ->: %d %d %d %d", + client->cryptState.uiGood, client->cryptState.uiLate, + client->cryptState.uiLost, client->cryptState.uiResync); + + break; + case Ping: + sendmsg = Msg_create(Ping); + sendmsg->sessionId = client->sessionId; + sendmsg->payload.ping.timestamp = msg->payload.ping.timestamp; + Client_send_message(client, sendmsg); + break; + case CryptSync: + Log_debug("Voice channel crypt resync requested"); + if (msg->payload.cryptSync.empty) { + sendmsg = Msg_create(CryptSync); + sendmsg->sessionId = msg->sessionId; + sendmsg->payload.cryptSync.empty = false; + memcpy(sendmsg->payload.cryptSync.nonce, client->cryptState.decrypt_iv, AES_BLOCK_SIZE); + Client_send_message(client, sendmsg); + } else { + memcpy(client->cryptState.decrypt_iv, msg->payload.cryptSync.nonce, AES_BLOCK_SIZE); + client->cryptState.uiResync++; + } + break; + case PlayerMute: + if (msg->payload.playerMute.victim != client->playerId) { + sendPermissionDenied(client, "Permission denied"); + } else { + Log_debug("Player ID %d muted", msg->payload.playerMute.victim); + client->mute = msg->payload.playerMute.bMute; + } + break; + case PlayerDeaf: + if (msg->payload.playerDeaf.victim != client->playerId) { + sendPermissionDenied(client, "Permission denied"); + } else { + Log_debug("Player ID %d deaf", msg->payload.playerDeaf.victim); + client->deaf = msg->payload.playerDeaf.bDeaf; + } + break; + case TextMessage: + if (msg->payload.textMessage.bTree) + sendPermissionDenied(client, "Tree message not supported"); + else if (msg->payload.textMessage.channel != -1) { /* To channel */ + channel_t *ch_itr = NULL; + do { + Chan_iterate(&ch_itr); + } while (ch_itr != NULL && ch_itr->id != msg->payload.textMessage.channel); + if (ch_itr == NULL) + Log_warn("Channel id %d not found - ignoring.", msg->payload.textMessage.channel); + else { + struct dlist *itr; + list_iterate(itr, &ch_itr->clients) { + client_t *c; + c = list_get_entry(itr, client_t, chan_node); + if (c != client && !c->deaf) { + Msg_inc_ref(msg); + Client_send_message(c, msg); + Log_debug("Text message to player ID %d", c->playerId); + } + } + } + } else { /* To player */ + client_t *itr = NULL; + while (Client_iterate(&itr) != NULL) { + if (!IS_AUTH(itr)) + continue; + if (itr->playerId == msg->payload.textMessage.victim) { + if (!itr->deaf) { + Msg_inc_ref(msg); + Client_send_message(itr, msg); + } + break; + } + } + if (itr == NULL) + Log_warn("TextMessage: Player ID %d not found", msg->payload.textMessage.victim); + } + break; + case PlayerSelfMuteDeaf: + client->deaf = msg->payload.playerSelfMuteDeaf.bDeaf; + client->mute = msg->payload.playerSelfMuteDeaf.bMute; + Log_debug("Player ID %d %s and %s", client->playerId, client->deaf ? "deaf": "not deaf", + client->mute ? "mute" : "not mute"); + break; + case PlayerMove: + Msg_inc_ref(msg); /* Re-use message */ + Client_send_message_except(NULL, msg); + Chan_playerJoin_id(msg->payload.playerMove.channel, client); + break; + + /* Permission denied for all these messages. Not implemented. */ + case PlayerRename: + case ChannelAdd: + case ChannelDescUpdate: + case ContextAction: + case ContextAddAction: + case ServerBanList: + case PlayerKick: + case PlayerBan: + case ChannelRemove: + case ChannelMove: + case ChannelLink: + case ChannelRename: + case EditACL: + sendPermissionDenied(client, "Not supported by uMurmur"); + break; + + case PlayerTexture: /* Ignore */ + break; + + default: + Log_warn("Message %d not handled", msg->messageType); + break; + } + Msg_free(msg); + return; +disconnect: + Msg_free(msg); + Client_close(client); +} diff --git a/src/messagehandler.h b/src/messagehandler.h new file mode 100644 index 0000000..cd46cd7 --- /dev/null +++ b/src/messagehandler.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef MESSAGEHANDLER_H_8907 +#define MESSAGEHANDLER_H_8907 + +void Mh_handle_message(client_t *client, message_t *msg); + +#endif diff --git a/src/messages.c b/src/messages.c new file mode 100644 index 0000000..42f1fa9 --- /dev/null +++ b/src/messages.c @@ -0,0 +1,353 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include + +#include "messages.h" +#include "pds.h" +#include "log.h" + + +void dumpmsg(uint8_t *data, int size); + +int Msg_messageToNetwork(message_t *msg, uint8_t *buffer, int bufsize) +{ + pds_t *pds = Pds_create(buffer, bufsize); + int len; + + Pds_add_numval(pds, msg->messageType); + Pds_add_numval(pds, msg->sessionId); + + switch (msg->messageType) { + case Speex: + Pds_add_numval(pds, msg->payload.speex.seq); + Pds_append_data_nosize(pds, msg->payload.speex.data, msg->payload.speex.size); + break; + case ServerReject: + Pds_add_string(pds, msg->payload.serverReject.reason); + Pds_add_numval(pds, msg->payload.serverReject.type); + break; + case ServerSync: + Pds_add_numval(pds, msg->payload.serverSync.maxBandwidth); + Pds_add_string(pds, msg->payload.serverSync.welcomeText); + break; + case ServerJoin: + Pds_add_string(pds, msg->payload.serverJoin.playerName); + Pds_add_numval(pds, msg->payload.serverJoin.id); + break; + case ChannelDescUpdate: + Pds_add_numval(pds, msg->payload.channelDescUpdate.id); + Pds_add_string(pds, msg->payload.channelDescUpdate.desc); + break; + case ChannelAdd: + Pds_add_numval(pds, msg->payload.channelAdd.id); + Pds_add_numval(pds, msg->payload.channelAdd.parentId); + Pds_add_string(pds, msg->payload.channelAdd.name); + break; + case PlayerMove: + Pds_add_numval(pds, msg->payload.playerMove.victim); + Pds_add_numval(pds, msg->payload.playerMove.channel); + break; + case QueryUsers: + break; + case Ping: + Pds_add_numval(pds, msg->payload.ping.timestamp); + break; + case PingStats: + Pds_add_numval(pds, msg->payload.pingStats.timestamp); + Pds_add_numval(pds, msg->payload.pingStats.good); + Pds_add_numval(pds, msg->payload.pingStats.late); + Pds_add_numval(pds, msg->payload.pingStats.lost); + Pds_add_numval(pds, msg->payload.pingStats.resync); + Pds_add_double(pds, msg->payload.pingStats.dUDPPingAvg); + Pds_add_double(pds, msg->payload.pingStats.dUDPPingVar); + Pds_add_numval(pds, msg->payload.pingStats.UDPPackets); + Pds_add_double(pds, msg->payload.pingStats.dTCPPingAvg); + Pds_add_double(pds, msg->payload.pingStats.dTCPPingVar); + Pds_add_numval(pds, msg->payload.pingStats.TCPPackets); + break; + case PlayerMute: + break; + case PlayerDeaf: + break; + case PlayerSelfMuteDeaf: + break; + case TextMessage: + Pds_add_numval(pds, msg->payload.textMessage.victim); + Pds_add_numval(pds, msg->payload.textMessage.channel); + Pds_add_numval(pds, msg->payload.textMessage.bTree); + Pds_add_string(pds, msg->payload.textMessage.message); + break; + case PermissionDenied: + Pds_add_string(pds, msg->payload.permissionDenied.reason); + break; + case CryptSetup: + Pds_append_data(pds, msg->payload.cryptSetup.key, AES_BLOCK_SIZE); + Pds_append_data(pds, msg->payload.cryptSetup.serverNonce, AES_BLOCK_SIZE); + Pds_append_data(pds, msg->payload.cryptSetup.clientNonce, AES_BLOCK_SIZE); + break; + case CryptSync: + if (!msg->payload.cryptSync.empty) + Pds_append_data(pds, msg->payload.cryptSync.nonce, AES_BLOCK_SIZE); + break; + case ServerLeave: + /* No info to add */ + break; + + default: + Log_warn("Unsupported message %d", msg->messageType); + break; + } + len = pds->offset; + Pds_free(pds); + return len; +} + +message_t *Msg_create(messageType_t messageType) +{ + message_t *msg = malloc(sizeof(message_t)); + + if (msg == NULL) + Log_fatal("Out of memory"); + memset(msg, 0, sizeof(message_t)); + msg->refcount = 1; + msg->messageType = messageType; + init_list_entry(&msg->node); + + if (msg->messageType == Speex) { + msg->payload.speex.data = malloc(SPEEX_DATA_SIZE); + if (msg->payload.speex.data == NULL) + Log_fatal("Out of memory"); + } + return msg; +} + +void Msg_inc_ref(message_t *msg) +{ + msg->refcount++; +} + +void Msg_free(message_t *msg) +{ + if (msg->refcount) msg->refcount--; + if (msg->refcount > 0) + return; + if (msg->messageType == Speex) + free(msg->payload.speex.data); + free(msg); +} + +void dumpmsg(uint8_t *data, int size) +{ + int i, r = 0, offset = 0; + char buf[512]; + + while (r * 8 + i < size) { + for (i = 0; i < 8 && r * 8 + i < size; i++) { + offset += sprintf(buf + offset, "%x ", data[r * 8 + i]); + } + sprintf(buf + offset, "\n"); + printf(buf); + offset = 0; + r++; + i = 0; + } +} + +message_t *Msg_networkToMessage(uint8_t *data, int size) +{ + message_t *msg = NULL; + int messageType; + int sessionId; + pds_t *pds; + + pds = Pds_create(data, size); + messageType = Pds_get_numval(pds); + sessionId = Pds_get_numval(pds); + + switch (messageType) { + case Speex: + msg = Msg_create(Speex); + msg->payload.speex.seq = Pds_get_numval(pds); + msg->payload.speex.size = pds->maxsize - pds->offset; + memcpy(msg->payload.speex.data, &pds->data[pds->offset], pds->maxsize - pds->offset); + break; + case ServerAuthenticate: + msg = Msg_create(ServerAuthenticate); + msg->payload.serverAuthenticate.version = Pds_get_numval(pds); + Pds_get_string(pds, msg->payload.serverAuthenticate.userName, MAX_TEXT); + Pds_get_string(pds, msg->payload.serverAuthenticate.password, MAX_TEXT); + break; + case ServerReject: + msg = Msg_create(ServerReject); + break; + case ServerSync: + msg = Msg_create(ServerSync); + break; + case ServerJoin: + msg = Msg_create(ServerJoin); + break; + case ServerLeave: + msg = Msg_create(ServerLeave); + break; + case QueryUsers: + msg = Msg_create(QueryUsers); + break; + case Ping: + msg = Msg_create(Ping); + msg->payload.ping.timestamp = Pds_get_numval(pds); + break; + case PingStats: + msg = Msg_create(PingStats); + msg->payload.pingStats.timestamp = Pds_get_numval(pds); + msg->payload.pingStats.good = Pds_get_numval(pds); + msg->payload.pingStats.late = Pds_get_numval(pds); + msg->payload.pingStats.lost = Pds_get_numval(pds); + msg->payload.pingStats.resync = Pds_get_numval(pds); + msg->payload.pingStats.dUDPPingAvg = Pds_get_double(pds); + msg->payload.pingStats.dUDPPingVar = Pds_get_double(pds); + msg->payload.pingStats.UDPPackets = Pds_get_numval(pds); + msg->payload.pingStats.dTCPPingAvg = Pds_get_double(pds); + msg->payload.pingStats.dTCPPingVar = Pds_get_double(pds); + msg->payload.pingStats.TCPPackets = Pds_get_numval(pds); + break; + case PlayerMute: + msg = Msg_create(PlayerMute); + msg->payload.playerMute.victim = Pds_get_numval(pds); + msg->payload.playerMute.bMute = Pds_get_numval(pds); + break; + case PlayerDeaf: + msg = Msg_create(PlayerDeaf); + msg->payload.playerDeaf.victim = Pds_get_numval(pds); + msg->payload.playerDeaf.bDeaf = Pds_get_numval(pds); + break; + case PlayerSelfMuteDeaf: + msg = Msg_create(PlayerSelfMuteDeaf); + msg->payload.playerSelfMuteDeaf.bMute = Pds_get_numval(pds); + msg->payload.playerSelfMuteDeaf.bDeaf = Pds_get_numval(pds); + break; + case TextMessage: + msg = Msg_create(TextMessage); + msg->payload.textMessage.victim = Pds_get_numval(pds); + msg->payload.textMessage.channel = Pds_get_numval(pds); + msg->payload.textMessage.bTree = Pds_get_numval(pds); + Pds_get_string(pds, msg->payload.textMessage.message, MAX_TEXT); + break; + case PermissionDenied: + Log_warn("Ignoring message PermissionDenied - not supported"); + break; + case CryptSetup: + Log_warn("Ignoring message CryptSetup - not supported"); + break; + case CryptSync: + msg = Msg_create(CryptSync); + if (Pds_get_data(pds, msg->payload.cryptSync.nonce, AES_BLOCK_SIZE) == 0) + msg->payload.cryptSync.empty = true; + else + msg->payload.cryptSync.empty = false; + break; + case PlayerMove: + msg = Msg_create(PlayerMove); + msg->payload.playerMove.victim = Pds_get_numval(pds); + msg->payload.playerMove.channel = Pds_get_numval(pds); + break; + + /* The commands below are not supported -> no need to read the parameters */ + case PlayerRename: + msg = Msg_create(PlayerRename); + break; + case ChannelAdd: + msg = Msg_create(ChannelAdd); + break; + case ChannelDescUpdate: + msg = Msg_create(ChannelDescUpdate); + break; + case ContextAction: + msg = Msg_create(ContextAction); + break; + case ContextAddAction: + msg = Msg_create(ContextAddAction); + break; + case ServerBanList: + msg = Msg_create(ServerBanList); + break; + case PlayerKick: + msg = Msg_create(PlayerKick); + break; + case PlayerBan: + msg = Msg_create(PlayerBan); + break; + case ChannelRemove: + msg = Msg_create(ChannelRemove); + break; + case ChannelMove: + msg = Msg_create(ChannelMove); + break; + case ChannelLink: + msg = Msg_create(ChannelLink); + break; + case ChannelRename: + msg = Msg_create(ChannelRename); + break; + case EditACL: + msg = Msg_create(EditACL); + break; + case PlayerTexture: + msg = Msg_create(PlayerTexture); + break; + default: + Log_warn("Message: Type %d (session %d) is unknown type", messageType, sessionId); + } + if (msg) { + msg->sessionId = sessionId; +#if 0 + if (!pds->bOk) { + Msg_free(msg); + msg = NULL; + Log_warn("Message: Type %d (session %d, size %d) corrupt or short packet", + messageType, sessionId, pds->offset); + } else if (pds->maxsize - pds->offset != 0) { + Msg_free(msg); + msg = NULL; + Log_warn("Message: Type %d (session %d) Long packet: %d/%d leftover bytes", + messageType, sessionId, pds->overshoot, pds->offset); + } else if (!pds->bOk) { + Msg_free(msg); + msg = NULL; + Log_warn("Message: Type %d (session %d, size %d) failed to validate", messageType, sessionId, pds->maxsize); + } +#endif + } + Pds_free(pds); + return msg; +} diff --git a/src/messages.h b/src/messages.h new file mode 100644 index 0000000..5283222 --- /dev/null +++ b/src/messages.h @@ -0,0 +1,238 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef MESSAGES_H_89768 +#define MESSAGES_H_89768 + +#include +#include +#include "list.h" +#include "types.h" + +#define MAX_TEXT 64 +#define SPEEX_DATA_SIZE 1024 +#define MESSAGE_STREAM_VERSION 4 + +typedef enum { + ServerReject, + ServerAuthenticate, + Speex, + ServerSync, + ServerJoin, + ServerLeave, + ServerBanList, + PlayerMute, + PlayerDeaf, + PlayerKick, + PlayerRename, /*10 */ + PlayerBan, + PlayerMove, + PlayerSelfMuteDeaf, + ChannelAdd, + ChannelRemove, + ChannelMove, + ChannelLink, + ChannelRename, + PermissionDenied, + EditACL, /* 20 */ + QueryUsers, + Ping, + TextMessage, + PlayerTexture, + CryptSetup, + CryptSync, + PingStats, + ContextAction, + ContextAddAction, + ChannelDescUpdate, +} messageType_t; + + +typedef enum { + AltSpeak = 0x01, + LoopBack = 0x02, + EndSpeech = 0x04, + FrameCountMask = 0x30 +} speexflag_t; + +typedef struct { + int speexflag; + int seq; + uint8_t *data; + int size; +} speex_t; + +typedef struct { + int maxBandwidth; + char welcomeText[MAX_TEXT]; +} serverSync_t; + +typedef struct { + char playerName[MAX_TEXT]; + int id; +} serverLeave_t; + +typedef enum { + None, + WrongVersion, + InvalidUsername, + WrongUserPW, + WrongServerPW, + UsernameInUse, + ServerFull +} rejectType_t; + +typedef struct { + char reason[MAX_TEXT]; + rejectType_t type; +} serverReject_t; + +typedef struct { + int version; + char userName[MAX_TEXT]; + char password[MAX_TEXT]; +} serverAuthenticate_t; + +typedef struct { + int id; + int parentId; + char name[MAX_TEXT]; +} channelAdd_t; + +typedef struct { + int id; + char desc[MAX_TEXT]; +} channelDescUpdate_t; + +typedef struct { + char playerName[MAX_TEXT]; + int id; +} serverJoin_t; + +typedef struct { + int victim; + int channel; +} playerMove_t; + +typedef struct { + uint8_t key[AES_BLOCK_SIZE]; + uint8_t clientNonce[AES_BLOCK_SIZE]; + uint8_t serverNonce[AES_BLOCK_SIZE]; +} cryptSetup_t; + +typedef struct { + bool_t empty; + uint8_t nonce[AES_BLOCK_SIZE]; +} cryptSync_t; + +typedef struct { + uint64_t timestamp; +} ping_t; + +typedef struct { + uint64_t timestamp; + uint32_t good; + uint32_t late; + uint32_t lost; + uint32_t resync; + double dUDPPingAvg; + double dUDPPingVar; + uint32_t UDPPackets; + double dTCPPingAvg; + double dTCPPingVar; + uint32_t TCPPackets; +} pingStats_t; + +typedef struct { + char reason[MAX_TEXT]; +} permissionDenied_t; + +typedef struct { + uint32_t victim; + bool_t bMute; +} playerMute_t; + +typedef struct { + uint32_t victim; + bool_t bDeaf; +} playerDeaf_t; + +typedef struct { + bool_t bMute; + bool_t bDeaf; +} playerSelfMuteDeaf_t; + +typedef struct { + int32_t victim; + int32_t channel; + bool_t bTree; + char message[MAX_TEXT]; +} textMessage_t; + +typedef union payload { + speex_t speex; + serverSync_t serverSync; + serverJoin_t serverJoin; + serverLeave_t serverLeave; + serverReject_t serverReject; + serverAuthenticate_t serverAuthenticate; + cryptSetup_t cryptSetup; + cryptSync_t cryptSync; + pingStats_t pingStats; + ping_t ping; + channelAdd_t channelAdd; + channelDescUpdate_t channelDescUpdate; + playerMove_t playerMove; + permissionDenied_t permissinDenied; + playerMute_t playerMute; + playerDeaf_t playerDeaf; + playerSelfMuteDeaf_t playerSelfMuteDeaf; + permissionDenied_t permissionDenied; + textMessage_t textMessage; +} payload_t; + +typedef struct message { + messageType_t messageType; + uint32_t sessionId; + int refcount; + struct dlist node; + payload_t payload; +} message_t; + + + +int Msg_messageToNetwork(message_t *msg, uint8_t *buffer, int bufsize); +message_t *Msg_networkToMessage(uint8_t *data, int size); +void Msg_free(message_t *msg); +void Msg_inc_ref(message_t *msg); + +message_t *Msg_create(messageType_t messageType); + +#endif diff --git a/src/pds.c b/src/pds.c new file mode 100644 index 0000000..7db1e7a --- /dev/null +++ b/src/pds.c @@ -0,0 +1,249 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include +#include "pds.h" +#include "log.h" + +/* + * Data serialization functions below + */ + +typedef union double64u { + uint64_t u64; + double dval; +} double64u_t; + +static inline void append_val(pds_t *pds, uint64_t val) +{ + if (pds->offset < pds->maxsize) + pds->data[pds->offset++] = ((uint8_t)(val)); + else { + pds->bOk = false; + pds->overshoot++; + } +} + +void Pds_append_data(pds_t *pds, const uint8_t *data, uint32_t len) +{ + int left; + Pds_add_numval(pds, len); + left = pds->maxsize - pds->offset; + if (left >= len) { + memcpy(&pds->data[pds->offset], data, len); + pds->offset += len; + } else { + memset(&pds->data[pds->offset], 0, left); + pds->offset += left; + pds->overshoot += len - left; + pds->bOk = false; + } +} + +void Pds_append_data_nosize(pds_t *pds, const uint8_t *data, uint32_t len) +{ + int left; + left = pds->maxsize - pds->offset; + if (left >= len) { + memcpy(&pds->data[pds->offset], data, len); + pds->offset += len; + } else { + memset(&pds->data[pds->offset], 0, left); + pds->offset += left; + pds->overshoot += len - left; + pds->bOk = false; + } +} + +static inline uint64_t next(pds_t *pds) +{ + if (pds->offset < pds->maxsize) + return pds->data[pds->offset++]; + else { + pds->bOk = false; + return 0; + } +} + +pds_t *Pds_create(uint8_t *buf, int size) +{ + pds_t *pds = malloc(sizeof(pds_t)); + if (pds == NULL) + Log_fatal("Out of memory"); + pds->data = buf; + pds->offset = pds->overshoot = 0; + pds->maxsize = size; + pds->bOk = true; + return pds; +} + +void Pds_free(pds_t *pds) +{ + free(pds); +} + +void Pds_add_double(pds_t *pds, double value) +{ + double64u_t u; + + u.dval = value; + + Pds_add_numval(pds, u.u64); +} + +double Pds_get_double(pds_t *pds) +{ + double64u_t u; + u.u64 = Pds_get_numval(pds); + return u.dval; +} +void Pds_add_numval(pds_t *pds, const uint64_t value) +{ + uint64_t i = value; + + if ((i & 0x8000000000000000LL) && (~i < 0x100000000LL)) { + // Signed number. + i = ~i; + if (i <= 0x3) { + // Shortcase for -1 to -4 + append_val(pds, 0xFC | i); + return; + } else { + append_val(pds, 0xF8); + } + } + if (i < 0x80) { + // Need top bit clear + append_val(pds, i); + } else if (i < 0x4000) { + // Need top two bits clear + append_val(pds, (i >> 8) | 0x80); + append_val(pds, i & 0xFF); + } else if (i < 0x200000) { + // Need top three bits clear + append_val(pds, (i >> 16) | 0xC0); + append_val(pds, (i >> 8) & 0xFF); + append_val(pds, i & 0xFF); + } else if (i < 0x10000000) { + // Need top four bits clear + append_val(pds, (i >> 24) | 0xE0); + append_val(pds, (i >> 16) & 0xFF); + append_val(pds, (i >> 8) & 0xFF); + append_val(pds, i & 0xFF); + } else if (i < 0x100000000LL) { + // It's a full 32-bit integer. + append_val(pds, 0xF0); + append_val(pds, (i >> 24) & 0xFF); + append_val(pds, (i >> 16) & 0xFF); + append_val(pds, (i >> 8) & 0xFF); + append_val(pds, i & 0xFF); + } else { + // It's a 64-bit value. + append_val(pds, 0xF4); + append_val(pds, (i >> 56) & 0xFF); + append_val(pds, (i >> 48) & 0xFF); + append_val(pds, (i >> 40) & 0xFF); + append_val(pds, (i >> 32) & 0xFF); + append_val(pds, (i >> 24) & 0xFF); + append_val(pds, (i >> 16) & 0xFF); + append_val(pds, (i >> 8) & 0xFF); + append_val(pds, i & 0xFF); + } +} + +uint64_t Pds_get_numval(pds_t *pds) +{ + uint64_t i = 0; + uint64_t v = next(pds); + + if ((v & 0x80) == 0x00) { + i=(v & 0x7F); + } else if ((v & 0xC0) == 0x80) { + i=(v & 0x3F) << 8 | next(pds); + } else if ((v & 0xF0) == 0xF0) { + switch (v & 0xFC) { + case 0xF0: + i=next(pds) << 24 | next(pds) << 16 | next(pds) << 8 | next(pds); + break; + case 0xF4: + i=next(pds) << 56 | next(pds) << 48 | next(pds) << 40 | next(pds) << 32 | next(pds) << 24 | next(pds) << 16 | next(pds) << 8 | next(pds); + break; + case 0xF8: + i = Pds_get_numval(pds); + i = ~i; + break; + case 0xFC: + i=v & 0x03; + i = ~i; + break; + default: + //ok = false; + i = 0; + break; + } + } else if ((v & 0xF0) == 0xE0) { + i=(v & 0x0F) << 24 | next(pds) << 16 | next(pds) << 8 | next(pds); + } else if ((v & 0xE0) == 0xC0) { + i=(v & 0x1F) << 16 | next(pds) << 8 | next(pds); + } + return i; +} + +void Pds_add_string(pds_t *pds, const char *str) +{ + Pds_append_data(pds, (uint8_t *)str, strlen(str)); +} + +void Pds_get_string(pds_t *pds, char *str, int maxlen) +{ + int len = Pds_get_numval(pds); + if (len < maxlen) { + memcpy(str, &pds->data[pds->offset], len); + str[len] = '\0'; + pds->offset += len; + } else { + Log_warn("Too long string from network"); + strcpy(str, "N/A"); + } +} + +int Pds_get_data(pds_t *pds, uint8_t *data, int maxlen) +{ + int len = Pds_get_numval(pds); + if (len < maxlen) { + memcpy(data, &pds->data[pds->offset], len); + pds->offset += len; + return len; + } else { + Log_warn("Pds_get_data: Too much data from network"); + return -1; + } +} diff --git a/src/pds.h b/src/pds.h new file mode 100644 index 0000000..e5be19b --- /dev/null +++ b/src/pds.h @@ -0,0 +1,58 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef PDS_H_457865876 +#define PDS_H_457865876 + +#include +#include "types.h" + +typedef struct { + uint8_t *data; + uint32_t maxsize; + uint32_t offset; + uint32_t overshoot; + bool_t bOk; +} pds_t; + +void Pds_append_data(pds_t *pds, const uint8_t *data, uint32_t len); +void Pds_append_data_nosize(pds_t *pds, const uint8_t *data, uint32_t len); +uint64_t Pds_get_numval(pds_t *pds); +void Pds_add_numval(pds_t *pds, const uint64_t value); +pds_t *Pds_create(uint8_t *buf, int size); +void Pds_free(pds_t *pds); +void Pds_add_string(pds_t *pds, const char *str); +void Pds_get_string(pds_t *pds, char *str, int maxlen); +void Pds_add_double(pds_t *pds, double value); +double Pds_get_double(pds_t *pds); +int Pds_get_data(pds_t *pds, uint8_t *data, int maxlen); + + +#endif diff --git a/src/server.c b/src/server.c new file mode 100644 index 0000000..7cabfb3 --- /dev/null +++ b/src/server.c @@ -0,0 +1,173 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "client.h" +#include "conf.h" +#include "log.h" +#include "timer.h" + +#define LISTEN_SOCK 0 +#define TCP_SOCK 0 +#define UDP_SOCK 1 + +int udpsock; /* XXX restructure! */ +bool_t shutdown_server; + +void Server_run() +{ + int timeout = 1000, rc; + struct pollfd *pollfds; + int tcpsock, sockopt = 1; + struct sockaddr_in sin; + int val, clientcount; + etimer_t janitorTimer; + + /* max clients + listen sock + udp sock + client connecting that will be disconnected */ + pollfds = malloc((getIntConf(MAX_CLIENTS) + 3) * sizeof(struct pollfd)); + if (pollfds == NULL) + Log_fatal("out of memory"); + + /* Prepare TCP socket */ + memset(&sin, 0, sizeof(sin)); + tcpsock = socket(PF_INET, SOCK_STREAM, 0); + if (tcpsock < 0) + Log_fatal("socket"); + if (setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) != 0) + Log_fatal("setsockopt: %s", strerror(errno)); + sin.sin_family = AF_INET; + sin.sin_port = htons(getIntConf(BINDPORT)); + sin.sin_addr.s_addr = inet_addr(getStrConf(BINDADDR)) == -1 ? inet_addr("0.0.0.0") : inet_addr(getStrConf(BINDADDR)); + rc = bind(tcpsock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in)); + if (rc < 0) Log_fatal("bind: %s", strerror(errno)); + rc = listen(tcpsock, 3); + if (rc < 0) Log_fatal("listen"); + fcntl(tcpsock, F_SETFL, O_NONBLOCK); + + pollfds[LISTEN_SOCK].fd = tcpsock; + pollfds[LISTEN_SOCK].events = POLLIN; + + /* Prepare UDP socket */ + memset(&sin, 0, sizeof(sin)); + udpsock = socket(PF_INET, SOCK_DGRAM, 0); + sin.sin_family = AF_INET; + sin.sin_port = htons(getIntConf(BINDPORT)); + sin.sin_addr.s_addr = inet_addr(getStrConf(BINDADDR)) == -1 ? inet_addr("0.0.0.0") : inet_addr(getStrConf(BINDADDR)); + rc = bind(udpsock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in)); + if (rc < 0) + Log_fatal("bind %d %s: %s", getIntConf(BINDPORT), getStrConf(BINDADDR), strerror(errno)); + val = 0xe0; + rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val)); + if (rc < 0) + Log_fatal("Server: Failed to set TOS for UDP Socket"); + val = 0x80; + rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val)); + if (rc < 0) + Log_fatal("Server: Failed to set TOS for UDP Socket"); + + fcntl(udpsock, F_SETFL, O_NONBLOCK); + pollfds[UDP_SOCK].fd = udpsock; + pollfds[UDP_SOCK].events = POLLIN | POLLHUP | POLLERR; + + Timer_init(&janitorTimer); + + /* Main server loop */ + while (!shutdown_server) { + struct sockaddr_in remote; + int i; + + pollfds[UDP_SOCK].revents = 0; + pollfds[TCP_SOCK].revents = 0; + clientcount = Client_getfds(&pollfds[2]); + + timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL; + if (timeout <= 0) { + Client_janitor(); + Timer_restart(&janitorTimer); + timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL; + } + rc = poll(pollfds, clientcount + 2, timeout); + if (rc == 0) { /* Timeout */ + /* Do maintenance */ + Timer_restart(&janitorTimer); + Client_janitor(); + continue; + } + if (rc < 0) { + if (errno == EINTR) /* signal */ + continue; + else + Log_fatal("poll: error %d", errno); + } + if (pollfds[LISTEN_SOCK].revents) { /* New tcp connection */ + int tcpfd, flag = 1; + uint32_t addrlen; + addrlen = sizeof(struct sockaddr_in); + tcpfd = accept(pollfds[LISTEN_SOCK].fd, (struct sockaddr*)&remote, &addrlen); + fcntl(tcpfd, F_SETFL, O_NONBLOCK); + setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); + Log_info("Connection from %s port %d\n", inet_ntoa(remote.sin_addr), + ntohs(remote.sin_port)); + Client_add(tcpfd, &remote); + } + + if (pollfds[UDP_SOCK].revents) { + Client_read_udp(); + } + for (i = 0; i < clientcount; i++) { + if (pollfds[i + 2].revents & POLLIN) { + Client_read_fd(pollfds[i + 2].fd); + } + if (pollfds[i + 2].revents & POLLOUT) { + Client_write_fd(pollfds[i + 2].fd); + } + } + } + + /* Disconnect clients */ + Client_disconnect_all(); + free(pollfds); +} + +void Server_shutdown() +{ + shutdown_server = true; +} diff --git a/src/server.h b/src/server.h new file mode 100644 index 0000000..aa48482 --- /dev/null +++ b/src/server.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SERVER_H_347563 +#define SERVER_H_347563 + +void Server_run(); +void Server_shutdown(); + +#endif diff --git a/src/ssl.c b/src/ssl.c new file mode 100644 index 0000000..42f9610 --- /dev/null +++ b/src/ssl.c @@ -0,0 +1,368 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include +#include +#include +#include + +#include "conf.h" +#include "log.h" +#include "ssl.h" + +static X509 *x509; +static RSA *rsa; +static SSL_CTX *context; +static EVP_PKEY *pkey; + +static int SSL_add_ext(X509 * crt, int nid, char *value) { + X509_EXTENSION *ex; + X509V3_CTX ctx; + X509V3_set_ctx_nodb(&ctx); + X509V3_set_ctx(&ctx, crt, crt, NULL, NULL, 0); + ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value); + if (!ex) + return 0; + + X509_add_ext(crt, ex, -1); + X509_EXTENSION_free(ex); + return 1; +} + +static X509 *SSL_readcert(char *certfile) +{ + FILE *fp; + X509 *x509; + + /* open the private key file */ + fp = fopen(certfile, "r"); + if (fp == NULL) { + Log_warn("Unable to open the X509 file %s for reading.", certfile); + return NULL; + } + + /* allocate memory for the cert structure */ + x509 = X509_new(); + + if (PEM_read_X509(fp, &x509, NULL, NULL) == 0) { + /* error reading the x509 information - check the error stack */ + Log_warn("Error trying to read X509 info."); + fclose(fp); + X509_free(x509); + return NULL; + } + fclose(fp); + return x509; +} + +static RSA *SSL_readprivatekey(char *keyfile) +{ + FILE *fp; + RSA *rsa; + +/* open the private key file for reading */ + fp = fopen(keyfile, "r"); + if (fp == NULL) { + Log_warn("Unable to open the private key file %s for reading.", keyfile); + return NULL; + } + +/* allocate memory for the RSA structure */ + rsa = RSA_new(); + + /* assign a callback function for the password */ + + /* read a private key from file */ + if (PEM_read_RSAPrivateKey(fp, &rsa, NULL, NULL) <= 0) { + /* error reading the key - check the error stack */ + Log_warn("Error trying to read private key."); + RSA_free(rsa); + fclose(fp); + return NULL; + } + fclose(fp); + return rsa; +} + +void SSL_writecert(char *certfile, X509 *x509) +{ + FILE *fp; + BIO *err_output; + + /* prepare a BIO for outputting error messages */ + + err_output = BIO_new_fp(stderr,BIO_NOCLOSE); + + /* open the private key file */ + fp = fopen(certfile, "w"); + if (fp == NULL) { + BIO_printf(err_output, "Unable to open the X509 file for writing.\n"); + BIO_free(err_output); + return; + } + + if (PEM_write_X509(fp, x509) == 0) { + BIO_printf(err_output, "Error trying to write X509 info.\n"); + ERR_print_errors(err_output); + } + fclose(fp); +} + +void SSL_writekey(char *keyfile, RSA *rsa) +{ + FILE *fp; + BIO *err_output; + /* prepare a BIO for outputing error messages */ + err_output = BIO_new_fp(stderr, BIO_NOCLOSE); + + /* open the private key file for reading */ + fp = fopen(keyfile, "w"); + if (fp == NULL) { + BIO_printf(err_output, "Unable to open the private key file %s for writing.\n", keyfile); + BIO_free(err_output); + return; + } + + if (PEM_write_RSAPrivateKey(fp, rsa, NULL, NULL, 0, NULL, NULL) == 0) { + /* error reading the key - check the error stack */ + BIO_printf(err_output, "Error trying to write private key\n"); + ERR_print_errors(err_output); + } + fclose(fp); +} + +void SSL_initializeCert() { + char *crt, *key, *pass; + + crt = (char *)getStrConf(CERTIFICATE); + key = (char *)getStrConf(KEY); + pass = (char *)getStrConf(PASSPHRASE); + + x509 = SSL_readcert(crt); + rsa = SSL_readprivatekey(key); + if (rsa != NULL) { + pkey = EVP_PKEY_new(); + EVP_PKEY_assign_RSA(pkey, rsa); + } + +#if 0 + /* Later ... */ + if (key && !x509) { + qscCert = QSslCertificate(key); + if (! qscCert.isNull()) { + logthis("Using certificate from key."); + } + } + + if (! qscCert.isNull()) { + QSsl::KeyAlgorithm alg = qscCert.publicKey().algorithm(); + /* Fetch algorith from cert */ + if (! key.isEmpty()) { + /* get key */ + qskKey = QSslKey(key, alg, QSsl::Pem, QSsl::PrivateKey, pass); + if (qskKey.isNull()) { + logthis("Failed to parse key."); + } + } + + if (! crt.isEmpty() && qskKey.isNull()) { + /* get key from certificate */ + qskKey = QSslKey(crt, alg, QSsl::Pem, QSsl::PrivateKey, pass); + if (! qskKey.isNull()) { + logthis("Using key from certificate."); + } + } + + } +#endif + + if (!rsa || !x509) { + logthis("Generating new server certificate."); + + BIO *bio_err; + + CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); + + bio_err=BIO_new_fp(stderr, BIO_NOCLOSE); + + x509 = X509_new(); + pkey = EVP_PKEY_new(); + rsa = RSA_generate_key(1024,RSA_F4,NULL,NULL); + EVP_PKEY_assign_RSA(pkey, rsa); + + X509_set_version(x509, 2); + ASN1_INTEGER_set(X509_get_serialNumber(x509),1); + X509_gmtime_adj(X509_get_notBefore(x509),0); + X509_gmtime_adj(X509_get_notAfter(x509),60*60*24*365); + X509_set_pubkey(x509, pkey); + + X509_NAME *name=X509_get_subject_name(x509); + + X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (const uint8_t *)"Murmur Autogenerated Certificate v2", -1, -1, 0); + X509_set_issuer_name(x509, name); + SSL_add_ext(x509, NID_basic_constraints, "critical,CA:FALSE"); + SSL_add_ext(x509, NID_ext_key_usage, "serverAuth,clientAuth"); + SSL_add_ext(x509, NID_subject_key_identifier, "hash"); + SSL_add_ext(x509, NID_netscape_comment, "Generated from umurmur"); + + X509_sign(x509, pkey, EVP_md5()); + + SSL_writecert(crt, x509); + SSL_writekey(key, rsa); + } + +} + +void SSL_getdigest(char *s, int l) +{ + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int n; + int j; + + if (!X509_digest (x509, EVP_md5(), md, &n)) + { + snprintf (s, l, "[unable to calculate]"); + } + else + { + for (j = 0; j < (int) n; j++) + { + char ch[8]; + snprintf(ch, 8, "%02X%s", md[j], (j % 2 ? " " : "")); + strcat(s, ch); + } + } +} + +void SSL_init(void) +{ + SSL_METHOD *method; + SSL *ssl; + int i, offset = 0; + STACK_OF(SSL_CIPHER) *cipherlist = NULL, *cipherlist_new = NULL; + SSL_CIPHER *cipher; + char cipherstring[1024]; + + SSL_library_init(); + OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */ + SSL_load_error_strings(); /* load all error messages */ + ERR_load_crypto_strings(); /* load all error messages */ + method = SSLv23_server_method(); /* create new server-method instance */ + context = SSL_CTX_new(method); /* create new context from method */ + if (context == NULL) + { + ERR_print_errors_fp(stderr); + abort(); + } + SSL_initializeCert(); + if (SSL_CTX_use_certificate(context, x509) <= 0) + Log_fatal("Failed to initialize cert"); + if (SSL_CTX_use_PrivateKey(context, pkey) <= 0) { + ERR_print_errors_fp(stderr); + Log_fatal("Failed to initialize private key"); + } + + /* Set cipher list */ + ssl = SSL_new(context); + cipherlist = (STACK_OF(SSL_CIPHER) *) SSL_get_ciphers(ssl); + cipherlist_new = (STACK_OF(SSL_CIPHER) *) sk_SSL_CIPHER_new_null(); + + for ( i = 0; (cipher = sk_SSL_CIPHER_value(cipherlist, i)) != NULL; i++) { + if (SSL_CIPHER_get_bits(cipher, NULL) >= 128) { + sk_SSL_CIPHER_push(cipherlist_new, cipher); + } + } + Log_info("List of ciphers:"); + if (cipherlist_new) { + for ( i = 0; (cipher = sk_SSL_CIPHER_value(cipherlist_new, i)) != NULL; i++) { + Log_info("%s", SSL_CIPHER_get_name(cipher)); + offset += snprintf(cipherstring + offset, 1024 - offset, "%s:", SSL_CIPHER_get_name(cipher)); + } + cipherstring[offset - 1] = '\0'; + } + + if (cipherlist_new) + sk_SSL_CIPHER_free(cipherlist_new); + + if (strlen(cipherstring) == 0) + Log_fatal("No suitable ciphers found!"); + + if (SSL_CTX_set_cipher_list(context, cipherstring) == 0) + Log_fatal("Failed to set cipher list!"); + + + SSL_free(ssl); +} + +void SSL_deinit(void) +{ + SSL_CTX_free(context); + EVP_cleanup(); +} + +int SSL_nonblockaccept(SSL *ssl, bool_t *SSLready) +{ + int rc; + rc = SSL_accept(ssl); + if (rc < 0) { + if (SSL_get_error(ssl, rc) == SSL_ERROR_WANT_READ || + SSL_get_error(ssl, rc) == SSL_ERROR_WANT_WRITE) { + Log_debug("SSL not ready"); + return 0; + } else { + Log_warn("SSL error: %s", ERR_error_string(SSL_get_error(ssl, rc), NULL)); + return -1; + } + } + *SSLready = true; + return 0; +} + +SSL *SSL_newconnection(int fd, bool_t *SSLready) +{ + SSL *ssl; + + *SSLready = false; + ssl = SSL_new(context); + SSL_set_fd(ssl, fd); + if (SSL_nonblockaccept(ssl, SSLready) < 0) { + SSL_free(ssl); + return NULL; + } + return ssl; +} + +void SSL_closeconnection(SSL *ssl) +{ + SSL_free(ssl); +} + + diff --git a/src/ssl.h b/src/ssl.h new file mode 100644 index 0000000..6c2a8ba --- /dev/null +++ b/src/ssl.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include +#include "types.h" + +void SSL_init(void); +void SSL_deinit(void); +SSL *SSL_newconnection(int fd, bool_t *SSLready); +void SSL_closeconnection(SSL *ssl); +int SSL_nonblockaccept(SSL *ssl, bool_t *SSLready); diff --git a/src/timer.c b/src/timer.c new file mode 100644 index 0000000..53542c1 --- /dev/null +++ b/src/timer.c @@ -0,0 +1,75 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include +#include + +#include "timer.h" + +static uint64_t Timer_now() +{ + struct timeval tv; + uint64_t e; + + gettimeofday(&tv, NULL); + e = tv.tv_sec * 1000000LL; + e += tv.tv_usec; + return e; +} + + +void Timer_init(etimer_t *t) +{ + *t = Timer_now(); +} + +bool_t Timer_isElapsed(etimer_t *t, uint64_t us) +{ + if (Timer_elapsed(t) > us) { + *t += us; + return true; + } + return false; + +} + +uint64_t Timer_elapsed(etimer_t *t) +{ + return Timer_now() - *t; +} + +uint64_t Timer_restart(etimer_t *t) +{ + uint64_t n = Timer_now(); + uint64_t e = n - *t; + *t = n; + return e; +} diff --git a/src/timer.h b/src/timer.h new file mode 100644 index 0000000..bb7f9bc --- /dev/null +++ b/src/timer.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2009, Martin Johansson + Copyright (C) 2005-2009, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Developers nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef TIMER_H_2766562 +#define TIMER_H_2766562 + +#include +#include "types.h" + +typedef uint64_t etimer_t; + +void Timer_init(etimer_t *t); +bool_t Timer_isElapsed(etimer_t *t, uint64_t us); +uint64_t Timer_elapsed(etimer_t *t); +uint64_t Timer_restart(etimer_t *t); + +#endif + diff --git a/src/types.h b/src/types.h new file mode 100644 index 0000000..cd45146 --- /dev/null +++ b/src/types.h @@ -0,0 +1,10 @@ +#ifndef TYPES_H_90878954 +#define TYPES_H_90878954 + +typedef enum { + false, + true +} bool_t; + +#endif +