From: Pekka Riikonen Date: Wed, 28 Dec 2005 18:17:42 +0000 (+0000) Subject: Added. X-Git-Tag: silc.client.1.1.beta1~324 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=69133353bfa52ea5c10d75499707521b5daa747d Added. --- diff --git a/lib/silcserver/server_internal.h b/lib/silcserver/server_internal.h new file mode 100644 index 00000000..5e1b90e9 --- /dev/null +++ b/lib/silcserver/server_internal.h @@ -0,0 +1,514 @@ +/* + + server_internal.h + + Author: Pekka Riikonen + + 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 */ diff --git a/lib/silcserver/server_util.c b/lib/silcserver/server_util.c new file mode 100644 index 00000000..4ce698ef --- /dev/null +++ b/lib/silcserver/server_util.c @@ -0,0 +1,203 @@ +/* + + server_util.c + + Author: Pekka Riikonen + + 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; +} diff --git a/lib/silcserver/server_util.h b/lib/silcserver/server_util.h new file mode 100644 index 00000000..aa0737d3 --- /dev/null +++ b/lib/silcserver/server_util.h @@ -0,0 +1,236 @@ +/* + + server_util.h + + Author: Pekka Riikonen + + 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 */