*/
#include <stdlib.h>
+#include <time.h>
#include "log.h"
#include "list.h"
#include "ban.h"
declare_list(banlist);
static int bancount; /* = 0 */
+static int ban_duration;
+void Ban_init(void)
+{
+ ban_duration = getIntConf(BAN_LENGTH);
+ /* Read ban file here */
+}
+
+void Ban_deinit(void)
+{
+ /* Save banlist */
+}
void Ban_UserBan(client_t *client, char *reason)
{
ban_t *ban;
char hexhash[41];
ban = malloc(sizeof(ban_t));
+ if (ban == NULL)
+ Log_fatal("Out of memory");
+ memset(ban, 0, sizeof(ban_t));
+
memcpy(ban->hash, client->hash, 20);
memcpy(&ban->address, &client->remote_tcp.sin_addr, sizeof(in_addr_t));
+ ban->mask = 128;
ban->reason = strdup(reason);
ban->name = strdup(client->username);
+ ban->time = time(NULL);
+ ban->duration = ban_duration;
Timer_init(&ban->startTime);
list_add_tail(&ban->node, &banlist);
+ bancount++;
SSLi_hash2hex(ban->hash, hexhash);
Log_info_client(client, "User kickbanned. Reason: '%s' Hash: %s IP: %s Banned for: %d seconds",
ban->name, ban->reason, hexhash, inet_ntoa(*((struct in_addr *)&ban->address)),
- getIntConf(BAN_LENGTH));
+ ban->duration);
}
void Ban_pruneBanned()
{
struct dlist *itr;
- static int64_t bantime = 0;
ban_t *ban;
char hexhash[41];
-
- if (bantime == 0) {
- bantime = getIntConf(BAN_LENGTH) * 1000000LL;
- }
-
+ uint64_t bantime_long;
+
list_iterate(itr, &banlist) {
ban = list_get_entry(itr, ban_t, node);
+ bantime_long = ban->duration * 1000000LL;
#ifdef DEBUG
SSLi_hash2hex(ban->hash, hexhash);
Log_debug("BL: User %s Reason: '%s' Hash: %s IP: %s Time left: %d",
ban->name, ban->reason, hexhash, inet_ntoa(*((struct in_addr *)&ban->address)),
- bantime / 1000000LL - Timer_elapsed(&ban->startTime) / 1000000LL);
+ bantime_long / 1000000LL - Timer_elapsed(&ban->startTime) / 1000000LL);
#endif
- if (Timer_isElapsed(&ban->startTime, bantime)) {
+ /* Duration of 0 = forever */
+ if (ban->duration != 0 && Timer_isElapsed(&ban->startTime, bantime_long)) {
free(ban->name);
free(ban->reason);
list_del(&ban->node);
free(ban);
+ bancount--;
}
}
}
{
struct dlist *itr;
ban_t *ban;
+ int mask;
+ in_addr_t tempaddr1, tempaddr2;
+
list_iterate(itr, &banlist) {
ban = list_get_entry(itr, ban_t, node);
- if (memcmp(&ban->address, addr, sizeof(in_addr_t)) == 0)
+ mask = ban->mask - 96;
+ if (mask < 32) { /* XXX - only ipv4 support */
+ memcpy(&tempaddr1, addr, sizeof(in_addr_t));
+ memcpy(&tempaddr2, &ban->address, sizeof(in_addr_t));
+ tempaddr1 &= (2 ^ mask) - 1;
+ tempaddr2 &= (2 ^ mask) - 1;
+ }
+ if (memcmp(&tempaddr1, &tempaddr2, sizeof(in_addr_t)) == 0)
return true;
}
return false;
}
+int Ban_getBanCount(void)
+{
+ return bancount;
+}
+
+message_t *Ban_getBanList(void)
+{
+ int i = 0;
+ struct dlist *itr;
+ ban_t *ban;
+ message_t *msg;
+ struct tm timespec;
+ char timestr[32];
+ char hexhash[41];
+ uint8_t address[16];
+
+ msg = Msg_banList_create(bancount);
+ list_iterate(itr, &banlist) {
+ ban = list_get_entry(itr, ban_t, node);
+ gmtime_r(&ban->time, ×pec);
+ strftime(timestr, 32, "%Y-%m-%dT%H:%M:%S", ×pec);
+ SSLi_hash2hex(ban->hash, hexhash);
+ /* ipv4 representation as ipv6 address. */
+ memset(address, 0, 16);
+ memcpy(&address[12], &ban->address, 4);
+ memset(&address[10], 0xff, 2); /* IPv4 */
+ Msg_banList_addEntry(msg, i++, address, ban->mask, ban->name,
+ hexhash, ban->reason, timestr, ban->duration);
+ }
+ return msg;
+}
+
+void Ban_clearBanList()
+{
+ ban_t *ban;
+ struct dlist *itr, *save;
+ list_iterate_safe(itr, save, &banlist) {
+ ban = list_get_entry(itr, ban_t, node);
+ free(ban->name);
+ free(ban->reason);
+ list_del(&ban->node);
+ free(ban);
+ bancount--;
+ }
+}
+
+void Ban_putBanList(message_t *msg, int n_bans)
+{
+ int i = 0;
+ struct tm timespec;
+ ban_t *ban;
+ char *hexhash, *name, *reason, *start;
+ uint32_t duration, mask;
+ uint8_t *address;
+
+ for (i = 0; i < n_bans; i++) {
+ Msg_banList_getEntry(msg, i, &address, &mask, &name, &hexhash, &reason, &start, &duration);
+ ban = malloc(sizeof(ban_t));
+ if (ban == NULL)
+ Log_fatal("Out of memory");
+ memset(ban, 0, sizeof(ban_t));
+ SSLi_hex2hash(hexhash, ban->hash);
+ memcpy(&ban->address, &address[12], 4);
+ ban->mask = mask;
+ ban->reason = strdup(reason);
+ ban->name = strdup(name);
+ strptime(start, "%Y-%m-%dT%H:%M:%S", ×pec);
+ ban->time = mktime(×pec);
+ Timer_init(&ban->startTime);
+ ban->duration = duration;
+ list_add_tail(&ban->node, &banlist);
+ bancount++;
+ }
+}
typedef struct {
uint8_t hash[20];
in_addr_t address;
+ uint32_t mask;
char *reason;
char *name;
+ time_t time;
+ uint32_t duration;
etimer_t startTime;
struct dlist node;
} ban_t;
void Ban_pruneBanned();
bool_t Ban_isBanned(client_t *client);
bool_t Ban_isBannedAddr(in_addr_t *addr);
+int Ban_getBanCount(void);
+message_t *Ban_getBanList(void);
+void Ban_putBanList(message_t *msg, int n_bans);
+void Ban_init(void);
+void Ban_deinit(void);
#endif
#include "channel.h"
#include "conf.h"
#include "voicetarget.h"
+#include "ban.h"
#define MAX_TEXT 512
#define MAX_USERNAME 128
if (!getBoolConf(ALLOW_TEXTMESSAGE))
msg->payload.permissionQuery->permissions &= ~PERM_TEXTMESSAGE;
+ if (!getBoolConf(ENABLE_BAN))
+ msg->payload.permissionQuery->permissions &= ~PERM_BAN;
Client_send_message(client, msg);
break;
memset(sendmsg->payload.userStats->address.data, 0, 16);
/* ipv4 representation as ipv6 address. Supposedly correct. */
memcpy(&sendmsg->payload.userStats->address.data[12], &target->remote_tcp.sin_addr, 4);
+ memset(&sendmsg->payload.userStats->address.data[10], 0xff, 2); /* IPv4 */
sendmsg->payload.userStats->address.len = 16;
}
/* BW */
msg->payload.userRemove->actor = client->sessionId;
if (msg->payload.userRemove->has_ban && msg->payload.userRemove->ban) {
- Ban_UserBan(target, msg->payload.userRemove->reason);
+ if (!getBoolConf(ENABLE_BAN))
+ sendPermissionDenied(client, "Permission denied");
+ else
+ Ban_UserBan(target, msg->payload.userRemove->reason);
} else {
Log_info_client(target, "User kicked. Reason: '%s'",
strlen(msg->payload.userRemove->reason) == 0 ? "N/A" : msg->payload.userRemove->reason);
Client_send_message_except(NULL, msg);
Client_close(target);
break;
+ case BanList:
+ /* Only admin can issue this */
+ if (!client->isAdmin) {
+ sendPermissionDenied(client, "Permission denied");
+ break;
+ }
+ if (!getBoolConf(ENABLE_BAN)) {
+ sendPermissionDenied(client, "Permission denied");
+ break;
+ }
+ if (msg->payload.banList->has_query && msg->payload.banList->query) {
+ /* Create banlist message and add banentrys */
+ sendmsg = Ban_getBanList();
+ Client_send_message(client, sendmsg);
+ } else {
+ /* Clear banlist and set the new one */
+ Ban_clearBanList();
+ Ban_putBanList(msg, msg->payload.banList->n_bans);
+ }
+ break;
/* Permission denied for all these messages. Not implemented. */
case ChannelRemove:
case ContextAction:
case ContextActionAdd:
case ACL:
- case BanList:
case UserList:
case QueryUsers:
sendPermissionDenied(client, "Not supported by uMurmur");
mumble_proto__server_config__pack(msg->payload.serverConfig, bufptr);
break;
+ case BanList:
+ len = mumble_proto__ban_list__get_packed_size(msg->payload.banList);
+ if (len > MAX_MSGSIZE) {
+ Log_warn("Too big tx message. Discarding");
+ break;
+ }
+ Msg_addPreamble(buffer, msg->messageType, len);
+ Log_debug("Msg_MessageToNetwork: BanList size %d", len);
+ mumble_proto__ban_list__pack(msg->payload.banList, bufptr);
+ break;
default:
Log_warn("Msg_MessageToNetwork: Unsupported message %d", msg->messageType);
return 0;
message_t *Msg_create(messageType_t messageType)
{
message_t *msg = Msg_create_nopayload(messageType);
+ int i;
switch (messageType) {
case Version:
return msg;
}
+message_t *Msg_banList_create(int n_bans)
+{
+ message_t *msg = Msg_create_nopayload(BanList);
+ int i;
+
+ msg->payload.banList = malloc(sizeof(MumbleProto__BanList));
+ if (msg->payload.banList == NULL)
+ Log_fatal("Out of memory");
+ memset(msg->payload.banList, 0, sizeof(MumbleProto__BanList));
+ mumble_proto__ban_list__init(msg->payload.banList);
+ msg->payload.banList->n_bans = n_bans;
+ msg->payload.banList->bans = malloc(sizeof(MumbleProto__BanList__BanEntry *) * n_bans);
+ if (msg->payload.banList->bans == NULL)
+ Log_fatal("Out of memory");
+ for (i = 0; i < n_bans; i++) {
+ msg->payload.banList->bans[i] = malloc(sizeof(MumbleProto__BanList__BanEntry));
+ if (msg->payload.banList->bans[i] == NULL)
+ Log_fatal("Out of memory");
+ memset(msg->payload.banList->bans[i], 0, sizeof(MumbleProto__BanList__BanEntry));
+ mumble_proto__ban_list__ban_entry__init(msg->payload.banList->bans[i]);
+ }
+ return msg;
+}
+
+void Msg_banList_addEntry(message_t *msg, int index, uint8_t *address, uint32_t mask,
+ char *name, char *hash, char *reason, char *start, uint32_t duration)
+{
+ MumbleProto__BanList__BanEntry *entry = msg->payload.banList->bans[index];
+
+ entry->address.data = malloc(16);
+ if (!entry->address.data)
+ Log_fatal("Out of memory");
+ memcpy(entry->address.data, address, 16);
+ entry->address.len = 16;
+ entry->mask = mask;
+ entry->name = strdup(name);
+ entry->hash = strdup(hash);
+ entry->reason = strdup(reason);
+ entry->start = strdup(start);
+ if (!entry->name || !entry->hash || !entry->reason || !entry->start)
+ Log_fatal("Out of memory");
+
+ if (duration > 0) {
+ entry->duration = duration;
+ entry->has_duration = true;
+ }
+ Log_debug("Msg_banList_addEntry: %s %s %s %s %s", entry->name, entry->hash, entry->address.data, entry->reason, entry->start);
+}
+
+void Msg_banList_getEntry(message_t *msg, int index, uint8_t **address, uint32_t *mask,
+ char **name, char **hash, char **reason, char **start, uint32_t *duration)
+{
+ MumbleProto__BanList__BanEntry *entry = msg->payload.banList->bans[index];
+
+ *address = entry->address.data;
+ *mask = entry->mask;
+ *name = entry->name;
+ *hash = entry->hash;
+ *reason = entry->reason;
+ *start = entry->start;
+ if (entry->has_duration)
+ *duration = entry->duration;
+ else
+ *duration = 0;
+}
+
+
void Msg_inc_ref(message_t *msg)
{
msg->refcount++;
void Msg_free(message_t *msg)
{
+ int i;
+
if (msg->refcount) msg->refcount--;
if (msg->refcount > 0)
return;
free(msg->payload.serverConfig);
}
break;
+ case BanList:
+ if (msg->unpacked)
+ mumble_proto__ban_list__free_unpacked(msg->payload.banList, NULL);
+ else {
+ for (i = 0; i < msg->payload.banList->n_bans; i++) {
+ free(msg->payload.banList->bans[i]->address.data);
+ free(msg->payload.banList->bans[i]->name);
+ free(msg->payload.banList->bans[i]->hash);
+ free(msg->payload.banList->bans[i]->reason);
+ free(msg->payload.banList->bans[i]->start);
+ free(msg->payload.banList->bans[i]);
+ }
+ free(msg->payload.banList->bans);
+ free(msg->payload.banList);
+ }
+ break;
default:
Log_warn("Msg_free: Unsupported message %d", msg->messageType);
goto err_out;
break;
}
+ case BanList:
+ {
+ msg = Msg_create_nopayload(BanList);
+ msg->unpacked = true;
+ msg->payload.banList = mumble_proto__ban_list__unpack(NULL, msgLen, msgData);
+ if (msg->payload.banList == NULL)
+ goto err_out;
+ break;
+ }
default:
- Log_warn("Unsupported message %d", messageType);
+ Log_warn("Msg_networkToMessage: Unsupported message %d", messageType);
break;
}
return msg;
#define MESSAGES_H_89768
#include <stdint.h>
+#include <arpa/inet.h>
#include "Mumble.pb-c.h"
#include "list.h"
#include "types.h"
struct _MumbleProto__ChannelState *channelState;
struct _MumbleProto__UserRemove *userRemove;
struct _MumbleProto__UserState *userState;
- /* BanEntry not supported */
- /* BanList not supported */
+ struct _MumbleProto__BanList *banList;
struct _MumbleProto__TextMessage *textMessage;
struct _MumbleProto__PermissionDenied *permissionDenied;
/* ChanACL not supported */
message_t *Msg_CreateVoiceMsg(uint8_t *data, int size);
message_t *Msg_create(messageType_t messageType);
+void Msg_banList_addEntry(message_t *msg, int index, uint8_t *address, uint32_t mask,
+ char *name, char *hash, char *reason, char *start, uint32_t duration);
+void Msg_banList_getEntry(message_t *msg, int index, uint8_t **address, uint32_t *mask,
+ char **name, char **hash, char **reason, char **start, uint32_t *duration);
+message_t *Msg_banList_create(int n_bans);
+
#endif