Added.
authorPekka Riikonen <priikone@silcnet.org>
Wed, 28 Dec 2005 18:17:42 +0000 (18:17 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Wed, 28 Dec 2005 18:17:42 +0000 (18:17 +0000)
lib/silcserver/server_internal.h [new file with mode: 0644]
lib/silcserver/server_util.c [new file with mode: 0644]
lib/silcserver/server_util.h [new file with mode: 0644]

diff --git a/lib/silcserver/server_internal.h b/lib/silcserver/server_internal.h
new file mode 100644 (file)
index 0000000..5e1b90e
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+
+  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 */
diff --git a/lib/silcserver/server_util.c b/lib/silcserver/server_util.c
new file mode 100644 (file)
index 0000000..4ce698e
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+
+  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;
+}
diff --git a/lib/silcserver/server_util.h b/lib/silcserver/server_util.h
new file mode 100644 (file)
index 0000000..aa0737d
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+
+  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 */