--- /dev/null
+/*
+
+ server_internal.h
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 1997 - 2005 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SERVER_INTERNAL_H
+#define SERVER_INTERNAL_H
+
+#include "server_st_accept.h"
+#include "server_st_connect.h"
+#include "server_st_notify.h"
+#include "server_st_query.h"
+#include "server_st_command.h"
+#include "server_st_command_reply.h"
+#include "server_st_packet.h"
+
+/* SILC port */
+#define SILC_PORT 706
+
+/* Server type */
+typedef enum {
+ SILC_SERVER = 0,
+ SILC_ROUTER = 1,
+ SILC_BACKUP_ROUTER = 2
+} SilcServerType;
+
+/* Forward declarations */
+typedef struct SilcServerEntryStruct *SilcServerEntry;
+typedef struct SilcClientEntryStruct *SilcClientEntry;
+typedef struct SilcChannelEntryStruct *SilcChannelEntry;
+typedef struct SilcServerCommandStruct *SilcServerCommand;
+typedef struct SilcServerThreadStruct *SilcServerThread;
+
+/* Pending command context */
+typedef struct {
+ SilcFSMSemaStruct wait_reply; /* Pending command signaller */
+ SilcServerCommand reply; /* Command reply context */
+ SilcUInt16 cmd_ident; /* Command identifier */
+ SilcInt16 refcnt; /* Reference counter */
+} *SilcServerPending;
+
+/* Command state context. This is used with both commands and command
+ replies. When command or command reply is executed its state is saved
+ here while processing. */
+struct SilcServerCommandStruct {
+ struct SilcServerCommandStruct *next;
+ SilcServerThread thread; /* Server thread */
+ SilcPacket packet; /* Command packet */
+ SilcCommandPayload payload; /* Command payload */
+ SilcServerPending pending; /* Pending command context */
+};
+
+/* Entry data header. Client and server entries has this as their first
+ field. */
+typedef struct {
+ SilcConnectionType type; /* Connection type */
+ SilcSKE ske; /* Key exchange protocol, for rekey */
+ SilcHash hash; /* Hash selected in SKE protocol */
+ SilcPublicKey public_key; /* Public key */
+ unsigned char fingerprint[20]; /* SHA-1 fingerprint */
+
+ long last_receive; /* Time last received data */
+ long last_sent; /* Time last sent data */
+
+ unsigned long created; /* Time when entry was created */
+
+ SilcUInt32 refcnt; /* Reference counter */
+
+ /* Flags */
+ unsigned int registered : 1; /* Set if registered to network */
+ unsigned int local : 1; /* Set if locally connected entry */
+ unsigned int resolving : 1; /* Set if entry data being resolved */
+ unsigned int resolved : 1; /* Set if entry data resolved */
+ unsigned int disabled : 1; /* Set if entry is disabled */
+ unsigned int resumed : 1; /* Set if entry resumed */
+ unsigned int resume_res : 1; /* Set if resolved while resuming */
+ unsigned int noattr : 1; /* Set if entry does not support
+ user attributes in WHOIS */
+} *SilcEntryData, SilcEntryDataStruct;
+
+/* Server entry */
+struct SilcServerEntryStruct {
+ SilcEntryDataStruct data; /* Entry data header */
+ SilcServerID id; /* Server ID */
+ char *server_name; /* Server name */
+ char *server_info; /* Server info */
+ char *motd; /* Message of the day */
+ SilcPacketStream stream; /* Connection to entry/origin of entry */
+ SilcUInt8 server_type; /* Server type */
+};
+
+/* Client's joined channel entry */
+typedef struct SilcChannelClientEntryStruct {
+ SilcClientEntry client; /* Client on channel */
+ SilcChannelEntry channel; /* Joined channel */
+ SilcUInt32 mode; /* Client's mode on channel */
+} *SilcChannelClientEntry;
+
+/* Client entry */
+struct SilcClientEntryStruct {
+ SilcEntryDataStruct data; /* Entry data header */
+ SilcClientID id; /* Client ID */
+ unsigned char *nickname; /* Client's nickname (not normalized) */
+ char *servername; /* Client's server's name */
+ char *username; /* Client's username */
+ char *userinfo; /* Client's user info */
+ SilcUInt32 mode; /* Client's mode in the network */
+ unsigned char *attrs; /* User attributes */
+ SilcUInt16 attrs_len; /* Attributes data length */
+ SilcHashTable channels; /* Joined channels */
+ SilcPacketStream stream; /* Connection to entry/origin of entry */
+
+ long last_command;
+ SilcUInt8 fast_command;
+ unsigned long updated;
+
+ /* data.status is RESOLVING and this includes the resolving command
+ reply identifier. */
+ SilcUInt16 resolve_cmd_ident;
+
+ /* we need this so nobody can resume more than once at the same time -
+ * server crashes, really odd behaviour, ... */
+ SilcClientEntry resuming_client;
+};
+
+/* Channel entry */
+struct SilcChannelEntryStruct {
+ SilcChannelID id; /* Channel ID */
+ char *channel_name; /* Channel name */
+ SilcUInt32 mode; /* Channel's mode */
+ SilcPacketStream router; /* Channel's owner */
+
+ unsigned char *passphrase; /* Channel's passphrase */
+ SilcHashTable channel_pubkeys; /* Channel authentication public keys */
+ SilcPublicKey founder_key; /* Channel founder's public key */
+
+ char *topic; /* Current topic */
+ char *cipher; /* User set cipher */
+ char *hmac_name; /* User set HMAC */
+ SilcUInt32 user_limit; /* Maximum user limit */
+ SilcHashTable invite_list; /* Invited list */
+ SilcHashTable ban_list; /* Ban list */
+ SilcHashTable user_list; /* Joined users */
+
+ SilcCipher channel_key; /* Current channel key */
+ unsigned char *key; /* Current channel key data */
+ SilcUInt32 key_len; /* Channel key data length */
+ SilcHmac hmac; /* Current HMAC */
+ SilcUInt32 refcnt; /* Reference counter */
+
+ // SilcServerChannelRekey rekey;
+ unsigned long created;
+ unsigned long updated;
+
+ /* Flags */
+ unsigned int global_users : 1;
+ unsigned int disabled : 1;
+ unsigned int users_resolved : 1;
+};
+
+/* Internal context for accepting new connection */
+typedef struct SilcServerAcceptStruct {
+ SilcEntryDataStruct data;
+ SilcServerThread thread;
+ SilcFSMThread t; /* Thread for accepting connection */
+ SilcStream stream; /* Remote connection */
+ SilcPacketStream packet_stream; /* Remote connection */
+ SilcConnAuth connauth; /* Connection authentication context */
+ SilcFSMSemaStruct wait_register; /* Signaller when registering received */
+ SilcPacket register_packet; /* NEW_CLIENT/NEW_SERVER packet */
+
+ SilcServerParamClient cconfig;
+ SilcServerParamServer sconfig;
+ SilcServerParamRouter rconfig;
+ SilcSKEStatus status;
+ SilcSKESecurityProperties prop;
+ SilcSKEKeyMaterial keymat;
+ SilcSKERekeyMaterial rekey;
+ SilcAsyncOperation op;
+ const char *hostname;
+ const char *ip;
+ SilcUInt16 port;
+ SilcStatus error;
+ char *error_string;
+ SilcBool auth_success;
+ SilcConnectionType conn_type;
+ SilcHash hash;
+ struct SilcServerAcceptStruct *next;
+} *SilcServerAccept;
+
+/* Server statistics structure. */
+typedef struct {
+ /* Local stats (server and router) */
+ SilcUInt32 my_clients; /* Locally connected clients */
+ SilcUInt32 my_servers; /* Locally connected servers */
+ SilcUInt32 my_routers; /* Locally connected routers */
+ SilcUInt32 my_channels; /* Locally created channels */
+ SilcUInt32 my_chanclients; /* Local clients on local channels */
+ SilcUInt32 my_aways; /* Local clients away (gone) */
+ SilcUInt32 my_detached; /* Local clients detached */
+ SilcUInt32 my_server_ops; /* Local server operators */
+ SilcUInt32 my_router_ops; /* Local router operators */
+
+ /* Global stats (mainly for router) */
+ SilcUInt32 cell_clients; /* All clients in cell */
+ SilcUInt32 cell_servers; /* All servers in cell */
+ SilcUInt32 cell_channels; /* All channels in cell */
+ SilcUInt32 cell_chanclients; /* All clients on cell's channels */
+ SilcUInt32 clients; /* All clients */
+ SilcUInt32 servers; /* All servers */
+ SilcUInt32 routers; /* All routers */
+ SilcUInt32 channels; /* All channels */
+ SilcUInt32 chanclients; /* All clients on channels */
+ SilcUInt32 aways; /* All clients away (gone) */
+ SilcUInt32 detached; /* All clients detached */
+ SilcUInt32 server_ops; /* All server operators */
+ SilcUInt32 router_ops; /* All router operators */
+ /* More to add
+ SilcUInt32 secret_channels;
+ SilcUInt32 private_channels;
+ */
+
+ /* General */
+ SilcUInt32 conn_attempts; /* Connection attempts */
+ SilcUInt32 conn_failures; /* Connection failure */
+ SilcUInt32 auth_attempts; /* Authentication attempts */
+ SilcUInt32 auth_failures; /* Authentication failures */
+ SilcUInt32 packets_sent; /* Sent SILC packets */
+ SilcUInt32 packets_received; /* Received SILC packets */
+ SilcUInt32 conn_num; /* Number of connections */
+ SilcUInt32 commands_sent; /* Commands/replies sent */
+ SilcUInt32 commands_received; /* Commands/replies received */
+} SilcServerStatistics;
+
+/* Server thread context */
+struct SilcServerThreadStruct {
+ struct SilcServerThreadStruct *next;
+ SilcServer server; /* Pointer to server */
+ SilcStack stack; /* Data stack for fast allocations */
+ SilcPacketEngine packet_engine; /* Packet engine */
+ SilcFSMThreadStruct thread; /* FSM thread */
+ SilcFSMStruct fsm; /* Thread's FSM */
+ SilcFSMSemaStruct wait_event; /* Thread's event signaller */
+ SilcUInt32 num_conns; /* Number of connections in the thread */
+ SilcList new_conns; /* New network connections */
+ SilcList packet_queue; /* Incoming packet queue */
+
+ /* Events */
+ unsigned int new_connection : 1; /* New connection received */
+ unsigned int new_packet : 1; /* New packet in packet queue */
+};
+
+/* Server context. */
+struct SilcServerStruct {
+ char *server_name; /* Server name */
+ SilcServerEntry server_entry; /* Server entry */
+ SilcServerID id; /* Server ID */
+ SilcUInt32 starttime;
+
+ SilcFSMStruct fsm; /* Server FSM */
+ SilcSchedule schedule; /* Scheduler */
+ SilcMutex lock; /* Server lock */
+ SilcRng rng; /* Random number generator */
+ SilcServerParams params; /* Server parameters */
+ SilcDList listeners; /* Network listeners */
+ SilcList threads; /* Server worker threads */
+ SilcList new_conns; /* New network connections */
+ SilcList command_pool; /* Command context freelist */
+ SilcHashTable pending_commands; /* Pending commands */
+
+ SilcFSMSemaStruct wait_event; /* Main state signaller */
+ SilcFSMSemaStruct thread_up; /* Signaller when thread is up */
+
+ SilcIDCache clients; /* Client entry cache */
+ SilcIDCache servers; /* Server entry cache */
+ SilcIDCache channels; /* Channel entry cache */
+
+ SilcSKR repository; /* Public key/certificate repository */
+ SilcHashTable watcher_list; /* Watcher list, nickname */
+ SilcHashTable watcher_list_pk; /* Watcher list, public keys */
+
+ void *app_context; /* Application specific context */
+
+ char *config_file;
+
+ /* Events */
+ unsigned int new_connection : 1; /* New connection received */
+ unsigned int connect_router : 1; /* Connect to configured routers */
+ unsigned int get_statistics : 1; /* Get statistics */
+ unsigned int reconfigure : 1; /* Reconfigure server */
+ unsigned int server_shutdown : 1; /* Shutdown server */
+ unsigned int run_callback : 1; /* Call running callback */
+
+ /* Flags */
+ unsigned int server_type : 2; /* Server type (server.h) */
+ unsigned int standalone : 1; /* Set if server is standalone, and
+ does not have connection to network. */
+ unsigned int listenning : 1; /* Set if server is listenning for
+ incoming connections. */
+ unsigned int background : 1; /* Set when server is on background */
+ unsigned int backup_router : 1; /* Set if this is backup router */
+ unsigned int backup_primary : 1; /* Set if we've switched our primary
+ router to a backup router. */
+ unsigned int backup_noswitch: 1; /* Set if we've won't switch to
+ become primary (we are backup) */
+ unsigned int backup_closed : 1; /* Set if backup closed connection.
+ Do not allow resuming in this case. */
+ unsigned int wait_backup : 1; /* Set if we are waiting for backup
+ router to connect to us. */
+ unsigned int no_reconnect : 1; /* If set, server won't reconnect to
+ router after disconnection. */
+
+ SilcPacketStream router; /* Pointer to the primary router */
+
+ /* Current command identifier, 0 not used */
+ SilcUInt16 cmd_ident;
+
+ /* Server public key */
+ SilcPKCS pkcs;
+ SilcPublicKey public_key;
+ SilcPrivateKey private_key;
+
+ /* Hash objects for general hashing */
+ SilcHash md5hash;
+ SilcHash sha1hash;
+
+ /* Server statistics */
+ SilcServerStatistics stat;
+
+#ifdef SILC_SIM
+ /* SIM (SILC Module) list */
+ SilcDList sim;
+#endif
+
+ /* Application callbacks */
+ SilcServerRunning running; /* Called to indicate server is up */
+ SilcServerStop stopped; /* Called to indicate server is down */
+ void *running_context;
+ void *stop_context;
+};
+
+/* Rekey must be performed at the lastest when this many packets is sent */
+#define SILC_SERVER_REKEY_THRESHOLD 0xfffffe00
+
+/* Macros */
+
+/* Return pointer to the primary router connection */
+#define SILC_PRIMARY_ROUTE(server) server->router
+
+/* Return TRUE if a packet must be broadcasted (router broadcasts) */
+#define SILC_BROADCAST(server) (server->server_type == SILC_ROUTER)
+
+/* Return TRUE if entry is locally connected or local to us */
+#define SILC_IS_LOCAL(entry) \
+ (((SilcIDListData)entry)->status & SILC_IDLIST_STATUS_LOCAL)
+
+/* Registers generic task for file descriptor for reading from network and
+ writing to network. As being generic task the actual task is allocated
+ only once and after that the same task applies to all registered fd's. */
+#define SILC_REGISTER_CONNECTION_FOR_IO(fd) \
+do { \
+ silc_schedule_task_add(server->schedule, (fd), \
+ silc_server_packet_process, \
+ context, 0, 0, \
+ SILC_TASK_GENERIC, \
+ SILC_TASK_PRI_NORMAL); \
+} while(0)
+
+#define SILC_SET_CONNECTION_FOR_INPUT(s, fd) \
+do { \
+ silc_schedule_set_listen_fd((s), (fd), SILC_TASK_READ, FALSE); \
+} while(0)
+
+#define SILC_SET_CONNECTION_FOR_OUTPUT(s, fd) \
+do { \
+ silc_schedule_set_listen_fd((s), (fd), (SILC_TASK_READ | SILC_TASK_WRITE), \
+ FALSE); \
+} while(0)
+
+#define SILC_OPER_STATS_UPDATE(c, type, mod) \
+do { \
+ if ((c)->mode & (mod)) { \
+ if (SILC_IS_LOCAL((c))) \
+ server->stat.my_ ## type ## _ops--; \
+ if (server->server_type == SILC_ROUTER) \
+ server->stat. type ## _ops--; \
+ (c)->mode &= ~(mod); \
+ } \
+} while(0)
+
+#define SILC_UMODE_STATS_UPDATE(oper, mod) \
+do { \
+ if (client->mode & (mod)) { \
+ if (!(mode & (mod))) { \
+ if (SILC_IS_LOCAL(client)) \
+ server->stat.my_ ## oper ## _ops--; \
+ if (server->server_type == SILC_ROUTER) \
+ server->stat. oper ## _ops--; \
+ } \
+ } else { \
+ if (mode & (mod)) { \
+ if (SILC_IS_LOCAL(client)) \
+ server->stat.my_ ## oper ## _ops++; \
+ if (server->server_type == SILC_ROUTER) \
+ server->stat. oper ## _ops++; \
+ } \
+ } \
+} while(0)
+
+#define SILC_GET_SKE_FLAGS(x, p) \
+ if ((x)) { \
+ if ((x)->param && (x)->param->key_exchange_pfs) \
+ (p) |= SILC_SKE_SP_FLAG_PFS; \
+ if (!(x)->publickeys) \
+ (p) |= SILC_SKE_SP_FLAG_MUTUAL; \
+ }
+
+#define SILC_CONNTYPE_STRING(ctype) \
+ (ctype == SILC_CONN_CLIENT ? "Client" : \
+ ctype == SILC_CONN_SERVER ? "Server" : "Router")
+
+/* This macro is used to send notify messages with formatted string. The
+ string is formatted with arguments and the formatted string is sent as
+ argument. */
+#define SILC_SERVER_SEND_NOTIFY(server, stream, type, fmt) \
+do { \
+ char *__fmt__ = silc_format fmt; \
+ if (__fmt__) \
+ silc_server_send_notify(server, stream, FALSE, \
+ type, 1, __fmt__, strlen(__fmt__)); \
+ silc_free(__fmt__); \
+} while(0)
+
+/* Send notify to operators */
+#define SILC_SERVER_SEND_OPERS(server, route, local, type, fmt) \
+do { \
+ char *__fmt__ = silc_format fmt; \
+ silc_server_send_opers_notify(server, route, local, \
+ type, 1, __fmt__, strlen(__fmt__)); \
+ silc_free(__fmt__); \
+} while(0)
+
+/* Connection retry timeout. We implement exponential backoff algorithm
+ in connection retry. The interval of timeout grows when retry count
+ grows. */
+#define SILC_SERVER_RETRY_COUNT 7 /* Max retry count */
+#define SILC_SERVER_RETRY_MULTIPLIER 2 /* Interval growth */
+#define SILC_SERVER_RETRY_RANDOMIZER 2 /* timeout += rnd % 2 */
+#define SILC_SERVER_RETRY_INTERVAL_MIN 10 /* Min retry timeout */
+#define SILC_SERVER_RETRY_INTERVAL_MAX 600 /* Max generated timeout */
+
+#define SILC_SERVER_KEEPALIVE 300 /* Heartbeat interval */
+#define SILC_SERVER_REKEY 3600 /* Session rekey interval */
+#define SILC_SERVER_MAX_CONNECTIONS 1000 /* Max connections */
+#define SILC_SERVER_MAX_CONNECTIONS_SINGLE 1000 /* Max connections per host */
+#define SILC_SERVER_LOG_FLUSH_DELAY 300 /* Default log flush delay */
+
+/* Macros */
+
+/* Check whether rekey protocol is active */
+#define SILC_SERVER_IS_REKEY(sock) \
+ (sock->protocol && sock->protocol->protocol && \
+ sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)
+
+/* Check whether backup resuming protocol is active */
+#define SILC_SERVER_IS_BACKUP(sock) \
+ (sock->protocol && sock->protocol->protocol && \
+ sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP)
+
+/* Output a message to stderr or to the appropriate log facility wether
+ we are in the background or not. */
+#define SILC_SERVER_LOG_INFO(fmt) \
+ silc_server_stderr(SILC_LOG_INFO, silc_format fmt)
+#define SILC_SERVER_LOG_WARNING(fmt) \
+ silc_server_stderr(SILC_LOG_WARNING, silc_format fmt)
+#define SILC_SERVER_LOG_ERROR(fmt) \
+ silc_server_stderr(SILC_LOG_ERROR, silc_format fmt)
+#define SILC_SERVER_LOG_FATAL(fmt) \
+ silc_server_stderr(SILC_LOG_WARNING, silc_format fmt)
+
+/* Server's states */
+SILC_FSM_STATE(silc_server_st_run);
+SILC_FSM_STATE(silc_server_st_new_connection);
+SILC_FSM_STATE(silc_server_st_wait_new_thread);
+SILC_FSM_STATE(silc_server_st_stop);
+SILC_FSM_STATE(silc_server_st_reconfigure);
+SILC_FSM_STATE(silc_server_st_get_stats);
+SILC_FSM_STATE(silc_server_st_connect_router);
+
+/* Server's thread's states */
+SILC_FSM_STATE(silc_server_thread_st_start);
+SILC_FSM_STATE(silc_server_thread_st_run);
+
+/* Prototypes */
+void silc_server_watcher_list_destroy(void *key, void *context,
+ void *user_context);
+
+#include "server_entry.h"
+
+#endif /* SERVER_INTERNAL_H */
--- /dev/null
+/*
+
+ server_util.c
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 1997 - 2005 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/* $Id$ */
+
+#include "silc.h"
+#include "silcserver.h"
+#include "server_internal.h"
+
+SilcBool silc_server_check_watcher_list(SilcServer server,
+ SilcClientEntry client,
+ const char *new_nick,
+ SilcNotifyType notify)
+{
+ return TRUE;
+}
+
+/* This function is used to send the notify packets and motd to the
+ incoming client connection. */
+
+void silc_server_send_welcome(SilcServerAccept ac, SilcClientEntry client)
+{
+ SilcServer server = ac->thread->server;
+ SilcPacketStream stream = client->stream;
+
+ SILC_LOG_DEBUG(("Send welcome notifys"));
+
+ /* Send some nice info to the client */
+ SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
+ ("Welcome to the SILC Network %s",
+ client->username));
+ SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
+ ("Your host is %s, running version %s",
+ server->server_name, SILC_DIST_VERSION_STRING));
+
+ if (server->server_type == SILC_ROUTER) {
+ SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
+ ("There are %d clients, %d servers and %d "
+ "routers in SILC Network",
+ server->stat.clients, server->stat.servers,
+ server->stat.routers));
+ } else {
+ if (server->stat.clients && server->stat.servers + 1)
+ SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
+ ("There are %d clients, %d servers and %d "
+ "routers in SILC Network",
+ server->stat.clients, server->stat.servers,
+ (server->standalone ? 0 :
+ !server->stat.routers ? 1 :
+ server->stat.routers)));
+ }
+
+ if (server->stat.cell_clients && server->stat.cell_servers + 1)
+ SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
+ ("There are %d clients on %d servers in our cell",
+ server->stat.cell_clients,
+ server->stat.cell_servers));
+ if (server->server_type == SILC_ROUTER) {
+ SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
+ ("I have %d clients, %d channels, %d servers and "
+ "%d routers",
+ server->stat.my_clients,
+ server->stat.my_channels,
+ server->stat.my_servers,
+ server->stat.my_routers));
+ } else {
+ SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
+ ("I have %d clients and %d channels formed",
+ server->stat.my_clients,
+ server->stat.my_channels));
+ }
+
+ if (server->stat.server_ops || server->stat.router_ops)
+ SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
+ ("There are %d server operators and %d router "
+ "operators online",
+ server->stat.server_ops,
+ server->stat.router_ops));
+ if (server->stat.my_router_ops + server->stat.my_server_ops)
+ SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
+ ("I have %d operators online",
+ server->stat.my_router_ops +
+ server->stat.my_server_ops));
+
+ SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
+ ("Your connection is secured with %s cipher, "
+ "key length %d bits",
+ silc_cipher_get_name(ac->prop->cipher),
+ silc_cipher_get_key_len(ac->prop->cipher)));
+ SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
+ ("Your current nickname is %s",
+ client->nickname));
+
+ /* Send motd */
+ silc_server_send_motd(server, stream);
+}
+
+/* Creates new Client ID. */
+
+SilcBool silc_server_create_client_id(SilcServer server, char *nickname,
+ SilcClientID *new_id)
+{
+ unsigned char hash[16];
+ SilcBool finding = FALSE;
+
+ SILC_LOG_DEBUG(("Creating new Client ID"));
+
+ /* Create hash of the nickname (it's already checked as valid identifier
+ string). */
+ silc_hash_make(server->md5hash, nickname, strlen(nickname), hash);
+
+ /* Create the ID */
+ memcpy(new_id->ip.data, server->id.ip.data, server->id.ip.data_len);
+ new_id->ip.data_len = server->id.ip.data_len;
+ new_id->rnd = silc_rng_get_byte(server->rng);
+ memcpy(new_id->hash, hash, CLIENTID_HASH_LEN);
+
+ /* Assure that the ID does not exist already */
+ while (1) {
+ if (!silc_server_find_client_by_id(server, new_id, FALSE, NULL))
+ break;
+
+ /* The ID exists, start increasing the rnd from 0 until we find a
+ ID that does not exist. If we wrap and it still exists then we
+ will return FALSE and the caller must send some other nickname
+ since this cannot be used anymore. */
+ new_id->rnd++;
+
+ if (finding && new_id->rnd == 0)
+ return FALSE;
+
+ if (!finding) {
+ new_id->rnd = 0;
+ finding = TRUE;
+ }
+ }
+
+ SILC_LOG_DEBUG(("New ID (%s)", silc_id_render(new_id, SILC_ID_CLIENT)));
+
+ return TRUE;
+}
+
+/* Creates a Server ID. */
+
+SilcBool silc_server_create_server_id(SilcServer server,
+ const char *ip, SilcUInt16 port,
+ SilcServerID *new_id)
+{
+ SILC_LOG_DEBUG(("Creating new Server ID"));
+
+ if (!new_id)
+ return FALSE;
+
+ /* Create the ID */
+
+ if (!silc_net_addr2bin(ip, new_id->ip.data, sizeof(new_id->ip.data)))
+ return FALSE;
+
+ new_id->ip.data_len = silc_net_is_ip4(ip) ? 4 : 16;
+ new_id->port = SILC_SWAB_16(port);
+ new_id->rnd = silc_rng_get_rn16(server->rng);
+
+ SILC_LOG_DEBUG(("New ID (%s)", silc_id_render(new_id, SILC_ID_SERVER)));
+
+ return TRUE;
+}
+
+/* Checks whether the `server_id' is valid. It must be based to the
+ IP address provided in the `remote' socket connection. */
+
+SilcBool silc_server_check_server_id(const char *ip_address,
+ SilcServerID *server_id)
+{
+ unsigned char ip[16];
+
+ if (!silc_net_addr2bin(ip_address, ip, sizeof(ip)))
+ return FALSE;
+
+ if (silc_net_is_ip4(ip_address)) {
+ if (!memcmp(server_id->ip.data, ip, 4))
+ return TRUE;
+ } else {
+ if (!memcmp(server_id->ip.data, ip, 16))
+ return TRUE;
+ }
+
+ return FALSE;
+}
--- /dev/null
+/*
+
+ server_util.h
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 1997 - 2005 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SERVER_UTIL_H
+#define SERVER_UTIL_H
+
+/* This function removes all client entries that are originated from
+ `router' and are owned by `entry'. `router' and `entry' can be same
+ too. If `server_signoff' is TRUE then SERVER_SIGNOFF notify is
+ distributed to our local clients. */
+SilcBool silc_server_remove_clients_by_server(SilcServer server,
+ SilcServerEntry router,
+ SilcServerEntry entry,
+ SilcBool server_signoff);
+
+/* Updates the clients that are originated from the `from' to be originated
+ from the `to'. If the `resolve_real_server' is TRUE then this will
+ attempt to figure out which clients really are originated from the
+ `from' and which are originated from a server that we have connection
+ to, when we've acting as backup router. If it is FALSE the `to' will
+ be the new source. If `from' is NULL then all clients (except locally
+ connected) are updated `to'. */
+void silc_server_update_clients_by_server(SilcServer server,
+ SilcServerEntry from,
+ SilcServerEntry to,
+ SilcBool resolve_real_server);
+
+/* Updates servers that are from `from' to be originated from `to'. This
+ will also update the server's connection to `to's connection. */
+void silc_server_update_servers_by_server(SilcServer server,
+ SilcServerEntry from,
+ SilcServerEntry to);
+
+/* Toggles the enabled/disabled status of local server connections. Packets
+ can be sent to the servers when `toggle_enabled' is TRUE and will be
+ dropped if `toggle_enabled' is FALSE, after this function is called. */
+void silc_server_local_servers_toggle_enabled(SilcServer server,
+ SilcBool toggle_enabled);
+
+/* Removes servers that are originated from the `from'. The server
+ entry is deleted in this function. If `remove_clients' is TRUE then
+ all clients originated from the server are removed too, and server
+ signoff is sent. Note that this does not remove the `from'. This
+ also does not remove locally connected servers. */
+void silc_server_remove_servers_by_server(SilcServer server,
+ SilcServerEntry from,
+ SilcBool remove_clients);
+
+/* Removes channels that are from `from. */
+void silc_server_remove_channels_by_server(SilcServer server,
+ SilcServerEntry from);
+
+/* Updates channels that are from `from' to be originated from `to'. */
+void silc_server_update_channels_by_server(SilcServer server,
+ SilcServerEntry from,
+ SilcServerEntry to);
+
+/* Checks whether given channel has global users. If it does this returns
+ TRUE and FALSE if there is only locally connected clients on the channel. */
+SilcBool silc_server_channel_has_global(SilcChannelEntry channel);
+
+/* Checks whether given channel has locally connected users. If it does this
+ returns TRUE and FALSE if there is not one locally connected client. */
+SilcBool silc_server_channel_has_local(SilcChannelEntry channel);
+
+/* This function removes the channel and all users on the channel, unless
+ the channel is permanent. In this case the channel is disabled but all
+ users are removed from the channel. Returns TRUE if the channel is
+ destroyed totally, and FALSE if it is permanent and remains. */
+SilcBool silc_server_channel_delete(SilcServer server,
+ SilcChannelEntry channel);
+
+/* Returns TRUE if the given client is on the channel. FALSE if not.
+ This works because we assure that the user list on the channel is
+ always in up to date thus we can only check the channel list from
+ `client' which is faster than checking the user list from `channel'. */
+SilcBool silc_server_client_on_channel(SilcClientEntry client,
+ SilcChannelEntry channel,
+ SilcChannelClientEntry *chl);
+
+/* Find number of sockets by IP address indicated by `ip'. Returns 0 if
+ socket connections with the IP address does not exist. */
+SilcUInt32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip,
+ SilcSocketType type);
+
+/* Find number of sockets by IP address indicated by remote host, indicated
+ by `ip' or `hostname', `port', and `type'. Returns 0 if socket connections
+ does not exist. If `ip' is provided then `hostname' is ignored. */
+SilcUInt32 silc_server_num_sockets_by_remote(SilcServer server,
+ const char *ip,
+ const char *hostname,
+ SilcUInt16 port,
+ SilcSocketType type);
+
+/* Finds locally cached public key by the public key received in the SKE.
+ If we have it locally cached then we trust it and will use it in the
+ authentication protocol. Returns the locally cached public key or NULL
+ if we do not find the public key. */
+SilcPublicKey silc_server_find_public_key(SilcServer server,
+ SilcHashTable local_public_keys,
+ SilcPublicKey remote_public_key);
+
+/* This returns the first public key from the table of public keys. This
+ is used only in cases where single public key exists in the table and
+ we want to get a pointer to it. For public key tables that has multiple
+ keys in it the silc_server_find_public_key must be used. */
+SilcPublicKey silc_server_get_public_key(SilcServer server,
+ SilcHashTable local_public_keys);
+
+/* Check whether the connection `sock' is allowed to connect to us. This
+ checks for example whether there is too much connections for this host,
+ and required version for the host etc. */
+SilcBool silc_server_connection_allowed(SilcServer server,
+ SilcSocketConnection sock,
+ SilcSocketType type,
+ SilcServerConfigConnParams *global,
+ SilcServerConfigConnParams *params,
+ SilcSKE ske);
+
+/* Checks that client has rights to add or remove channel modes. If any
+ of the checks fails FALSE is returned. */
+SilcBool silc_server_check_cmode_rights(SilcServer server,
+ SilcChannelEntry channel,
+ SilcChannelClientEntry client,
+ SilcUInt32 mode);
+
+/* Check that the client has rights to change its user mode. Returns
+ FALSE if setting some mode is not allowed. */
+SilcBool silc_server_check_umode_rights(SilcServer server,
+ SilcClientEntry client,
+ SilcUInt32 mode);
+
+/* This function is used to send the notify packets and motd to the
+ incoming client connection. */
+void silc_server_send_connect_notifys(SilcServer server,
+ SilcSocketConnection sock,
+ SilcClientEntry client);
+
+/* Kill the client indicated by `remote_client' sending KILLED notify
+ to the client, to all channels client has joined and to primary
+ router if needed. The killed client is also removed from all channels. */
+void silc_server_kill_client(SilcServer server,
+ SilcClientEntry remote_client,
+ const char *comment,
+ void *killer_id,
+ SilcIdType killer_id_type);
+
+/* This function checks whether the `client' nickname is being watched
+ by someone, and notifies the watcher of the notify change of notify
+ type indicated by `notify'. */
+SilcBool silc_server_check_watcher_list(SilcServer server,
+ SilcClientEntry client,
+ const char *new_nick,
+ SilcNotifyType notify);
+
+/* Remove the `client' from watcher list. After calling this the `client'
+ is not watching any nicknames. */
+SilcBool silc_server_del_from_watcher_list(SilcServer server,
+ SilcClientEntry client);
+
+/* Force the client indicated by `chl' to change the channel user mode
+ on channel indicated by `channel' to `forced_mode'. */
+SilcBool silc_server_force_cumode_change(SilcServer server,
+ SilcSocketConnection sock,
+ SilcChannelEntry channel,
+ SilcChannelClientEntry chl,
+ SilcUInt32 forced_mode);
+
+/* Find active socket connection by the IP address and port indicated by
+ `ip' and `port', and socket connection type of `type'. */
+SilcSocketConnection
+silc_server_find_socket_by_host(SilcServer server,
+ SilcSocketType type,
+ const char *ip, SilcUInt16 port);
+
+/* This function can be used to match the invite and ban lists. */
+SilcBool silc_server_inviteban_match(SilcServer server, SilcHashTable list,
+ SilcUInt8 type, void *check);
+
+/* Process invite or ban information */
+SilcBool silc_server_inviteban_process(SilcServer server, SilcHashTable list,
+ SilcUInt8 action, SilcArgumentPayload args);
+
+/* Destructor for invite or ban list entrys */
+void silc_server_inviteban_destruct(void *key, void *context,
+ void *user_context);
+
+/* Creates connections according to configuration. */
+void silc_server_create_connections(SilcServer server);
+
+
+/* Processes a channel public key, either adds or removes it. */
+SilcStatus
+silc_server_process_channel_pk(SilcServer server,
+ SilcChannelEntry channel,
+ SilcUInt32 type, const unsigned char *pk,
+ SilcUInt32 pk_len);
+
+/* Returns the channel public keys as Argument List payload. */
+SilcBuffer silc_server_get_channel_pk_list(SilcServer server,
+ SilcChannelEntry channel,
+ SilcBool announce,
+ SilcBool delete);
+
+/* Sets the channel public keys into channel from the list of public keys. */
+SilcStatus silc_server_set_channel_pk_list(SilcServer server,
+ SilcSocketConnection sender,
+ SilcChannelEntry channel,
+ const unsigned char *pklist,
+ SilcUInt32 pklist_len);
+
+/* Verifies the Authentication Payload `auth' with one of the public keys
+ on the `channel' public key list. */
+SilcBool silc_server_verify_channel_auth(SilcServer server,
+ SilcChannelEntry channel,
+ SilcClientID *client_id,
+ const unsigned char *auth,
+ SilcUInt32 auth_len);
+
+#endif /* SERVER_UTIL_H */