--- /dev/null
++Wed Feb 13 12:46:25 CET 2002 Johnny Mnemonic <johnny@themnemonic.org>
++
++ * Merged the new SILC Config library, with the server parsing
++ support. Read the header file silcconfig.h or the toolkit
++ documentation for the news. Affected files are
++ doc/example_silcd.conf.in lib/silcutil/silcconfig.[ch]
++ silcd/command.c silcd/packet_receive.c silcd/packet_send.c
++ silcd/protocol.c silcd/server.c silcd/server_backup.c
++ silcd/serverconfig.[ch] silcd/silcd.c.
++
++ * Fixed some silclog documentation. Affected file is
++ lib/silcutil/silclog.h.
++
+Sun Feb 10 18:11:30 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * The silc_cipher_register, silc_hash_register and
+ silc_hmac_register now checks if the object to be registered
+ is registered already. Affected files are
+ lib/silccrypt/silccipher.c, silchash.c and silchmac.c.
+
+Sun Feb 10 15:48:38 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Merged new irssi from irssi.org's CVS, the version 0.7.99.
+
+Sat Feb 9 14:54:33 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Allow zero length channel messages inside the Channel Message
+ Payload. Affected file lib/silccore/silcchannel.c.
+
+ * Fixed scripts/silcdoc/silcdoc to support all kinds of filenames
+ as header filenames.
+
+ * Removed lib/silcclient/README and created HTML file
+ lib/silcclient/silcclient_using.html, which is now included
+ as part of Toolkit documentation.
+
+Thu Feb 7 10:12:25 CET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed CUMODE_CHANGE notify handling to change the mode of
+ correct client. Affected file lib/silcclient/client_notify.c.
+
+ * Make silc_rng_alloc fail if it cannot allocate the sha1
+ hash algorithm. Affected file lib/silccrypt/silcrng.c.
+
+Sun Feb 3 17:20:52 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed the file transfer's key agreement payload to include
+ zero port also if the hostname is NULL because it could not
+ be bound.
+
+ Call file transfer monitor callback now also if error occurs
+ during key agreement protocol.
+
+ Changed the silc_client_file_send interface to return the
+ SilcClientFileError instead of session id. The session ID
+ is returned into pointer provided as argument.
+
+ Check that the file exists locally before sending the
+ file transfer request at all.
+
+ Affected file lib/silcclient/client_ftp.c, silcapi.h.
+
+ * Added SILC_CLIENT_FILE_KEY_AGREEMENT_FAILED file transfer
+ error than can occur while key agreement protocol. Affected
+ file lib/silcclient/silcapi.h.
+
+ * Fixed the event_mode CMODE handler to not crash when mode
+ is changed and +k mode is set in the channel. Affected file
+ irssi/src/silc/core/silc-channels.c.
+
+ * Fixed SILC_LOG_ERROR to give out Error and not Warning, and
+ SILC_LOG_WARNING to give out Warning and not Error. Affected
+ file lib/silcutil/silclog.c.
+
+ * Fixed the channel message payload decryption in the function
+ silc_channel_message_payload_decrypt to not modify the original
+ buffer before it is verified that the message decrypted
+ correctly. Otherwise, next time it is called with correct
+ channel key it won't encrypt since the payload is corrupted.
+ Affected file lib/silccore/silcchannel.c.
+
+Sun Feb 3 11:46:12 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Do not constantly resize the window. A fix patch by cras.
+ Affected file irssi/src/fe-text/screen.c.
+
+Sat Feb 2 16:54:18 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Applied IPv6 fix patch from Jun-ichiro itojun Hagino.
+ Affected file lib/silcutil/silcnet.c.
+
+Fri Feb 1 22:33:11 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed a bug in hash table internal routine for traversing
+ the table with foreach callback. The current entry may
+ become invalid in the callback but it was referenced after
+ the callback returned.
+
+ Do not allow auto rehashing of hash table during the
+ silc_hash_table_foreach operation, for same reasons as it is
+ not allowed for SilcHashTableList. Affected files are
+ lib/silcutil/silchashtable.[ch].
+
+Fri Feb 1 14:55:00 CET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Defined DLLAPI into silcincludes.h and silcwin32.h for
+ Win32 DLL. extern's in header files are now declared with
+ DLLAPI.
+
+Thu Jan 31 23:34:33 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed private message handling. It used some old code that
+ caused the client to crash. Affecte file is
+ lib/silcclient/client_prvmsg.c.
+
+Thu Jan 31 19:06:22 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added function silc_client_add_channel,
+ silc_client_replace_channel_id, and removed functions
+ silc_client_new_channel_id and silc_idlist_get_channel_by_id
+ from client library.
+
+ * Added cross reference of the joined channels to the
+ SilcClientEntry, and changed the SilcChannelEntry's
+ users list to SilcHashTable. The affected files are
+ lib/silcclient/idlist.[ch].
+
+ * Fixed a bug in hash table tarversing. While the hash table
+ is traversed with SilcHashTableList the table must not be
+ rehashed. It is now guaranteed that auto rehashable tables
+ are not rehashed while tarversing the list. Also defined that
+ silc_hash_table_rehash must not be called while tarversing
+ the table. Added function silc_hash_table_list_reset that must
+ be called after the tarversing is over. The affected files are
+ lib/silcutil/silchashtable.[ch].
+
+ * Changed all hash table traversing to call the new
+ silc_hash_table_list_reset in server and in client library.
+
+ * Added function silc_client_on_channel to return the
+ SilcChannelUser entry if the specified client entry is joined
+ on the specified channel. This is exported to application as
+ well. Affected files lib/silcclient/client_channel.c, silcapi.h.
+
+Wed Jan 30 19:14:31 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed founder regaining problem with JOIN command on normal
+ server. The notify for mode change must be sent always and
+ not only if !cmd->pending. Affected file silcd/command.c.
+
+ * Fixed the WHOWAS command's reply sending to support the
+ lists correctly. Affected file silcd/command.c.
+
+Wed Jan 30 11:11:47 CET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * When sending JOIN command to router for processing the
+ sender's old command identifier was not saved back to the
+ sender's command context, fixed now. The affected file is
+ silcd/command.c.
+
+ * Create the key in JOIN command of the router did not return
+ the channel key, added check for this. Affected file is
+ silcd/command.c.
+
+ * Fixed a channel ID update bug in JOIN command reply. Do
+ not directly upgrade the ID but call the function
+ silc_idlist_replace_channel_id if the ID was changed.
+ Affected file silcd/command_reply.c.
+
+ * Fixed memory leaks from command calling if it would fail.
+ Affected file silcd/command.c.
+
+Tue Jan 29 19:49:31 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Applied patches from cras:
+
+ Memory leak fixes around libaries, irssi window resize fix,
+ new silclist.h and silcdlist.h, all extern inline changed to
+ static inline.
+
+ * Removed dotconf from lib/dotconf, not needed anymore.
+
+ * Removed TRQ from lib/trq, not needed anymore.
+
+ * Do more frequent heartbeats (5 minutes instead of 10 minutes)
+ with server connections. Later this will be configurable
+ in config file after new config file is done. Affected file
+ silcd/server.c.
+
+Tue Jan 29 10:35:03 CET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed a crash in server related to channel announcements.
+ Affected file silcd/server.c.
+
+Mon Jan 28 17:49:42 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed memory leaks in silc_server_create_new_channel*
+ functions. Affected file silcd/server.c.
+
+ * Fixed the CHANNEL_CHANGE notify to re-announce the channel
+ which ID was changed. This way the router will send the
+ user list for the channel again, and server won't be in
+ desync in some rare circumstances. Affected file is
+ silcd/packet_receive.c.
+
+Sun Jan 27 21:04:19 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Check for NULL socket pointer in the function
+ silc_server_packet_send_to_channel_real. Affected file
+ silcd/packet_send.c.
+
+ * Fixed the BAN notify handling to correctly remove ban
+ list. Affected file silcd/packet_receive.c.
+
+Sat Jan 26 23:01:03 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed some header addition to Toolkit distribution in
+ lib/silcutil/Makefile.am and lib/trq/Makefile.am.
+
+ * Added lib/silcclient/client_ops_example.h as an template
+ file for application programmers to quickly start using
+ the SilcClientOperation functions in their application.
+ Updated the lib/silcclient/README as well to tell about this
+ nice file made available.
+
+Sat Jan 26 10:45:41 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Call silc_server_remove_from_channels when removing client
+ entry when NO_SUCH_CLIENT_ID was received. Affected file
+ is silcd/command_reply.c.
+
+Fri Jan 25 19:12:36 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added server & router operator statistics updating. Affected
+ file silcd/packet_receive.c and silcd/command.c.
+
+ * Fixed the SERVER_SIGNOFF notify handling on normal server
+ not to save the history information for clients. Same was
+ fixed earlier in remove_clients_by_server function, but not
+ here. Affected file silcd/packet_receive.c.
+
+ * Raised the default connection-retry count from 4 to 7 in
+ server. Affected file silcd/server.h.
+
+ * Cancel any possible reconnect timeouts when we start the
+ key exchange. Affected file silcd/server.c.
+
+ * Do not reconnect on connection failure when SCONNECT was
+ given. Affected files silcd/server.[ch].
+
+Tue Jan 22 18:19:36 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Removed assert()'s from the lib/silcclient/client_keyagr.c.
+
+ * Fixed the NICK command to always give the unformatted
+ nickname to the one giving the NICK command. If unformatted
+ nickname is cached already it will be formatted and the
+ local entry will always get the unformatted nickname.
+ Affected file lib/silcclient/idlist.c.
+
+ * Fixed some double frees from client library commands.
+ Affected file is lib/silcclient/command.c.
+
+ * Fixed CUMODE command in server to assure that no one can
+ change founder's mode than the founder itself, there was a
+ little bug. Affected file silcd/command.c.
+
+Mon Jan 21 19:07:53 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Removed the SilcClientCommandDestructor from the client
+ libary, it is not needed anymore. Affected files are
+ lib/silcclient/silcapi.h, command[_reply].[ch],
+ client_notify, idlist.c.
+
+ * Fixed GETKEY command to first resolve client, and then
+ resolve the server only if the client was not found, instead
+ of resolving both at the same time. Affected file is
+ lib/silcclient/command.c.
+
+ * Added silc_client_start_key_exchange_cb and lookup the
+ remote hostname and IP address before starting the key
+ exchange with server. The affected file is
+ lib/silcclient/client.c.
+
+ * The server's public key is now saved using the IP address
+ of the server and not the servername for the filename.
+ The hostname public key filename is checked as an fall back
+ method if the IP address based filename is not found.
+
+ Fixed the GETKEY command to save the fetched server key
+ in correct filename.
+
+ Print the remote server's hostname now when new key is
+ received during connection process. Affected file is
+ irssi/src/silc/core/client_ops.c.
+
+ * Return always our own public key to the client if it asks
+ for it with GETKEY command. Affected file silcd/command.c.
+
+ * Removed the use_auto_addr variable from default config
+ file since it was in wrong section. Affected file is
+ irssi/src/config.
+
+ * Fixed TOPIC_CHANGE notification to not route it when it
+ was sent using silc_server_send_notify_to_channel function.
+ Affected file silcd/command.c.
+
+ * Fixed silc_server_send_notify_kicked to send the kicker's
+ Client ID also, it was missing. Affected files are
+ silcd/command.c, silcd/packet_send.[ch].
+
+Thu Jan 17 18:59:11 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Do not save client history information in SERVER_SIGNOFF.
+ Fixes the bug in normal server that it does not detect
+ the client becoming valid after the server becomes back
+ online. Affected file silcd/server_util.c.
+
+ * Added `sock_error' field into the SilcSocketConnection
+ context. When error occurs during socket operation (read
+ or write) the error is saved. Added also new function
+ silc_socket_get_error to return human readable socket error
+ message. Affected files are lib/silcutil/silcsockconn.[ch],
+ lib/silcutil/unix/silcunixsockconn.c, and
+ lib/silcutil/win32/silcwin32sockconn.c.
+
+ * The server now prints the socket error message in the
+ signoff for client. Affected file silcd/server.c.
+
+ * Fixed the `created' channel information sending from router
+ to server in JOIN command. Checks now whether the channel
+ really was created or not and set it according that.
+
+ Fixed the JOIN command to use the client entry's current
+ ID during the joining procedure instead of the one it sent
+ in the command (it is checked though), since it can change
+ between the packet processing and command processing, and
+ would just case unnecessary pain in the client end. Affected
+ file silcd/command.c.
+
+ * Fixed a channel key payload sending to use correct channel
+ ID when the server was forced to change the channel's ID by
+ router. Router sent the key payload with the old Channel ID.
+ Affected file silcd/packet_receive.c.
+
+Wed Jan 16 22:26:30 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Call silc_server_save_channel_key only if the key payload
+ was provided in the JOIN command's command reply. Affected
+ file silcd/command_reply.c.
+
+Tue Jan 15 18:49:41 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed silc_mp_sizeinbase to return the value correctly with
+ MPI. Affected file lib/silcmath/mp_mpi.c.
+
+ * Fixed the stop_server signal to correctly stop the scheduler
+ and gracefully stop the server when SIGTERM or SIGINT signals
+ are received. Affected file silcd/silcd.c.
+
+Mon Jan 7 23:38:19 CET 2002 Johnny Mnemonic <johnny@themnemonic.org>
+
+ * Simple handling of TERM and HUP signals. Also added some log
+ flushing call around. Affected file is
+ silcd/silcd.c.
+
+ * Fixed small bugs in silclog.c. Now buffering output will take
+ effect after 10 seconds since startup: This will ensure that
+ no important startup messages are lost. Also output redirection
+ will preserve original format ([Date] [Type] message).
+ Affected file is lib/silcutil/silclog.c.
+
+ * Added two options to the config file, in the logging section:
+ quicklogs:<yes/no>: and flushdelay:<seconds>:. Affected files
+ lib/silcutil/silclog.[ch], silcd/serverconfig.[ch].
+
+Sun Jan 6 12:49:40 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Do not print the warning about log files not being initialized
+ more than once to avoid excess logging. Affected file is
+ lib/silcutil/silclog.c.
+
+ * Fixed the SIM compilation in lib/silcsim/Makefile.am. Fixed
+ the SIM copying in make install in Makefile.am.pre.
+
+Sun Jan 6 01:10:21 CET 2001 Johnny Mnemonic <johnny@themnemonic.org>
+
+ * Rewritten silclog APIs. Globally interesting changes follows:
+ silc_log_set_files() changed to silc_log_set_file().
+ silc_log_set_callbacks() changed to silc_log_set_callback().
+ ROBOdoc documented silclog header file.
+ SilcLogCb now returns bool to wether inihibit the default
+ handler or not (to keep the old behaviour return always TRUE).
+ The new APIs should also fix the problem of the
+ silcd_error.log file that was written in the current directory.
+
+ New features:
+ Log files streams will remain opened after silc_log_set_file()
+ call, means less CPU usage notably on high traffic servers.
+ File streams are now full buffered, and flushed to the disk
+ every 5 minutes, lesses HD activity and CPU usage.
+ Messages can be redirected, allowing admins to configure
+ one single logfile for all server messages.
+ the silc_log_quick global variable to activate fast-logging.
+ Affected files lib/silcutil/silclog.[ch]
+
+ * Changed some code to conform new silclog APIs. Affected
+ files are doc/example_silcd.conf.in, silcd/server.c
+ irssi/src/silc/core/silc-core.c, silcd/serverconfig.[ch],
+ silcd/silcd.c.
+
+ * Fixed a memory leak that could occur in some situations.
+ Affected file silcd/serverconfig.c.
+
+Sat Jan 5 13:37:29 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added the silc_client_del_client to remove the client from
+ all channels as well. Affected file lib/silcclient/idlist.c.
+
+ * Fixed the client library to correctly remove the client
+ from all channels when the client entry is being destroyed.
+ Affected file lib/silcclient/client_notify.c, command.c.
+
+ * Added auto-nicking support to the client library. If the
+ applicatio now sets client->nickname it will be sent to the
+ server after connecting by the library. This way for example
+ SILCNICK (or IRCNICK) environment variables will have effect
+ and always change the nickname automatically to whatever
+ it is wanted. Affected file lib/silcclient/client.[ch].
+
+ * Renamed silc_server_command_bad_chars to the
+ silc_server_name_bad_chars and moved it to the
+ silcd/server_util.[ch]. Added also new function
+ silc_server_name_modify_bad to return nickname that
+ includes bad characters as new nickname without those
+ bad characters. This check and modify is now used in
+ silc_server_new_client when the username is initially set
+ as nickname, so it must be checked to be valid nickname.
+ Affected file silcd/packet_receive.c.
+
+ * The nickname length is now taken from the packet for real
+ and not trusted to strlen() since it clearly can return
+ wrong length for nickname including bad characters. This
+ also applies to channel names. Affected file silcd/command.c.
+
+ * Removed the lib/silcsilm/modules directory. Modules are now
+ compiled into the lib/silcsim. Fixed the copying of the
+ modules to follow symbolic links in Makefile.am.pre.
+
+Wed Jan 2 18:56:21 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed silc_string_regexify list creation. Fixes bugs with
+ BAN and INVITE commands in server. The affected file is
+ lib/silcutil/unix/silcunixutil.c.
+
+Sun Dec 30 13:41:34 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Removed the command destructor entirely from the server's
+ command and command reply routines. It is not needed, and
+ its usage was buggy and caused crashes. Affected files are
+ silcd/command[_reply].[ch].
+
+Fri Dec 28 12:43:22 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Cancel protocol and NULL sock->protocol if timeout
+ occurred during protocol. Affected file silcd/server.c.
+
+ * Cancel protocol timeouts always before calling the final
+ callback, to assure that after final callback is called
+ no other state will be called for the protocol anymore.
+ Affected file silcd/protocol.c.
+
+ * Print error log if incoming connection configuration could
+ not be found. Affected file silcd/server.c.
+
+ * Fixed JOIN command to correctly save the founder mode
+ to the client on normal SILC server, when the channel
+ was created by the router. Affected file silcd/command.c.
+
+ * Fixed LIST command (hopefully) to send correct reply
+ packets. Affected file silcd/command.c.
+
+Thu Dec 20 16:14:52 CET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * The silc_packet_receive_process now returns FALSE if the
+ read data was invalid packet, and TRUE if it was ok.
+
+ The server now checks that if unauthenticated connection
+ sends data and its processing fails the server will close
+ the connection since it could be a malicious flooder.
+
+ Affected files lib/silccore/silcpacket.[ch], silcd/server.c.
+
+Wed Dec 19 21:31:25 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Make sure the warning about error opening a log file is
+ printed only once and not everytime it fails (produces
+ too much useless log). Affected file lib/silcutil/silclog.c.
+
+Wed Dec 19 18:21:51 CET 2001 Johnny Mnemonic <johnny@themnemonic.org>
+
+ * Made the silc_server_daemonise() function more readable.
+ Affected file silcd/server.c.
+
+ * Pid file is now optional, the user may comment it out from
+ the config file. Removed define SILC_SERVER_PID_FILE, we
+ don't need a default any longer. Affected file
+ configure.in.pre, lib/Makefile.am.pre.
+
+ * Make some use of the pid file. The server now dies at startup
+ if it detects a valid pid file on his path. The server would
+ die anyway in this circumstance, because of the bind() failure.
+ Affected file silcd/silcd.c.
+
+ * No longer compiling lib/dotconf.
+
+Mon Dec 17 18:24:27 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed JOIN command parsing not to crash. Affected file
+ lib/silcclient/command.c.
+
+ * Fied the NICK_CHANGE notify to add the new client entry
+ even it is resolved. This removes an <[unknown]> nick
+ thingy bug in the client. Affected file is
+ lib/silcclient/client_notify.c.
+
+ * Do not try to allocate 0 bytes (efence does not like it)
+ in lib/silccore/silccomand.c when encoding payload.
+
+ * Do not take IRCNICK as nickname in Irssi SILC client since
+ it is not possible to set nickname before hand connecting
+ the server (TODO has an entry about adding auto-nicking
+ support).
+
+ * Changed the silc_server_command_pending to check whether
+ there already exists an pending entry with the specified
+ command, command identifier and pending callback. This is
+ to fix IDENTIFY and WHOIS related crashes that may register
+ multiple pending commands with same identifier. Affected
+ file silcd/command.c.
+
+ * Fixed the server to reconnect to the router even if it
+ was already reconnecting and EOF was received. This to
+ fix a possibility that the server wouldn't ever try to
+ auto-reconnect to the router. Affected file silcd/server.c.
+
+Sat Dec 15 20:31:50 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed the server's password authentication to use the
+ length of the locally saved password, and not the one
+ sent in the packet. Affected file silcd/protocol.c.
+
+ * Fixed same password authentication problem in the
+ Authentication Payload handling routines in
+ lib/silccore/silcauth.c.
+
+ * Yet another password authentication problem fixed with
+ channel password handling in silcd/command.c.
+
+Mon Dec 10 19:57:40 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * If first character of string in silc_parse_userfqdn is '@'
+ then do not parse it. Affected file is
+ lib/silcutil/silcutil.c.
+
+Sun Dec 9 22:18:50 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed minor bug in IDENTIFY command reply sending, which
+ caused various weird problems during JOIN when it was
+ resolving names for users. Affected file silcd/command.c.
+
+Sun Dec 9 19:18:41 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed the IDENTIFY command reply sending to chech better valid
+ clients. It was possible to send incomplete list of replies.
+ Affected file silcd/command.c.
+
+Sat Dec 8 15:58:31 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added silc_client_command[s]_[un]register functions now to
+ dynamically register the commands in client library. Removed
+ the static table of commands. This allows the client library
+ to call commands without causing the application to know about
+ what commands library has called.
+
+ Removed the INFO command reply kludge to detect when the command
+ was called by library. Now library use its own command reply
+ function for INFO command.
+
+ Added function silc_client_command_call to call a command.
+ Application can use it to call command, not access the structure
+ directly.
+
+ Now all commands that are sent by the client library (not
+ explicitly sent by application) use own command reply functions.
+
+ Affected files around lib/silcclient/ and in
+ irssi/src/silc/core/.
+
+ * Fixed the WHOIS command reply sending to chech better valid
+ clients. It was possible to send incomplete list of replies.
+
+ Fixed the WHOIS and IDENTIFY to send the request to router
+ if normal server did not do it and did not find any results.
+
+ Affected file silcd/command.c.
+
+Thu Dec 6 17:21:06 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Moved the internal data from SilcClient context into its
+ own file, not accesible to application. Affected files
+ lib/silcclient/client.h and lib/silcclient/client_internal.h,
+ and other files in client library.
+
+Thu Dec 6 10:37:55 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added doc/examples installation target in Makefile.am.pre.
+ A patch by salo.
+
+Tue Dec 4 17:43:19 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * If NO_SUCH_CLIENT_ID notify is received for WHOIS or IDENTIFY
+ commands the found client entry will be removed from the
+ cache, after notifying application about the error. Affected
+ file lib/silcclient/command_reply.c.
+
+ * Changed the /MSG to check for exact nickname user gave, and
+ not let `nick' match `nick@host' if it is only one found. Now,
+ user must type the exact nickname (like nick@host2) even if
+ there are no more than one same nicks found. This is to avoid
+ a possibility of sending nickname to wrong nickname since
+ `nick' could match `nick@host'. Affected file is
+ irssi/src/core/silc-servers.c.
+
+Mon Dec 3 18:49:45 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Do not print "you are now server operator" or similar when
+ giving /away command. Affected files are
+ irssi/src/silc/core/client_ops.c, silc-servers.h.
+
+ * Made the silc_server_command_pending_error_check to send
+ the same command reply payload it received back to the
+ original sender of the command. This way all arguments
+ that was received by the server will be received by the
+ client too. Affected file silcd/command.c.
+
+ * Added the silc_idcache_add to return the created cache entry
+ to a pointer. Affected file lib/silccore/silcidcache.[ch].
+
+ * Add global clients to expire if they are not on any channel.
+ This is because normal server will never know if they signoff
+ if they are not on any channel. The cache expiry will take
+ case of these entries. This is done by normal servers only.
+ The affected files are silcd/command_reply.c,
+ silcd/idlist.[ch], silcd/server and silcd/packet_receive.c.
+
+ * If server receives invalid ID notification for WHOIS or
+ IDENTIFY and the ID exists in the lists, it is removed.
+ Affected file silcd/command_reply.c.
+
+ * If NO_SUCH_CLIENT_ID is received for WHOIS or IDENTIFY command
+ in client then client entry that it matches is searched and
+ the nickname is printed on the screen for user. Affected
+ file irssi/src/silc/core/client_ops.c.
+
+Mon Dec 3 11:56:59 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Use cache entry expire time in the LIST command reply to
+ purge old entries from the cache after the LIST command
+ reply has been received. This way we don't have non-existent
+ entries in the cache for too long. Affected file is
+ silcd/command_reply.c.
+
+Sun Dec 2 23:29:07 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * If we are normal server, and we've not resolved client info
+ in WHOIS or IDENTIFY from router, and it is global client,
+ we'll check whether it is on some channel. If it is not
+ then we cannot be sure about its validity and will resolve it
+ from router. Fixes a bug in WHOIS and IDENTIFY. Affected
+ file silcd/command.c.
+
+ * Search channel by name (if possible) rather than by ID
+ in IDENTIFY command's command reply. Affected file is
+ silcd/command_reply.c.
+
+Sun Dec 2 13:48:46 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Distribute to the channel passphrase in CMODE_CHANGE notify.
+ Updated specs and implemented it. Affected file silcd/command.c,
+ silcd/packet_send.c and silcd/packet_receive.c.
+
+ * Implemented the <founder auth> payload handling in the JOIN
+ command. If provided all conditions for channel joining
+ except requirement to provide correct passphrase can be
+ overrided by the channel founder. Updated the protocol specs.
+ Affected file silcd/command.c.
+
+ Added support for founder auth in JOIN command in client
+ library. Fixed the parsing of the JOIN command now to support
+ all options as they should be. The affected file is
+ lib/silcclient/command.c.
+
+ * Optimized the WHOIS and IDENTIFY commands to send the request
+ to router only if it includes nicknames or other names. If
+ they include only IDs then check the local cache first before
+ routing. Affected file is silcd/command.c.
+
+ * Added channels topic announcements. Affected file is
+ silcd/packet_receive.c and silcd/server.c.
+
+ * Fixed the silc_server_send_notify_topic_set to really destine
+ the packet to channel. Affected file silcd/packet_send.c.
+
+ * Fixed a crash in CHANNEL_CHANGE notify handling in the client
+ library. Affected file lib/silcclient/client_notify.c.
+
+ * Added UMODE announcements. Affected file silcd/server.c.
+
+Sat Dec 1 12:52:39 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Memory leak fixes in:
+
+ lib/silcutil/silcsockconn.c
+ lib/silcske/silcske.c
+ lib/silcske/groups.c
+ lib/silccrypt/rsa.c
+ lib/silccrypt/silcpkcs.c
+ lib/silccore/silccommand.c
+ lib/silccore/silcidcache.c
+ silcd/idlist.c
+ silcd/packet_send.c
+ silcd/command.c
+
+ * ROBOdoc documented the lib/silcske/groups.h file and a
+ bit changed the interface for better.
+
+Thu Nov 29 22:12:50 EET 2001 Pekka Riikonen <priikone@silcnet.org>'
+
+ * Update the client entry context in the ID cache after
+ nick change. Affected file lib/silcclient/command.c.
+ Fixes the CUMODE command when regaining founder privileges,
+ and a little WHOIS problem.
+
+ * Fixed silc_net_gethostbyname to correctly call the
+ inet_ntop. Affected file lib/silcutil/silcnet.c.
+
+Thu Nov 29 19:31:23 EET 2001 Pekka Riikonen <priikone@silcnet.org>'
+
+ * Added IPv6 support checking to the configure.in.pre, added
+ also --enable-ipv6 option to override the check. Affected
+ file configure.in.pre.
+
+ * The silc_thread_create now calls the start function
+ directly if threads support is not compiled in. Removes
+ ugly #ifdef's from generic code. Affected files are
+ lib/silcutil/unix/silcunixthread, win32/silcwin32thread.c.
+
+ * Added silc_net_gethostby[name/addr]_async to asynchronously
+ resolve. Affected files are lib/silcutil/silcnet.[ch].
+
+ * Added support for rendering IPv6 based server, client and
+ channel IDs. Affected file lib/silcutil/silcutil.c.
+
+ * Added support for creating IPv6 based server IDs. Affected
+ file is silcd/serverid.c.
+
+Wed Nov 28 23:46:09 EET 2001 Pekka Riikonen <priikone@silcnet.org>'
+
+ * Added silc_net_gethostby[addr/name] into the
+ lib/silcutil/silcnet.[ch]. Added IPv6 support to Unix network
+ routines. Added silc_net_is_ip[4/6]. Affected file is
+ lib/silcutil/unix/silcunixnet.c. All routines that take
+ address as argument now supports both IPv4 and IPv6 addresses.
+
+Mon Nov 26 18:09:48 EET 2001 Pekka Riikonen <priikone@silcnet.org>'
+
+ * Fixed LIST command reply sending in server. Affected file
+ silcd/command.c.
+
+ * Server now sends the kicker's client ID in the KICK notify
+ to the kicked client. Affected file silcd/command.c.
+
+ * The client library now parses the kickers client ID and
+ UI displays it. Affected files lib/silcclient/client_notify.c
+ and irssi/src/silc/core/silc-channels.c, module-formats.c.
+
+ * Made all payload parsing function prototypes consistent.
+ They all take now const unsigned char * and uint32 pair as
+ the payload data instead of SilcBuffer. Changes all around
+ the source tree. Other unsigned char* -> const unsigned char*
+ changes around the tree as well.
+
+ * Optimized SFTP client and server packet sending not to
+ allocate new buffer for each packet but to recycle the
+ first allocated buffer. Affected files are
+ lib/silcsftp/sftp_client.c, sftp_server.c, sftp_util.[ch].
+
+ * Optimized the SFTP client to use SilcList instead of
+ SilcDList for requests, because it is faster. Affected file
+ is lib/silcsftp/sftp_client.c.
+
+ * Moved the ID Payload routines from lib/silccore/silcpayload.[ch]
+ into lib/silccore/silcid.[ch].
+
+ Renamed silcpayload.[ch] into silcargument.[ch].
+
+Mon Nov 26 15:01:53 CET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * If client entry is deleted with active key agreement
+ session, abort the session.
+
+ The silc_client_abort_key_agreement now calls the completion
+ callback with new SILC_KEY_AGREEMENT_ABORTED status.
+
+ Affected file lib/silcclient/silcapi.h, client_keyagr.c and
+ idlist.c.
+
+Sun Nov 25 18:01:45 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Don't use __restrict in older GCC's. Affected file is
+ lib/silcmath/mpi/mpi-priv.h. A patch by salo.
+
+ * silc_net_localhost now attempts to reverse lookup the
+ IP/hostname. Affected file lib/silcutil/silcnet.c.
+
+ * Defined <founder auth> argument to the SILC_COMMAND_JOIN
+ command. It can be used to gain founder privileges at
+ the same time when joining the channel.
+
+ Defined that the SILC_NOTIFY_TYPE_KICKED send the
+ kicker's client ID as well. Updated protocol specs.
+
+ Defined that the server must send SILC_COMMAND_IDENTIFY
+ command reply with error status to client who sent
+ private message with invalid client ID.
+
+ Updated the protocol specification.
+
+ * Added silc_server_send_command_reply to send any
+ command reply. Affected file silcd/packet_send.[ch].
+
+ * Added silc_id_payload_encode_data to encode ID payload
+ from raw ID data. Affected file lib/silccore/silcpayload.[ch].
+
+ * The server now send IDENTIFY command reply with error
+ status if client ID in private message is invalid. Affected
+ file silcd/packet_receive.c.
+
+ * Save the server key file with server's IP address in
+ the filename instead of hostname. The affected file is
+ irssi/src/silc/core/client_ops.c.
+
+Sat Nov 24 20:08:22 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Typo fixes in irssi/src/fe-common/silc/module-formats.c.
+ A patch by Sunfall.
+
+ * Added libtool support for compiling shared objects in
+ lib/silcsim. Affected file configure.in.pre and
+ lib/silcsim/Makefile.am. Original patch by cras.
+
+Fri Nov 23 23:30:59 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Pid file configuration, and server's config file fixes
+ patch by toma. Updated CREDITS file.
+
+Sun Nov 18 01:34:41 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed silc_client_channel_message to not try to decrypt
+ the message twice if it resolved the destination client
+ information. This could cause of dropping one channel
+ message. Affected file lib/silcclient/client_channel.c.
+
+Wed Nov 14 23:44:56 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added silc_client_run_one into lib/silcclient/silcapi.h and
+ lib/silcclient/client.c. This function is used when the SILC
+ Client is run under some other scheduler, or event loop or
+ main loop. On GUI applications, for example this may be
+ desired to used to run the client under the GUI application's
+ main loop. Typically the GUI application would register an
+ idle task that calls this function multiple times in a second
+ to quickly process the SILC specific data.
+
+Wed Nov 14 19:16:52 CET 2001 Johnny Mnemonic <johnny@themnemonic.org>
+
+ * Fixed silc_server_drop() for dropping the supplementary
+ groups as well, this could cause a security hole on some
+ systems.
+
+Wed Nov 14 16:22:25 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * __pid_t -> pid_t in lib/silccrypt/silcrng.c. A patch by
+ johnny.
+
+ * Write PID file after dropping privileges. Added -F option
+ to run server on foreground. A patch by debolaz.
+ Affected files silcd/server.c, silcd/silcd.c.
+
+ * Fixed MOTD to return the MOTD file server name. Affected
+ file silcd/command.c.
+
+ * Added INFO command reply handling to the Irssi SILC Client.
+ Affected file irssi/src/silc/core/client_ops.c.
+
+Wed Nov 14 00:18:08 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed the silc_idcache_list_* routines to really support
+ the dynamic list. Fixes a crash. Affected file is
+ lib/silccore/silcidcache.c.
+
+ * Fixed the LIST command reply to really call LIST command's
+ pending callbacks. Affected file silcd/command_reply.c.
+
+Tue Nov 13 00:49:17 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Update conn->local_entry->nickname after giving NICK
+ command. Affected file lib/silcclient/command.c.
+
+Sun Nov 11 23:43:02 PST 2001 Brian Costello <bc@wpfr.org>
+
+ * Added the [pid] option to the silcd configuration file
+
+ Affected files: serverconfig.[ch] and silcd.c
+
+Sun Nov 11 23:56:39 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Save fingerprint in WHOIS command reply in server.
+ Affected file silcd/command_reply.c.
+
+ * Fixed NICK commands pending callback registration.
+ Affected file lib/silcclient/command.c.
+
+Sun Nov 11 10:49:10 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Use ++server->cmd_ident when sending commands in server,
+ instead of random number. Affected file silcd/command.c.
+
+ * Fixed GETKEY command reply to call actually GETKEY pending
+ command callbacks. Affected file silcd/command_reply.c.
+
+ * A bit stricter check for nicknames. Check for same nickname
+ in NICK command also. Affected file silcd/command.c.
+
+ * Do not call INFO command everytime client ID changes, only
+ during first connecting. Affected file lib/silcclient/client.c.
+
+ * Set the new nickname only after successful command reply for
+ NICK command is returned by server. Affected file
+ lib/silcclient/command.c.
+
+ * Remove nicknames from nicklist during server_signoff notify.
+ Should fix /NAMES bit more. The affected file is
+ irssi/src/silc/core/silc-channels.c.
+
+ * Added `fingerprint' field to the SilcIDListData in the
+ silcd/idlist.h to hold the fingerprint of the client's
+ public key.
+
+ Send the fingerprint of the client's public key in WHOIS
+ command reply.
+
+ Affected files silcd/command.c, and silcd/idlist.[ch].
+
+ * Added silc_fingerprint into lib/silcutil/silcutil.[ch] to
+ create fingerprint from given data.
+
+ * Show the fingerprint of the client's public key in WHOIS.
+ Affected files irssi/src/module-formats.[ch] and
+ irssi/src/silc/core/client_ops.c.
+
+ * Format the multiple same nicknames also during JOIN and
+ NICK_CHANGE notifys. Affected file is
+ lib/silcclient/client_notify.c.
+
+ * Do not print error on screen for invalid private message
+ payload since it can come if someone is sending private
+ messages with wrong key. Affected file
+ lib/silccore/silcprivate.c.
+
+ * Fixed multiple concurrent /PING crash. Affected file
+ lib/silcclient/command.c.
+
+ * Changed the wrong ID encoding. All IP addresses must be
+ in MSB first order in encoded format. They were encoded
+ wrong and was in LSB format. Affected files are
+ silcd/serverid.c, lib/silcutil/silcutil.c.
+
+ * Remove silc_net_addr2bin_ne from lib/silcutil/silcnet.[ch].
+
+ * Call the `connect' client operation through the scheduler
+ in case of error. Affected file lib/silcclient/client.c.
+
+ * Call the `failure' client operation even if the error
+ occurred locally during a protocol. Affected file is
+ lib/silcclient/protocol.c.
+
+ * Added support of sending LIST command to router from normal
+ server. This way normal server can get list of all channels
+ in the network too. Fixed the channel list sending in the
+ server too. Affected files are silcd/command.c, and
+ silcd/command_reply.[ch].
+
+ * Added silc_server_update_channels_by_server and
+ silc_server_remove_channels_by_server. They are used during
+ disconnection of primary router and in backup router protocol.
+ Affected file silcd/server_util.[ch], silcd/server.c and
+ silcd/server_backup.c.
+
+ * Fixed channel adding to global list in IDENTIFY command
+ reply in server. Affected file silcd/command_reply.c.
+
+Sat Nov 10 21:39:22 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * If the incoming packet type is REKEY or REKEY_DONE process
+ that packet always synchronously. Fixes yet another MAC
+ failed error on slow (dialup) connections. Affected file
+ lib/silcclient/client.c and silcd/server.c.
+
+Thu Nov 8 22:21:09 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Call check_version SKE callback for initiator too. Affected
+ file lib/silcske/silcske.c.
+
+ * Implemented fix for security hole found in the SKE that was
+ fixed in the specification few days back; the initiator's
+ public key is now added to the HASH value computation.
+ Added backwards support for the old way of doing it too, for
+ old clients and old servers. Affected file is
+ lib/silcske/silcske.c.
+
+ * Enabled mutual authentication by default in SKE. If initiator
+ is not providing mutual authentication the responder will
+ force it. This will provide the proof of posession of the
+ private key for responder. The affected files are
+ lib/silcclient/protocol.c and silcd/protocol.c.
+
+ * Do not cache anymore the server's public key during SKE.
+ We do mutual authentication so the proof of posession of
+ private key is done, and if the server is authenticated in
+ conn auth protocol with public key we must have the public
+ key already. Affected file silcd/protocol.c.
+
+ * Added new global debug variable: silc_debug_hexdump. If
+ it is set to TRUE SILC_LOG_HEXDUMP will be printed. Affected
+ file lib/silcutil/silclog.[ch].
+
+ * Fixed compilation warning due to char * -> const char *.
+ Affected files lib/silcutil/silcnet.h, and
+ lib/silccore/silcauth.[ch].
+
+Wed Nov 7 20:43:03 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed CMODE command when new channel key was created. If
+ the creation failed the old key was removed. Next time giving
+ same command would crash the server since the old key was
+ freed already. Affected file silcd/command.c.
+
+ * Fixed the silc_server_announce_get_channels to not crash
+ on reconnect. Affected file silcd/server.c.
+
+Wed Nov 7 17:15:07 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added silc_log_set_debug_string function to set a regex
+ string to match for debug output. Only the function names,
+ or filenames matching the given debug string is actually
+ printed. This way it is possible to filter out those debug
+ strings that user is not interested in.
+
+ Fixed a bug in silc_string_regexify.
+
+ Affected files lib/silcutil/silclog.[ch], and
+ lib/silcutil/unix/silcunixutil.c.
+
+ * Changed the -d options in both server and Irssi SILC client
+ to take the debug string as argument. Affected files
+ silcd/silcd.c and irssi/src/silc/core/silc-core.c.
+
+Tue Nov 6 21:31:54 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added silc_hash_babbleprint to create a Bubble Babble
+ Encoded fingerprint. The encoding is developed by Antti
+ Huima (draft-huima-babble-01.txt), and it creates human
+ readable strings out of binary data. Affected file
+ lib/silccrypt/silchash.[ch].
+
+ * Print the babble print now in addition of fingerprint as well
+ in Irssi SILC client. Affected files are
+ irssi/src/fe-common/silc/module-formats.[ch],
+ irssi/src/fe-common/silc/core/client_ops.c.
+
+Sun Nov 4 23:37:28 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed a security problem found in SKE. The initiator's
+ public key too is now added to the HASH hash value creation
+ which is signed by the responder to create the SIGN value.
+ This will prevent anyone in the middle to lie to the responder
+ about the initiator's public key. If this is done now, the
+ man in the middle will get caught. Updated the protocol
+ specification.
+
+Sun Nov 4 11:43:53 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Better installation directory handling. Configure module
+ paths and other paths automatically to example_silc* files
+ in doc/. A patch by toma.
+
+ * Fixed compiler warning from MPI library, and from SILC RNG.
+ A patch by johnny.
+
+ * Added SILC_SERVER_PID_FILE to define the pid file for server.
+ It can be configured with ./configure. A patch by toma.
+
+Sat Nov 3 23:48:23 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Find correct make to use in prepare-clean. A patch by
+ toma. Affected file prepare-clean.
+
+Sat Nov 3 22:04:00 PST 2001 Brian Costello <bc@mksecure.com>
+
+ * Added irssi variables use_auto_addr, auto_bind_ip,
+ auto_bind_port and auto_public_ip.
+
+ * Changed the interface for silc_client_send_key_agreement
+ in lib/silcclient/silcapi.h
+
+ Affected files:
+
+ irssi/src/silc/core/silc-core.c
+ irssi/config
+ lib/silcclient/silcapi.h
+ irssi/src/silc/core/silc-channels.c
+ lib/silcclient/client_keyagr.c
+ irssi/docs/help/key
+
+Sat Nov 3 17:48:55 EET 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added silc_pkcs_public_key_compare to compare two
+ public keys. Affected file lib/silccrypt/silcpkcs.[ch].
+
+ * Check that the client who set the founder mode on the
+ channel is the same client that is giving the founder
+ mode to itself. It is done by comparing the saved public
+ key (it is saved even in the authentication is passphrase).
+ Affected file silcd/command.c.
+
+Fri Nov 2 18:52:08 EST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Do not process packet for disconnected socket connection.
+ Affected file lib/silccore/silcpacket.c.
+
+ * Process the DISCONNECT packet through scheduler in the
+ client library. Affected file lib/silcclient/client.c.
+
+ * Fixed the silc_client_packet_parse to not to increase
+ the packet sequence number if the conn->sock and the
+ current socket connection is not same. This can happen
+ for example during key agreement when the conn includes
+ multiple socket connections (listeners). Affected file
+ lib/silcclient/client.c.
+
+ * The sender of the file transfer request now provides also
+ the pointer (listener) for the key exchange protocol. If
+ the listener cannot be created then it sends empty key
+ agreement and lets the receiver provide the listener.
+
+ Added `local_ip' and `local_port' arguments to the
+ silc_client_file_send. If they are provided they are used,
+ if not then it will attempt to find local IP address, if
+ not found or bind fails then the remote client will provide
+ the listener.
+
+ Affected files are lib/silcclient/client_ftp.c and
+ lib/silcclient/silcapi.h.
+
+ * Extended the FILE SEND command to support defining the
+ local IP and port for key exchange listener. They are
+ optional. Affected file irssi/src/silc/core/silc-servers.c.
+
+Thu Nov 1 22:10:07 EST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Defined to WHOIS command reply the sending of fingerprint
+ of the client's public key (if the proof of posession of the
+ corresponding private key is verified by the server).
+ Updated to the protocol specification.
+
+ * Added support of receiving the client's public key's
+ fingerprint in command reply in client library. Affected
+ file is lib/silcclient/command_reply.c, and
+ lib/silcclient/idlist.[ch].
+
+Thu Nov 1 18:06:12 EST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Do not send over 128 chars long nickname to the server
+ in NICK command. Affected file lib/silcclient/command.c.
+
+ * Do not send over 256 chars long channel names to the server
+ in JOIN command. Affected file lib/silcclient/command.c.
+
+Tue Oct 30 22:48:59 EST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Assure that silc_server_close_connection cannot be called
+ twice for same socket context. Affected file is
+ silcd/server.c.
+
+Tue Oct 30 16:58:14 EST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Send error message to application if opening file for
+ writing during file transfer fails. Affected file is
+ lib/silcclient/client_ftp.c.
+
+ Remove all file transfer sessions for a client that we're
+ removing from ID cache.
+
+ Affected file is lib/silcclient/client_ftp.c.
+
+ * Fixed silc_net_addr2bin to return correct address. Affected
+ file lib/silcutil/[unix/win32]/silc[unix/win32]net.c.
+
+ * Fixed file transfer session removing on signoff notify.
+ Affected file irssi/src/silc/core/silc-servers.c.
+
+ * Added the SilcClientFileError to be returned in the monitor
+ callback. Added NO_SUCH_FILE and PERMISSION_DENIED errors.
+ Affected file lib/silcclient/silcapi.h.
+
+Mon Oct 29 17:43:04 EST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed a crash in silc_client_ftp_free_sessions and
+ silc_client_ftp_session_free_client. Affected file
+ lib/silcclient/client_ftp.c.
+
+ * Added `disabled' field in the SilcChannelEntry in the server
+ to indicate if the server entry is disabled. Affected file
+ silcd/idlist.h, silcd/command[_reply].c.
+
+ * SILC server adds now /var/run/silcd.pid everytime it is
+ started. Affected file silcd/silcd.c.
+
+ * Added silc_server_packet_send_clients to send a packet to
+ the provided table of client entries. Affected file
+ silcd/packet_send.[ch].
+
+ * Fixed a crash in client resolving in client_prvmsg.c in
+ client library. Affected file lib/silcclient/client_prvmsg.c.
+
+ * Do not actually remove the client directly from ID cache
+ during SERVER_SIGNOFF, but invalidate it. This way we
+ preserve the WHOWAS info for the client. Affected file
+ silcd/server_util.c.
+
+ * Fixed SERVER_SIGNOFF notify handling in the server. The
+ server is now able to process incoming SERVER_SIGNOFF notify
+ for a server that it doesn't even know about. It will remove
+ the clients provided in the notify. Affected file
+ silcd/packet_receive.c.
+
+ * Check for partial packet in data queue after every packet that
+ was found from the queue. Return and wait for more data if
+ there is partial data in queue. Affected file is
+ lib/silccore/silcpacket.c.
+
+Sun Oct 28 18:46:27 EST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added SilcClietFileError enum to indicate error in
+ file transfer. Added SILC_CLIENT_FILE_MONITOR_KEY_AGREEMENT
+ and SILC_CLIENT_FILE_MONITOR_ERROR new monitor statuses.
+ Affected files lib/silcclient/silcapi.h and
+ lib/silcclient/client_ftp.c.
+
+ * Check that newsize in silc_buffer_realloc is larger than
+ the old buffer's size. Affected file lib/silcutil/silcbufutil.h.
+
+ * Added better monitor of file transfers. It now monitors
+ key agreement protocol during the file transfer too. Added
+ error reporting too. Affected files
+ irssi/src/silc/core/silc-servers.c,
+ irssi/src/fe-common/silc/module-formats.[ch].
+
+ * Wrote a help file for FILE command.
+
+ * Added silc_rng_global_get_byte_fast to get not-so-secure
+ random data as fast as possible. Random data is read from
+ /dev/urandom if available and from the SILC RNG if not
+ available. It is used in padding generation. Affected file
+ lib/silccrypt/silcrng.[ch].
+
+ * All packets in client library are now processed synchronously.
+ Optimized packet processing a lot. Affected file
+ lib/silcclient/client.c.
+
+ * All server connection packets are processing synchronously
+ now in server, to optimize packet processing. Affected file
+ silcd/server.c.
+
+ * Include files are installed now only in Toolkit distribution
+ if make install is given. Affected files: all Makefile.am's.
+
+Thu Oct 25 22:44:06 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Assure that silc_client_notify_by_server_resolve does not
+ resolve the client information multiple times. If it cannot
+ be found by the first it cannot be found at all. Affected
+ file lib/silcclient/client_notify.c.
+
+ * Fixed WHOWAS command reply calling. Affected file
+ lib/silcclient/command_reply.c.
+
+ * Removed all references to silc_idlist_get_client from the
+ Irssi SILC client since that call is internal call used by
+ the library. The Irssi SILC client will use now client
+ retrieval functions found in silcapi.h.
+
+ * Fixed a bug in resolving nickname info before sending
+ private message. It used freed memory. Affected file
+ irssi/src/silc/core/silc-servers.c.
+
+Thu Oct 25 19:04:49 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Assure my_channels statistics cannot go negative in server.
+ Affected files silcd/server.c, silcd/server_util.c.
+
+Wed Oct 24 19:53:05 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Upgraded dotconf 1.0.2 to 1.0.6 in lib/dotconf.
+
+Tue Oct 23 13:51:19 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Win32 Toolkit changes. Affected files
+ win32/silc.dsw, win32/libsilc/libsilc.def,
+ win32/libsilcclient/libsilc.def,
+ lib/silcutil/silcutil.c, and
+ lib/sftp/sftp_fs_memory.c.
+
+Mon Oct 22 16:35:05 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added silc_net_localip to return local host's IP address.
+ Affected file lib/silcutil/silcnet.[ch].
+
+ * If key exchange or rekey protocol is active for a connection
+ parse all packets syncronously since there might be packets
+ in packet queue that we are not able to process without first
+ processing packets before them. Affected file silcd/server,
+ lib/silcclient/client.c.
+
+ * SilcPacketParserCallback now returns TRUE or FALSE to indicate
+ whether library should continue processing the packet.
+ Affected file lib/silccore/silcpacket.h.
+
+ * Added SilcSFTPMonitor callback, SilcSFTPMonitors and
+ SilcSFTPMonitorData to SFTP server to monitor various
+ SFTP client requests. Affected file lib/silcsftp/silcsftp.h,
+ lib/silcsftp/sftp_server.c.
+
+ * Added silc_file_size to return file size. Affected file
+ lib/silcutil/silcutil.[ch].
+
+ * Implemented the file transfer support for the client library.
+ Added preliminary support for simple client to client one-file
+ transmission. Affected file lib/silcclient/client_ftp.c,
+ lib/silccilent/client.[ch].
+
+ * Added new local command FILE to the Irssi SILC Client.
+ It is used to perform the file transfer. It has subcommands
+ SEND, RECEIVE, SHOW and CLOSE. Affected files
+ irssi/src/silc/core/client_ops.c,
+ irssi/src/silc/core/silc-server.[ch].
+
+Mon Oct 22 12:50:08 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Relay the SILC_PACKET_FTP in the server. Affected files
+ silcd/server.c and silcd/packet_receive.c.
+
+Sun Oct 21 20:21:02 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Renamed silc_file_read and silc_file_write to functions
+ silc_file_readfile and silc_file_writefile. Added function
+ silc_file_open and silc_file_close. Affected files
+ lib/silcutil/silcutil.[ch].
+
+Thu Oct 18 20:58:13 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Resolve the client info when received private message or
+ channel message for a client which nickname we don't know.
+ Affected files lib/silcclient/client_prvmsg.c and
+ lib/silcclient/client_channel.c.
+
+ * Do not crash in /KEY if client is not connected. Affected
+ file irssi/src/silc/core/silc-channels.c.
+
+ * Added SilcClientStatus field to the SilcClientEntry in the
+ lib/silcclient/idlist.h.
+
+ Added SILC_CLIENT_STATUS_RESOLVING to mark that the entry
+ is incomplete and is being resolved, it won't be resolved
+ twice.
+
+ Make sure also that USERS command reply does not resolve
+ twice information. Affected file is
+ lib/silcclient/command_reply.c.
+
+ Make sure that silc_client_get_clients_by_list does not
+ resolve twice same information.
+
+ * Check for valid client->id in the silc_server_free_client_data.
+ Affected file silcd/server.c.
+
+ * Fixed /GETKEY nick@server not to crash if the server entry
+ is not found. Affected file lib/silcclient/command.c.
+
+ * Fixed the silc_server_check_cmode_rights to check the
+ requested modes correctly. Affected file silcd/command.c.
+
+Thu Oct 18 12:10:22 CEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Better checks for non-printable chars in nick added.
+ Affected file silcd/command.c.
+
+Thu Oct 18 09:18:58 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Call the silc_server_udpate_servers_by_server in the
+ primary router that comes back online in the backup resuming
+ protocol. Otherwise it routes packets wrong. Affected file
+ silcd/server_util.[ch], silcd/server_backup.c.
+
+Wed Oct 17 16:51:18 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added SILC_STR_UI8_[N]STRING[_ALLOC] formats to the
+ lib/silcutil/silcbuffmt.[ch].
+
+ * Redefined the SILC packet header to include the padding
+ length. Affected file lib/silccore/silcpacket.[ch].
+
+ * Added SILC_PACKET_PADLEN_MAX macro to return the padding
+ length for maximum padding up to 128 bytes). Affected
+ file lib/silccore/silcpacket.h.
+
+ * Removed all backwards support for old 0.5.x MAC thingies.
+ The SILC packet header change makes it impossible to be
+ backwards compatible.
+
+ * Send the ENDING packet with timeout in the backup resuming
+ protocol. This is to assure that all routers has connected
+ to the primary router. Affected file silcd/server_backup.c.
+
+ * Changed the RNG to take the first IV from random data. It
+ used to take it from zero actually. Changed the RNG also
+ to use /dev/urandom during session. /dev/random is used
+ in initialization. Affected file lib/silccrypt/silcrng.[ch].
+
+Tue Oct 16 20:45:49 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Changed the SILC packet header to have the first two bytes
+ (the packet length) encrypted. Affected files aroung the
+ code tree, lib/silccore/silcpacket.[ch]. Removed the
+ SilcPacketCheckDecrypt callback. It is not needed anymore
+ since the silc_packet_receive_process will determine now
+ whether the packet is normal or special.
+
+ * Implemented the unidirectional MAC keys. Affected files
+ lib/silcske/silcske.c, silcd/protocol.c and
+ lib/silcclient/protocol.c.
+
+ * Implemented the packet sequence number to the MAC computation.
+ Affected files lib/silccore/silcpacket.c, silcd/protocol.c,
+ silcd/packet_send.c, silcd/server.c, lib/silcclient/client.c,
+ lib/silcclient/protocol.c.
+
+Mon Oct 15 17:42:55 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Allow backup router to announce servers. All servers
+ announced by backup router are added to the global list
+ automatically. Update hte server's socket to our primary
+ router also when backup router announces a server.
+ Affected file silcd/packet_receive.c.
+
+ * Do not update the client->router in the function
+ silc_server_udpate_clients_by_server if the client is on
+ global list. We might fail to find any specific server
+ for locally connected clients and local cell clients. They
+ should still use the `from' and not `to' as client->router.
+ This fixes backup router resuming protocol. Affected file
+ silcd/server_util.c.
+
+ * Decrease channel statistics count only if the channel
+ deletion worked. Affected files are silcd/server.c and
+ silcd/server_util.c.
+
+ * Added silc_server_update_servers_by_server to update origin
+ of all server entries. Used during backup router protocol.
+ Affected files silcd/server_util.[ch], silcd/server.c. and
+ silcd/backup_router.c.
+
+ * ROBODoc documented the lib/silccrypt/silchmac.h. Added new
+ function silc_hmac_init, silc_hmac_update, silc_hmac_final,
+ silc_hmac_get_hash and silc_hmac_get_name. Affected file
+ lib/silccrypt/silchmac.c.
+
+Sun Oct 14 18:28:22 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Assure that router cannot reroute the same channel message
+ to the sender. Affected file silcd/packet_receive.c.
+
+Sat Oct 13 12:46:18 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Made better checks that the channel message is not sent
+ to the router it came from. Affected file is
+ silcd/packet_send.c. Fixed memory leak too.
+
+ * Announce informations for incoming router connection, but
+ only after checking if it is replaced by backup router.
+ Affected file silcd/packet_receive.c.
+
+Fri Oct 12 18:37:24 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed the backup resuming protocol to work in multiple
+ router environment. Affected file silcd/server_backup.c.
+
+ * Route packet only to one router in the function
+ silc_server_packet_send_to_channel. Affected file is
+ silcd/packet_send.c.
+
+ * Fixed silc_server_send_notify_dest to set the broadcast
+ flag. Fixed the silc_server_send_notify_topic to actually
+ send the TOPIC_CHANGE notify and not SERVER_SIGNOFF notify.
+ Affected file silcd/packet_send.c.
+
+ * Changed the SFTP Filesystem interface. Changed the
+ SilcSFTPFilesystemStruct to SilcSFTPFilesystemOps to include
+ the filesystem operation function. The SilcSFTPFilesystem
+ is now a context that is allocated by all filesystem allocation
+ functions and it already includes the operations structure
+ and filesystem specific context. It is given as argument
+ now to the silc_sftp_server_start. This made the interface
+ a bit cleaner. Affected file lib/silcsftp/silcsftp[_fs].h,
+ lib/silcsftp/sftp_fs_memory.c and sftp_server.c.
+
+Thu Oct 11 22:19:26 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Changed the backup router adding and getting interfaces
+ in the server. The router that will be replaced by the
+ specified backup router is now sent as argument. Affected
+ files silcd/serverconfig.[ch], silcd/backup_router.[ch], and
+ silcd/server.c.
+
+ * Added silc_net_addr2bin_ne to return the binary form of
+ the IP address in network byte order. Affected files
+ lib/silcutil/[unix/win32].silc[unix/win32]net.[ch].
+
+Thu Oct 11 12:14:19 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Check for existing server ID in silc_server_new_server
+ and in silc_server_connect_to_router_final and remove the
+ old entry if it exists. Affected file silcd/packet_receive.c,
+ silcd/server.c.
+
+ * Send the channel message always to only one router, either
+ in upstream or downstream. Affected file is
+ silcd/packet_send.c.
+
+Tue Oct 9 17:45:43 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Wrote the definition of the backup resuming protocol to the
+ protocol specification.
+
+ * Removed one redundant channel key generation from normal
+ server during joining procedure. Removed one redundant
+ channel key sending from server to router during joining
+ procedure. Affected file silcd/command.c.
+
+ * Made minor bugfixes to the backup router resuming protocol.
+ Affected file silcd/server_backup.c, server.c.
+
+Mon Oct 8 16:47:42 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added --disable-asm configuration option. Affected files
+ configure.in.pre, lib/silcmath/mpi/configure.in. A patch
+ by salo.
+
+ * Implemented the backup resuming protocol that is used to
+ resume the primary router position in the cell after the
+ primary router comes back online. Affected files
+ silcd/server_backup.[ch], silcd/server, silcd/packet_receive.c,
+ and silcd/server_util.[ch].
+
+Sun Oct 7 12:29:25 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Sleep two (2) seconds after sending QUIT command to server.
+ Affected file lib/silcclient/command.c.
+
+ * Assure that if outgoing data buffer is pending do not force
+ send any data. Affected file silcd/packet_send.c.
+
+ * Assure that if outgoing data buffer is pending do not force
+ send any data. Affected file lib/silcclient/client.c.
+
+ * Implemented the backup router support when the primary router
+ goes down. The servers and routers can now use the backup
+ router as new primary router without loosing connectivity.
+
+Sat Oct 6 21:18:54 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added new SILC_IDLIST_STATUS_DISABLED flag for entries
+ in the server to indicate disabled entry. All data read
+ from the connection will be ignored and no data is sent
+ for entry that is disabled. Affected files are
+ silcd/idlist.h, silcd/server.c.
+
+Fri Oct 5 00:03:29 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Created SFTP client and server test programs in the
+ lib/silcsftp/tests directory.
+
+Wed Oct 3 23:31:42 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Implemented memory filesystem (virtual filesystem) for
+ SFTP server. Affected file lib/silcsftp/silcsftp_fs.h,
+ sftp_fs_memory.c.
+
+Sun Sep 30 22:10:57 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Implemented the SFTP (SSH File Transfer Protocol) to the
+ lib/silcsftp. It includes SFTP client and SFTP server
+ implementations.
+
+Sun Sep 30 10:35:44 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Moved lib/silccore/silcprotocol.[ch] to the
+ lib/silcutil library.
+
+ * Added silc_buffer_format_vp and silc_buffer_unformat_vp to
+ take variable argument list pointer as argument. Affected
+ file lib/silcutil/silcbuffmt.[ch].
+
+ * Added silc_buffer_set function that is used to set data
+ to a SilcBuffer that is not allocated at all (SilcBufferStruct).
+ Affected file lib/silcutil/silcbuffer.h.
+
+ * Changed various routines in the core library to use the new
+ silc_buffer_set instead of allocating new buffer only for
+ temporary purposes.
+
+ * Added 64-bit value formatting and unformatting support to the
+ silc_buffer_[un]format routines. Affected file is
+ lib/silcutil/silcbuffmt.[ch].
+
+ Added also 64-bit macros: SILC_GET64_MSB and SILC_PUT64_MSB,
+ to includes/bitmove.h.
+
+Fri Sep 28 21:30:10 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed channel user mode saving in client library. Affected
+ file lib/silcclient/command[_reply].c.
+
+Thu Sep 27 22:52:30 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Defined the file transfer to the SILC Protocol. Added
+ new packet type SILC_PACKET_FTP and defined File Transfer
+ Payload. The mandatory file transfer protocol is SFTP
+ (SSH File Transfer Protocol). Affected file in addition
+ of the internet draft is lib/silccore/silcpacket.h.
+
+ * Deprecated the SILC_PACKET_CELL_ROUTERS and defined new
+ packet SILC_PACKET_RESUME_ROUTER instead. The new packet
+ is used as part of backup router protocol when the primary
+ router of the cell is back online and wishes to resume
+ the position as primary router.
+
+ * Redefined the MAC generation keys in the protocol. The
+ same key is not used anymore in both direction. Both
+ direction will now use different keys for sending and
+ receiving. This fixes a potential security flaw. This
+ change causes incompatibilities in the protocol.
+
+ * Redefined also the MAC computation from the packet.
+ An packet sequence number is now added to the MAC
+ computation. This prevents possible replay attacks against
+ the protocol. This change too causes incompatibilities
+ in the protocol.
+
+ Added `sequence' field to the SilcPacketContext to hold
+ the current sequence number for the packet.
+
+Wed Sep 26 20:15:22 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added `created' field to the SilcIDListData in the file
+ silcd/idlist.h to indicate the time when the entry was
+ created.
+
+ * Added `created' field to the SilcChannelEntry too. Affected
+ file silcd/idlist.h.
+
+ * Added `creation_time' aguments to all the announcement functions
+ in the server. If it is provided then only the entries that
+ was created after the provided time frame are actually
+ announced. Affected file silcd/server.[ch].
+
+ * The protocol says that the Channel ID's IP address must be
+ based on the router's IP address. Added check for this in
+ the silc_server_new_channel when processing incoming New Channel
+ Payload. Affected file silcd/packet_receive.c.
+
+ * Print out the correct version with --version in SILC client.
+ Affected file irssi/src/silc/core/silc-core.c.
+
+Mon Sep 24 17:19:00 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed WHOWAS command to check for completnes of the client
+ entry always, not just when the command is coming from client.
+ Affected file silcd/command.c.
+
+ * Added new function silc_server_packet_queue_purge to purge the
+ outgoing data queue to the network. After the function returns
+ it is guaranteed that the outgoing packet queue is empty.
+ Affected file silcd/packet_send.[ch].
+
+ * Purge the outgoing packet queue in the rekey protocol's final
+ callback to assure that all rekey packets go to the network
+ before quitting the protocol. Affected file silcd/server.c.
+
+ * Added silc_client_packet_queue_parse as similar function as
+ in server to the client library. The affected file is
+ lib/silcclient/client.c.
+
+Sun Sep 23 15:15:53 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Splitted silcd/server.c and created silcd/server_util.[ch]
+ for utility functions.
+
+ * Added new socket flag SILC_SF_DISABLED to indicate that the
+ connection is open but nothing can be sent to or received from
+ the connection. Affected file lib/silcutil/silsockconn.[ch].
+ The checking for disabled socket is checked in the low level
+ silc_socket_write and silc_socket_read functions.
+
+Thu Sep 20 23:11:28 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Allow only nicknames and channel names that fits into the
+ 7-bit unsigned char ASCII set. Affected file silcd/command.c.
+
+Thu Sep 20 18:04:12 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * When processing JOIN command reply in server check that if
+ the channel exists in our global list we'll move it the local
+ list. Affected file silcd/command_reply.c.
+
+ * Fixed the check whether client is joined on the channel already
+ in JOIN command. Affected file lib/silcclient/command.c.
+
+ * Fixed the JOIN command reply to check whether the channel
+ already exists. Affected file lib/silcclient/command_reply.c.
+
+Wed Sep 19 22:58:32 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added silc_ske_status_string to map the SKE error numbers
+ to readable strings. The affected files are
+ lib/silcske/silcske[_status].[ch].
+
+Tue Sep 18 22:50:41 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Do not show the private channels on the WHOIS channel list
+ as it is not allowed by the protocol. The affected file is
+ silcd/server.c.
+
+Sun Sep 16 12:32:58 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Assure that the packet length digged from the actual packet
+ is something sensible in the silc_packet_decrypt_rest_special
+ in lib/silccrypt/silcpacket.c.
+
+ * Free and NULL the allocated pointer in silc_hmac_alloc if
+ the HMAC allocation fails. The affected file is
+ lib/silccrypt/silchmac.c.
+
+ * Print the selected security properties to the log files in
+ the server. Affected file silcd/protocol.c.
+
+ * Add SKE's reference counter even if calling the completion
+ callback manually. Otherwise it goes negative, although it
+ does not cause any problems. The affected file is
+ lib/silcske/silcske.c.
+
+ * Remove the client entry with short timeout after giving the
+ KILL command. Affected file lib/silcclient/command.c.
+
+ * Fixed to send error reply in WHOIS and IDENTIFY commands in
+ case all found clients are already disconnected (WHOWAS would
+ found them) in the server. Affected file silcd/command.c.
+
+ * Update the last_receive (time of last data received) to be
+ updated only when received private or channel message so that
+ the idle time showed in WHOIS makes more sense.
+
+ * Added boolean field `valid' in to the SilcClientEntry in the
+ client library to indicate whether the entry is valid or not.
+ This fixes the nickname change bug on channel when changing
+ the nickname to be same than the old (like nick to Nick) the
+ nickname formatter doesn't set the new nick anymore to Nick@host.
+ Affected file lib/silcclient/idlist.[ch].
+
+ * Now actually fixed the nickname changing on disconnection.
+ Added new function silc_change_nick to the Irssi SILC Client.
+ Affected file irssi/src/silc/core/client_ops.c,
+ irssi/src/silc/core/silc-nicklist.[ch].
+
+Sat Sep 15 13:29:17 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Check that the public key exists in the GETKEY command before
+ trying to encode it. Affected file silcd/command.c.
+
+ * Print some notifications on received public keys with GETKEY
+ command in the Irssi SILC Client. Affected files are
+ irssi/src/fe-common/silc/module-formats.[ch],
+ irssi/src/silc/core/client_ops.c.
+
+ * Use IDENTIFY command to resolve the server information in the
+ GETKEY command instead of INFO command. Affected file
+ lib/silcclient/command.c.
+
+ * All command reply functions in the client library now calls
+ the pending command reply callbacks even if an error has
+ occurred. The server has done this a long time and now it was
+ time to move the client library to this as well. Now all
+ errors can be delivered back to the pending command reply
+ callbacks if necessary. Affected files are
+ lib/silcclient/command[_reply].[ch].
+
+ * Change the nickname on disconnection back to the username
+ because in reconnect the server will enforce it to it anyway.
+ Affected file irssi/src/silc/core/silc-servers.c.
+
+ * Fixed a config file parsing bug in the Irssi SILC client.
+ Affected file irssi/src/silc/core/clientconfig.c.
+
+Thu Sep 13 23:11:18 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * When printing the channel mode on JOIN, verify that the
+ channel key and channel's HMAC are valid. Affected file
+ irssi/src/silc/core/client_ops.c.
+
+Thu Sep 13 20:24:52 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added defines SILC_DEFAULT_CIPHER, SILC_DEFAULT_HMAC,
+ SILC_DEFAULT_HASH and SILC_DEFAULT_PKCS in the file
+ lib/silccrypt/[silccipher.h|silchmac.h|silchash.h|silcpkcs.h].
+
+ * Removed channel key rekey task deleting from the function
+ silc_server_save_channel_key. Affected file silcd/server.c.
+ Added explicit timeout task context instead that is used to
+ delete the task if we are registering a new task before the
+ new task has elapsed.
+
+ * When channel key rekey occurs the client library now saves
+ the old channel key for a short period of time (10 seconds) and
+ is able to use it in case some is still sending channel
+ messages encrypted with the old key after the rekey. Affected
+ file lib/silcclient/[idlist.h|client_channel.c].
+
+Sun Sep 9 15:49:16 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added check to the silc_server_new_id_real to not accept
+ new ID if it is the sender's own ID. Affected file is
+ silcd/packet_receive.c.
+
+ * Assure that we do not announce ourself or the one we've
+ sending our announcements when we're router and are announcing
+ servers to our primary router. Affected file silcd/server.c.
+
+ * Fixed silc_server_command_identify_check_client to assemble
+ correct WHOIS packet. It send corrupted WHOIS packet and
+ caused problem with router to router connections. Affected
+ file silcd/command.c.
+
+ Fixed also silc_server_command_whois_check the same way
+ as for the IDENTIFY command.
+
+ * Added new SilcIDListStatus to the server in the SilcIDListData
+ structure. The status now includes the current status of
+ the entry (like registered, resolved etc.). Affected file
+ silcd/idlist.[ch]. Defined a bunch of different status types
+ as well. This replaced the old boolean registered field as well.
+
+ Added resolve_cmd_ident field to the SilcClientEntry structure
+ too so that if the entry is for example being resolved so
+ another command may attach to the same pending command reply
+ without requiring to resolve the same entry again. This concept
+ should optimize the WHOIS and the IDENTIFY resolving under
+ heavy load by taking away unnecessary resolving for entries
+ that are being resolved already.
+
+ Added support for adding multiple pending commands for one
+ command idenfier. Affected file silcd/command[_reply].[ch].
+
+ * Fixed WHOIS and IDENTIFY save to remove the cache entry
+ before deleting the data. Otherwise the hash table will have
+ freed data in comparison functions. Affected file is
+ silcd/command_reply.c.
+
+ * Fixed silc_idlist_replace_client_id to add the new entry to
+ the cache with NULL nickname. Otherwise there will be invalid
+ memory as the nickname after the nickname is freed. Affected
+ file silcd/packet_receive.c.
+
+ * Fixed the silc_idlist_get_clients_by_hash. The entries was
+ saved into wrong slots because the previous number of entries
+ was not taken into account. Affected file silcd/idlist.c.
+ Fixed same thing in silc_idlist_get_clients_by_nickname too.
+
+ * If we are router and we receive JOIN notify to a channel that
+ does not have any users then notified client is marked as the
+ channel founder, as it is it. The affected file is
+ silcd/packet_receive.c
+
+ * Added to the extended hash table API's table_del_*ext functions
+ the destructor as argument too, so that the caller can decide
+ which destructor to use or whether to use destructor at all.
+ Affected file lib/silcutil/silchashtable.[ch].
+
+ * Fixed ID Cache purging. It actually deleted the entries from
+ the hash table after the data was freed. The hash table ended
+ up comparing freed memory. The affected file is
+ lib/silccore/silcidcache.c.
+
+Sat Sep 8 10:22:10 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed Irssi SILC client's KILL command's HELP syntax.
+
+ * The USERS command now resolves the detailed user information
+ if the userinfo field is missing. Affected file is
+ lib/silcclient/command_reply.c.
+
+ * Do not print error in silc_file_read if the read file does
+ not exist. Just silently return NULL. Affected file is
+ lib/silcutil/silcutil.c.
+
+ * Fixed the silc_log_output to not wine about NULL filename
+ and to not create some bogus " " filename. Affected file is
+ lib/silcutil/silclog.c.
+
+Fri Sep 7 22:16:38 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed various printing bugs on the user interface in the
+ Irssi SILC Client. Minor changes that were forgotten from
+ the release.
+
+Fri Sep 7 17:28:37 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed the configure.in.pre and the compilation and distribution
+ environment to support the new autoconf 2.52. That version is
+ now required to compile the CVS trunk.
+
+Thu Sep 6 12:47:37 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Renamed function silc_parse_nickname to silc_parse_userfqdn
+ to generally parse user@fqdn format strings. Affected file
+ lib/silcutil/silcutil.c.
+
+ * Added nickname_format and nickname_force_format fields to the
+ SilcClientParams structure. The first one defines the format
+ for the nicknames that the library will enforce if the receives
+ multiple same nicknames. The second one is boolean value and
+ can be used to force the library to always enforce the format
+ to the nicknames regardles whether there are multiple nicknames
+ or not. This configurable formatting was employed to flexibly
+ support accessing multiple nicknames from the user interface.
+ The userinterface can now set the nicknames to what ever format
+ they prefer. Affected file lib/silcclient/silcapi.h.
+
+ Added function silc_client_nickname_format to the file
+ lib/silcclient/idlist.c. It performs the nickname formatting.
+
+ Added new field `hostname´ to the SilcClientEntry context.
+ It holds the hostname of the client. Affected file is
+ lib/silcclient/idlist.h.
+
+ * Irssi SILC Client sets the nicknames in nick@hostn format.
+ Fe. priikone@otaku, priikone@otaku2 etc. Affected file
+ irssi/src/silc/core/silc-core.c.
+
+ The WHOIS printing now also shows both the real nickname and
+ the formatted nickname so that user knows how to access the
+ user if there are multiple same nicknames cached. Affected
+ file irssi/src/silc/core/client_ops.c. Changed the WHOIS
+ printing formatting too to take the hostname now as a separate
+ argument. The Affected file is
+ irssi/src/fe-common/silc/modules-formats.[ch].
+
+ * Changed the silc_client_get_clients_local to accept the formatted
+ nickname as argument. It accepts the real nickname too but the
+ formatted nickname can be used to find the true entry from
+ multiple entries. Affected file lib/silcclient/silcapi.h and
+ lib/silcclient/idlist.c.
+
+ * Added nickname_format_parse field to the SilcClientParams.
+ It is a callback function provided by the application to parse
+ the nickname out of the formatted nickname string. The library
+ calls it to get the nickname from the formatted string. Since
+ the application generally knows better the format of the nickname
+ string it parses it instead of the library, even though library
+ encodes the formatted string. If the callback function is not
+ provided then the library will use the string as is. The
+ affected file is lib/silcclient/silcapi.h.
+
+ * All the nickname strings passed to the client library in
+ commands are now expected to be formatted nickname strings.
+ If the command does not support the formatted nickname string
+ it will assume that the sent string is the actual nickname.
+ Affected file lib/silcclient/command.c.
+
+Tue Sep 4 22:31:28 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added public key authentication support to OPER and SILCOPER
+ commands in the client library. Affected file is
+ lib/silcclient/command.c.
+
+Tue Sep 4 12:39:17 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Changed the get_auth_methdod client operation to be asynchronous.
+ It can be async if the application resolves the authentication
+ method from the server during the negotiation. Added new
+ SilcGetAuthMeth completion callback that the application will
+ call after resolving the authentication method.
+
+ Added function silc_client_request_authentication_method that
+ the application can use to resolve the authentication method
+ from the server. Added also SilcConnectionAuthRequest callback
+ that the library will call after the server has replied. The
+ application can call this function if it does not know the
+ current authentication method.
+
+ Affected files are lib/silcclient/client.c and
+ lib/silcclient/silcapi.h.
+
+ * The Irssi SILC client now automatically resolves the authentication
+ method incase any configuration information is not present (and
+ currently there never is). The affected file is
+ irssi/src/silc/core/client_ops.c.
+
+ * Fixed public key authentication from the client library.
+ Affected file lib/silcclient/protocol.c. Changed also the
+ protocol specification about the public key authentication in
+ the connection authentication protocol. The actual data to be
+ signed is now computed with a hash function before signing.
+
+ * Fixed the public key authentication from the server as well.
+ Affected file silcd/protocol.c.
+
+ * Removed the mlock()'s from the memory allocation routines.
+ Affected file lib/silcutil/silcmemory.c. The ./configure does
+ not check anymore for the mlock(). Affected file is
+ configure.in.pre.
+
+ * Fixed USERS command in server to allow the execution of the
+ command for private and secret channels if the client sending
+ the command is on the channel. Affected file silcd/command.c.
+
+ * Fixed silc_client_get_clients_local to return the clients
+ count correctly. It could return wrong value. Affected file
+ lib/silcclient/idlist.c.
+
+Mon Sep 3 20:09:59 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed the lib/silcmath/mpi/mpi.h to always use 32-bit data
+ types. The assembler optimizations seemed not to like 64-bit
+ data types. The assmebler optimizations thus are now enabled
+ also for BSD systems as opposed to only enable them for Linux.
+
+ * Do not check for threads at all on BSD systems. Affected
+ file configure.in.pre.
+
+ * Removed -n and -h options from the Irssi SILC Client since
+ they are not used in silc.
+
+ * Fixed the prime generation to assure that the first digit
+ of the generated random number is not zero since our conversion
+ routines does not like number strings that starts with zero
+ digit. If zero digit is seen the random number is regenerated.
+ This caused some corrupted RSA keys when the zero first digit
+ was met. Affected file lib/silcmath/silcprimegen.c.
+
+Sun Sep 2 17:17:24 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed WIN32 configuration in the ./configure script.
+ Fixed to include xti.h on environments that has it.
+ Patches by Carsten Ilchmann and andrew.
+
+Sat Sep 1 00:29:33 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Changed the silc_id_create_client_id to be collision
+ resistant. It is now assured that there cannot be created
+ two same client ID's. I suspect that some weird bugs in
+ the server were actually caused by duplicate Client IDs.
+ Affected file silcd/serverid.[ch]. A router receiving
+ new ID now also assures and informs the sending server
+ if the ID caused collision.
+
+ * Changed the silc_id_create_channel_id to also assure that
+ there are no collisions.
+
+Wed Aug 29 17:55:01 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Statement about ignoring the Mutual Authentication flag when
+ performing rekey with PFS was a bit misleading. It is ignored
+ if it was set in the initial negotiation, it cannot be even
+ set in the rekey. Fixed in the ke-auth draft. Started the
+ new versions of the protocol drafts in the doc/.
+
+Sun Aug 26 14:59:15 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed a bug in silc_client_command_identify_save when saving
+ new channel information. The channel name was no duplicated
+ and caused crash on exit. Affected file is
+ lib/silcclient/command_reply.c.
+
+Fri Aug 17 23:07:45 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed the getkey command handling in the server. Send just
+ empty OK reply to the sender if the key could not be fetched
+ (but everything else was ok, like the key just was not available).
+ Changed the public key parameter to optional in the protocol
+ specs so that empty OK reply can be sent. Affected file
+ silcd/command.c.
+
+ Added a message to Irssi SILC client to tell to user if the
+ server did not return a public key.
+
+Tue Aug 14 07:29:27 CEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed a channel key regeneration bug. It registered new
+ timeout tasks exponentially until all system resources were
+ used. Affected file silcd/server.c.
+
+Sun Aug 12 20:48:14 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added the SILC Document generator to the scripts/silcdoc.
+ It can be used to generate the Toolkit Reference Manual out
+ of the source tree. Internally it will also use the RoboDoc
+ generator now imported in util/robodoc.
+
+Sun Aug 12 12:28:17 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added couple of return's in rekey protocol if error orccurred
+ during the protocol. The execution must be terminated.
+ Affected file silcd/protocol.c. Also, terminate the protocol
+ always with timeout.
+
+Sat Aug 11 12:36:02 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * The client's Client ID was created initally from the wrong
+ nickname (it could have been in format nick@host) in the
+ silc_server_new_client. Affected file silcd/packet_receive.c
+
+Sat Aug 11 00:29:57 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added some SILC_LOG_ERROR's to various error conditions
+ if client could not be added to ID cache. Affected files
+ silcd/packet_receive.c and silcd/server.c.
+
+ * When client's sock->user_data is freed, NULL also the
+ client->router and client->connection pointers. Added check
+ for these pointers being NULL to various places around the
+ code. Affected file silcd/server.c.
+
+ * Added client->data.registered == TRUE checks to various
+ places around the code to assure that unregistered client's
+ are not handled when it is not allowed. Affected file
+ silcd/server.c.
+
+ * Added `bool registered' fields to all
+ silc_idlist_[server|client]_get_* routines to indicate whether
+ the fetched client needs to be registered or not. Affected
+ file silcd/idlist.[ch].
+
+ * Add your own entry as registered to the ID cache in the
+ server. Affected file server.c.
+
+ * Fixed a bug in silc_server_new_server. The SilcServer was
+ set as the new server's context instead of SilcServerEntry.
+ This naturally caused some weird bugs.
+
+Thu Aug 9 18:28:37 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Do not delete the channel rekey task when adding it
+ for in silc_server_create_channel_key.
+
+ * Changed the silc_server_create_channel_key to return
+ TRUE or FALSE to indicate the success of the channel key
+ creation.
+
+Thu Jul 26 11:32:31 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed MSVC++ project files and added missing files to
+ Makefiles under win32/.
+
+Wed Jul 25 18:43:54 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Do not add TCP_NODELAY flag if the operating system
+ does not have it defined. Affected files are
+ lib/silcutil/[unix/win32]/silc[unix/win32]net.c.
+
+ * Fixed buffer overflow from Irssi SILC Client. Affected
+ file irssi/src/fe-common/core/themes.c.
+
+ * Fixed double free in client library in the file
+ lib/silcclient/client.c when disconnecting from server.
+
+ * Applied double free patch from cras to Irssi SILC client.
+ Affected files irssi/src/core/[modules/expandos].c
+
+ * Fixed the disconnection handling to Irssi SILC Client.
+ The application must call silc_client_close_connection
+ in ops->connect client operation in case of failure of
+ the connection. Affected file is
+ irssi/src/silc/core/client_ops.c.
+
+ * Do not set sock->protocol to NULL in the function
+ silc_client_close_connection after executing the protocol's
+ final callback since the sock might not be valid anymore.
+ Affected file lib/silcclient/client.c.
+
+Wed Jul 25 16:04:35 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Do not enable SILC_THREADS if the linking with libpthread
+ did not happen. Affected file configure.in.pre.
+
+ * Added notion to protocol specification that server must
+ verify the sent authentication payload with CMODE when
+ setting the channel founder key. Implemented it to the
+ server. Affected file silcd/command.c.
+
+Mon Jul 23 18:31:43 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added _EXTRA_DIST SILC distribution variable to the
+ distributions file. It is used to conditionally add extra
+ files or directories to the specific distribution. Affected
+ files ./prepare, Makefile.am.pre and distributions.
+
+ Removed the `_' from the start of the distribution names.
+ It is redundant.
+
+ * Added README.WIN32 for instructions to compile the Toolkit
+ under WIN32.
+
+Mon Jul 23 10:12:37 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed a double free in disconnection in the server. Affected
+ file is silcd/server.c.
+
+ * Fixed the lib/silcske/groups.c to work now also with GMP
+ MP library. The string conversion did not work when using
+ specific base and the base is indicated in the string as well.
+
+ * Created win32/ directory which now includes MSVC++ specific
+ stuff so that toolkit (DLLs) may be compiled with MSVC++.
+ It will appear only in the toolkit distribution
+
+Sun Jul 22 19:40:30 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Changed the key material distribution function in case when
+ the hash output is too short. The data is now concatenated
+ a bit differently than it used to. Made the change to the
+ SKE protocol specification.
+
+ * Added better GMP detection to configure.in.pre. A patch
+ by salo.
+
+Fri Jul 20 13:16:00 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed a minor bug in SKE that might cause some problem on
+ some platforms. Affected file lib/silcske/silcske.c.
+
+ * Added the cookie checking for initiator in the SKE. It checks
+ that the responder returns the sent cookie unmodified. The
+ affected file is lib/silcske/silcske.c. Added new SKE
+ error type INVALID_COOKIE that can be sent during the
+ negotiation. Fixed some memory leaks as well.
+
+ * Added the "invalid cookie" error message to Irssi SILC client's
+ message formats.
+
+Thu Jul 19 21:44:31 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added `task_max' field to the SilcClientParams to indicate
+ the maximum tasks the scheduler can handle. If set to zero,
+ default values are used. Affected file lib/silcclient/silcapi.h.
+
+ * Fixed memory leaks in silc_client_close_connection. Affected
+ file lib/silcclient/client.c.
+
+ * Added silc_client_del_client_entry to client library to free
+ all memory of given client entry. Affected file is
+ lib/silcclient/idlist.[ch].
+
+ * Added new functions silc_client_del_channel and
+ silc_client_del_server to delete channel and server entries.
+ Affected file lib/silcclient/[silcapi.h/idlist.c].
+
+ * Removed silc_client_del_client_by_id from silcapi.h.
+
+ * Fixed the INFO command to return the server's own info
+ correctly when querying by Server ID. Affected file is
+ silcd/command.c.
+
+Thu Jul 19 14:47:30 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Removed the non-blocking settings in WIN32 code in the
+ silc_sock_[read/write] and added SleepEx instead. Affected
+ file lib/silcutil/win32/silcwin32sockconn.c. The availability
+ of input data is now checked with FIONREAD and ioctlsocket.
+
+Wed Jul 18 18:34:01 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Call silc_schedule_task_del_by_context in the
+ silc_protocol_cancel instead of silc_schedule_task_del_by_callback.
+ Affected file lib/silccore/silcprotocol.c.
+
+ * Call silc_protocol_cancel for active protocols in the
+ silc_server_close_connection if the funtion
+ silc_server_free_sock_user_data has not been called.
+ Affected file silcd/server.c.
+
+ * Generic tasks cannot be deleted using the del_by_fd
+ task deleting function since generic tasks does not match
+ any specific fd. Affected file lib/silcutil/silcschedule.[ch].
+
+ * Added a notion to SILCOPER help file that the SILCOPER works
+ only on router server, not on normal server.
+
+Wed Jul 18 09:40:04 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added for WIN32 support for the new scheduler as well.
+ Affected file lib/silcutil/win32/silcwin32schedule.c.
+
+ * Fixed the SHA1 implementation to work on various platforms.
+
+Tue Jul 17 23:04:10 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Rewrote the SILC Scheduler entirely. Removed the old SILC Task
+ API. It is part of the scheduler now. Everything else is
+ as previously but some functions has changed their names.
+ Checkout the lib/silcutil/silcschedule.h for the interface.
+ Updated all applications to use the new interface. Affected
+ files are lib/silcutil/silcschedule.[ch].
+
+Tue Jul 17 16:53:30 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Found a bug in the SKE implementation. The HASH value,
+ specified by the protocol, was not computed correctly. The
+ public key of the responder was not added to the computation
+ even though it is mandatory. Affected file lib/silcske/silcske.c.
+ This unfortunately causes incompatibilities with older
+ clients and servers.
+
+ * Added WIN32 specific network init and uninit functions:
+ silc_net_win32_init and silc_net_win32_uninit to init and uninit
+ the Winsock2. Affected file lib/silcutil/silcnet.h and
+ lib/silcutil/win32/silcwin32net.c.
+
+ * Set the socket always to nonblocking mode on WIN32 after
+ reading data or writing data. Affected file is
+ lib/silcutil/win32/silcwin32sockconn.c.
+
+Mon Jul 16 22:55:26 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed various compilation problems under WIN32. Affected
+ files lib/silcutil/win32/silcwin32thread.c and
+ lib/silcutil/win32/silcwin32schedule.c.
+
+ * Removed all _internal.h #includes from public header
+ files. Internal headers must never be included from
+ public headers.
+
+ Removed also the lib/silcske/payload_internal.h file.
+
+ * All include files that may be needed (public and some others
+ included by the public headers) by application developers are
+ now copied to the ./includes directory. It does not copy any
+ internal headers. Affected file Makefile.defines.pre and all
+ Makefile.am's under lib/ and subdirs.
+
+Thu Jul 12 17:49:31 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Do not change the ~/.silc directory's permissions automatically.
+ Affected file irssi/src/silc/core/clientutil.c.
+
+Thu Jul 12 10:18:40 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Do not cancel the protocol in silc_server_close_connection
+ it might cause recursion. Now cancelled in the function
+ silc_server_free_sock_user_data. Affected file silcd/server.c.
+
+ * Fixed the silc_server_remove_clients_by_server to regenerate
+ the channel keys correctly finally. Added also new function
+ silc_server_remove_clients_channels to actually do it.
+ Affected file silcd/server.c.
+
+ * Fixed the silc_server_new_channel to not crash by giving
+ wrong router to the new channel. Affected file is
+ silcd/packet_receive.c.
+
+Wed Jul 11 18:31:57 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added SilcClientParams structure to the lib/silcclient/silcapi.h
+ which is given as argument to the silc_client_alloc now.
+ It can be used to configure the client and set various parameters
+ that affect the function of the client.
+
+ * The USERS command in server did not check whether the channel
+ is private or secret. Affected file silcd/command.c.
+
+ * Added new argument to the USERS command in protocol specification.
+ The USERS command now can take the channel name as argument
+ as well. Added support for this in client and server and
+ updated the protocol specs.
+
+ * Completed the GETKEY command in client. It can be now used
+ to fetch also servers public key not only some clients.
+ Affected files lib/silcclient/command[_reply].c.
+
+ * Added silc_client_get_server to return server entry by the
+ server name. Affected files lib/silcclient/silcapi.h and
+ idlist.c.
+
+ * Redefined the IDENTIFY command in protocol specification to be
+ more generic. It now can be used to query information about
+ any entity in the SILC Network, including clients, servers and
+ channels. The query may be based either the entity's name
+ or the ID. Added support for this in both client and server.
+
+ Affected files silcd/command.c and lib/silcclient/command.c
+ and command_reply.c.
+
+ * Optimized the WHOIS and WHOWAS commands in the server. Removed
+ the _from_client and _from_server functions. Affected file
+ silcd/command.c.
+
+ * Added silc_client_get_channel_by_id_resolve to the file
+ lib/silcclient/silcapi.h to resolve channel information by
+ its ID. Added also silc_client_get_channel_by_id that
+ does not resolve it from the server.
+
+Tue Jul 10 18:05:38 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added SilcServerEntry context into the client library
+ to represent one server. The INFO command now allocates
+ these to save the resolved server info. For now on the
+ client library will also keep information about servers,
+ connected and resolved with INFO.
+
+ The INFO command now allocates the SilcServerEntry context
+ and saves the server info there. The COMMAND_REPLY in
+ the INFO now returns the parameters to application in
+ same order as defined in the protocol specification.
+
+ The entries are cached in the client->server_cache.
+
+ * The INFO command is now issued after received the Client ID
+ from the server. Affected file lib/silcclient/client.c.
+
+ * The CMODE_CHANGE notify may now return also an SilcServerEntry
+ to the application as the mode changer might be server.
+ It is guaranteed that NULL is not returned anymore to the
+ application. Affected file lib/silcclient/client_notify.c.
+
+ The ID Type is now also passed to the application so that
+ it can check whether the returned entry is SilcClientEntry
+ or SilcServerEntry.
+
+ Added new function silc_client_get_server_by_id to return
+ the server entry by ID. Affected files are the
+ lib/silcclient/silcapi.h and lib/silcclient/idlist.c.
+
+ * Do not create the channel in the Irssi SILC Client when issuing
+ the JOIN command but when received the sucessful JOIN command
+ reply. Otherwise the channel might get created even though we
+ could not join it. The Affected file is
+ irssi/src/silc/core/[silc-channels.c/client_ops.c].
+
+ * Fixed a channel joining bug in router. The router must also
+ check the channel modes, invite and ban lists etc. when serving
+ the JOIN command sent by normal server. Affected file is
+ silcd/command.c. The router now resolves the client's
+ information from the server who sent the JOIN command if it
+ does not know it, and processes the JOIN command only after
+ that.
+
+ * Changed the SilcCommandCb to take new argument; void *context2.
+ Affected file lib/silccore/silccommand.h
+
+ The second argument in the command callbacks in the server now
+ includes the SilcServerCommandReplyContext if the command was
+ called as pending command callback from the command reply.
+ Otherwise it is NULL. When called as pending the status of the
+ command reply will be checked and if it was erronous the
+ error will be sent to the original sender of the command.
+ This way the client always receives the error messages even
+ though the server was actually the one who received the error
+ when it resent the command to router, for example. Affected
+ files silcd/command[_reply].[ch].
+
+ * Fixed sending WHOWAS command's error message to client if
+ the requested client could not be found. It was missing.
+ silcd/command.c.
+
+ * Changed the CMODE and CUMODE commands reply arguments in the
+ protocol specification. The Channel ID is now sent in both
+ of the commands to identify the channel. Implemented this
+ new feature to the client and server. Affected files
+ lib/silcclient/command_reply.c and silcd/command.c.
+
+ * Made better checks for invite and ban lists in the JOIN
+ command in server. Affected file silcd/command.c.
+
+Mon Jul 9 18:28:34 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * The server now performs the incoming host IP/DNS lookup
+ using the silc_socket_host_lookup and thus does not block
+ the server anymore. Affected file silcd/server.c.
+
+ * Completed the multi-thread support for SILC Scheduler in
+ the lib/silcutil/silcschedule.c.
+
+ * Fixed the configure.in.pre to detect the pthread correctly
+ on various systems.
+
+ * Fixed a deadlock in silc_task_queue_wakeup in the file
+ lib/silcutil/silctask.c.
+
+Mon Jul 9 13:40:03 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added new function silc_schedule_wakeup that is used in
+ multi-threaded environment to wakeup the main thread's
+ schduler. It needs to be used when a thread adds a new task
+ or removes a task from task queues. After waking up, the
+ scheduler will detect the task queue changes. If threads
+ support is not compiled in this function has no effect.
+ Implemented the wakeup mechanism to both Unix and WIN32
+ systems. Affected files are lib/silcutil/silcschedule.[ch],
+ lib/silcutil/unix/silcunixschedule.c and the
+ lib/silcutil/win32/silcwin32schedule.c.
+
+ * Added new function silc_task_queue_wakeup to wakeup the
+ scheduler by the specified task queue. Affected file
+ lib/silcutil/silctask.[ch].
+
+ * The silc_socket_host_lookup_start now wakes up the scheduler
+ after adding the timeout task. Affected file is
+ lib/silcutil/silcsockconn.c.
+
+ * The silc_socket_host_lookup is synchronous now if the threads
+ support is not compiled in. However, the callback is still
+ called asyncronously through the scheduler, anyway. Affected
+ file lib/silcutil/silcsockconn.c.
+
+Mon Jul 9 00:24:45 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added new function silc_socket_host_lookup to perform
+ asynchronous IP and FQDN lookups for the socket connection.
+ Affected files lib/silcutil/silcsockconn.[ch].
+
+Sun Jul 8 18:44:53 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added SILC_MUTEX_DEFINE to define the mutex on environments
+ that may or may not compile the mutex support in.
+
+ Changed the silc_mutex_alloc interface. It allocates the
+ mutex now to the sent pointer and returns TRUE or FALSE.
+
+ Affected file lib/silcutil/silcmutex.h.
+
+ * Wrote the SILC Task Queue interface to support multi-threads.
+ Affected file lib/silcutil/silctask.[ch].
+
+ * Wrote the SILC Scheduler to support multi-threads. Affected
+ file lib/silcutil/silcschedule.c.
+
+Sun Jul 8 11:16:01 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Implemented the SILC Mutex API and SILC Thread API for WIN32
+ in lib/silcutil/win32/.
+
+Sun Jul 8 00:18:15 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Defined SILC Mutex API and SILC Thread API and implemented
+ them for Unix. Affected files are
+ lib/silcutil/silcmutex.h, lib/silcutil/silcthread.h,
+ lib/silcutil/unix/silcunixmutex.c and
+ lib/silcutil/unix/silcunixthread.c.
+
+Sat Jul 7 14:40:31 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed the silc_server_remove_clients_by_server's channel
+ key re-generation. The hash table handling was incorrect
+ and would not work with many channels. Affected file is
+ silcd/server.c.
+
+ * Fixed some memory leaks around the server code.
+
+ * Rewrote the silc_server_get_users_on_channel to support IPv6
+ based Client ID's. Affected file silcd/server.c.
+
+ * Defined the SILC_MESSAGE_FLAG_SIGNED to the protocol
+ specification. However, a separate document must be written
+ to define the detailed signing procedure and the payload
+ associated with the flag. Defined the flag to the
+ lib/silccore/silcchannel.h as well.
+
+Fri Jul 6 18:26:31 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Changed the dynamic tables to static size tables in the
+ lib/silccrypt/silchmac.c.
+
+ * Removed GCC dependencies from the code. A patch by cras.
+
+Fri Jul 6 09:39:35 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Do not show the error "Error receiving packet bla bla"
+ in server if it really was not an error (-2 means that reading
+ is pending). Affected file silcd/server.c.
+
+Thu Jul 5 21:22:32 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed a possible crash in silc_server_remove_clients_by_server
+ in silcd/server.c. Fixed there also some memory leaks.
+
+ * Fixed the silc_idlist_replace_client_id. It could replace
+ wrong key in the hash table. Affected file silcd/idlist.c.
+
+ * Do not check whether there are global users on the channel
+ if the channel->global_users is FALSE. Affected functions
+ silc_server_remove_from_one_channel and
+ silc_server_remove_from_channels in silcd/server.c. Also,
+ do not check if the removed client is local as we can be
+ sure that global client was not removed from the channel
+ and checking for global users is not needed.
+
+ * The silc_server_remove_clients_by_server now re-generates
+ the channel keys correctly for those channels that had
+ clients removed from them. Affected file silcd/server.c.
+
+Tue Jul 3 11:39:20 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Found the reason of random crashes in the server. We weren't
+ ignoring the SIGPIPE signal (which can be sent in write())
+ and it crashed the server. Affected file silcd/silcd.c.
+
+Fri Jun 29 20:05:25 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Assure that sock->user_data is not NULL in the function
+ silc_server_packet_send in silcd/packet_send.c.
+
+ * Disconnect the remote connection if it could not be added
+ to any ID lists in the server. The affected file is
+ silcd/server.c.
+
+ * Check in silc_server_packet_send[_real/dest] that the
+ socket is not disconnecting and ignore the data if it is.
+ Affected file silcd/packet_send.c.
+
+ * Define inline to __inline on native WIN32 compilation.
+ Affected file includes/silcwin32.h.
+
+ * Added some explicit type casts for inline code since MSVC
+ require them. Affected files lib/silcutil/silcbuffer.h,
+ lib/trq/silcdlist.h and lib/trq/silclist.h.
+
+ * Print warning in log files from now on if the packet
+ decryption fails. Affected file silcd/server.c.
+
+Thu Jun 28 21:30:39 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Changed the `say' client operation's interface to accept
+ new `type' argument to indicate the type of the message sent
+ by the library. The application may filter the library's
+ messages according the type. The affected file is the
+ lib/silcclient/silcapi.h.
+
+ * Added two new functions to lib/silcclient/silcapi.h:
+ silc_client_del_client and silc_client_del_client_by_id.
+ Affected file lib/silcclient/idlist.c.
+
+ * Moved the clientincludes.h from includes/ to silc/ and
+ serverincludes.h from includes/ to silcd/.
+
+ * The modes for the CMODE and CUMODE are now passed as
+ uint32 for application with COMMAND_REPLY. The affected
+ file is lib/silcclient/command_reply.c.
+
+Wed Jun 27 22:24:47 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * /WHOIS without arguments shows client's own information.
+ Affected file lib/silcclient/command.c.
+
+ * Changed PING to not accept any arguments. The specs
+ says that client can ping only the connected server so
+ requiring an argument is not needed. Affected file is
+ lib/silcclient/command.c.
+
+Wed Jun 27 00:10:33 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed a fatal bug in private message sending and reception
+ encryption and decryption when using private message keys.
+ The implementation was incorrect and did not follow the
+ specification. It causd that some of the message were
+ lost since it did not use the sending and receiving keys
+ as the protocol suggests. This has been fixed and will cause
+ incompatibilities with older clients when sending private
+ message encrypted with private message keys. Affected files
+ lib/silcclient/client_prvmsg.c, lib/silcclient/client_keyagr.c
+ and various other in Irssi SILC Client.
+
+ Added `responder' boolean argument to the functions
+ silc_client_add_private_message_key[_ske] to indicate when
+ the key is added as responder or initiator of the key
+ negotiation.
+
+Tue Jun 26 19:23:07 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Removed the silc_ske_check_version function and created
+ a SilcSKECheckVersion callback. Added also a function
+ silc_ske_set_callbacks that is now used to set all SKE
+ callbacks. The callback functions are not given to
+ the SKE functions anymore, but this function is used to
+ set the callbacks.
+
+ * Fixed the WIN32 DLL generation in lib/Makefile.am.pre.
+
+ * Added `silc_version' argument to the silc_client_alloc
+ to define the version of the application for the library.
+ The library will use the version string to compare it
+ against the remote host's (usually a server) version
+ string. Affected file lib/silcclient/silcapi.h
+
+ * Added the KE protocol context to Key Agreement context
+ in client library so that we can abort the SKE if it
+ is in process when we get timeout. Affected file is
+ lib/silcclient/client_keyagr.c.
+
+ * Do not resolve the client ID forever if it returns in the
+ first time that such client does not exist. This was done
+ for example with private message. Affected file is
+ lib/silcclient/client_prvmsg.c.
+
+Mon Jun 25 21:42:51 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Do not add regex.h for WIN32. The affected file
+ includes/silcincludes.h.
+
+ * Added WIN32 DLL generation to lib/Makefile.am.pre. It might
+ not work yet 100%. It generates the DLL's automatically
+ when compiling with --with-win32 under cygwin.
+
+Sun Jun 24 19:49:23 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * lib/contrib/regex.c is not compiled on WIN32.
+
+ * Added silc_net_get_socket_opt function to the
+ lib/silcutil/silcnet.h.
+
+ * Added includes/silcwin32.h for WIN32 specific includes
+ and definitions.
+
+ * Do not use ptime structure or any of the posix process
+ functions on WIN32 in lib/silccrypt/silrng.c.
+
+ * Added silc_gettimeofday to provide generic function
+ for struct timeval on all platforms. Added the function
+ to lib/silcutil/silcutil.h.
+
+Sun Jun 24 12:19:52 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Moved the lib/silccore/silcsockconn.[ch] to the utility
+ library as they clearly belong there. As a plus side we
+ can make the actual socket connection routines platform
+ specific.
+
+ Added also new generic function silc_socket_read and
+ silc_socket_write (that used to be silc_packet_[read/write].
+ The implementation of these are platform specific.
+
+ * Added WIN32 specific routines of silc_socket_[read/write]
+ to lib/silcutil/win32/silcwin32sockconn.c.
+
+Sat Jun 23 16:01:00 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added preliminary support for native WIN32 compilation under
+ cygwin (using the -mno-cygwin option for GCC) to the
+ ./configure.in.pre. The --with-win32 now prepares the
+ compilation for native WIN32.
+
+ * Rewrote the SILC Scheduler interface in the file
+ lib/silcutil/silcschedule.h. The scheduler is now context
+ based and does not have anymore any global static scheduler.
+ Moved the Unix scheduler to the lib/silcutil/unix/ directory
+ and created lib/silcutil/win32 directory for WIN32 based
+ scheduler.
+
+ * Added Unix specific network routines to the
+ lib/silcutil/unix/silcunixnet.c and the old
+ lib/silcutil/silcnet.c includes now only generic routines.
+
+ Added WIN32 specific network routines to the
+ lib/silcutil/win32/silcwin32net.c.
+
+ * Added Unix specific utility functions from the
+ lib/silcutil/silcutil.c to lib/silcutil/unix/silcunixutil.c.
+
+ * Added WIN32 SILC Scheduler to the file
+ lib/silcutil/win32/silcwin32schedule.c. The code is of course
+ untested.
+
+Fri Jun 22 10:44:14 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Do not handle JOIN notify in the server if the target client
+ is not registered (idata->registered == FALSE). The affected
+ file is silcd/packet_receive.c.
+
+ * Update the nickrec->founder in event_cumode in the Irssi SILC
+ client. Affected file irssi/src/silc/core/silc-channels.c.
+
+ * Fixed the CUMODE_CHANGE notify handling in the server when
+ server and router are announcing their clients on channels.
+ Now the mode changes are saved and notified correctly. The
+ affected file is /silcd/packet_receive.c.
+
+ * Fixed silc_idlit_replace_[server/client/channel]_id functions.
+ They really did not replace the cache entry in the ID Cache.
+ Now they do that. Affected file silcd/idlist.c.
+
+ * Fixed the KICK notify handling in the Irssi SILC client to
+ update the channel records so that the kicked client does not
+ appear to be on the channel. The affected file is
+ irssi/src/silc/core/silc-channels.c.
+
+ * Always update the conn->current_channel when executing command
+ on a channel. Affected file irssi/src/silc/core/silc-servers.c.
+
+ * Fixed the KILL notify handling in Irssi SILC client to remove
+ the killed client on all channels.
+
+Thu Jun 21 17:10:08 CEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed the silc_parse_command_line to remove extra spaces
+ from the start and end of the arguments. Affected file is
+ lib/silcutil/silcutil.c.
+
+ * Cancel and free any active protocol in the function
+ silc_server_close_connection. Affected file silcd/server.c.
+
+ * Cancel and free any active protocol in the function
+ silc_client_close_connction. Affected file is
+ lib/silcclient/client.c.
+
+ * Do not execute the KILL command for clients that are in
+ history (ie. they are not in the network). Affected file is
+ silcd/command.c.
+
+ * Fixed KILL notify handling, client does not crash anymore.
+ Affected file irssi/src/silc/core/silc-channels.c.
+
+ * Reduced the default packet buffer size from 2048 to 1024 in
+ lib/silccore/silcpacket.c.
+
+ * Added SILC_SKE_STATUS_FREED SKE status type and a reference
+ counter to the SKE context that is incresed when the SKE library
+ performs async operation outside the library. If the outside
+ process frees the SKE context and FREED status will be set
+ and the library will detect after the sync operation that the
+ libary is freed. The affected files are
+ lib/silcske/silcske[_status].[ch].
+
+ * Resolve the client entry information in the function
+ silc_client_channel_message to assure that NULL pointer is not
+ passed as client entry to the application. */
+
+ * Fixed the task timeout calculation to assure that there is
+ never negative timeouts. The affected file is
+ lib/silcutil/silcschedule.c.
+
+ * Fixed the channel user mode notification sending in server.
+ It was sent point-to-point to the router (or to server by router)
+ but it needs to be destined to a channel. The routines now
+ supports sending the channel user mode notifys to the channels
+ when announcing clients and channels. Affected files are
+ silcd/server.c and silcd/packet_receive.c.
+
+ * Fixed the CHANNEL_CHANGE notify handling in the client libary.
+ It did not actually replace the old channel entry in the cache.
+ Affected file lib/silcclient/client_notify.c.
+
+Tue Jun 19 22:10:36 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed a possible crash in silc_packet_send_prepare. It now
+ assures always that there is enough space in the buffer and
+ at the tail area of the buffer (for MAC).
+
+ Fixed the inbound buffer reallocation in silc_packet_read.
+ It was old code and did not handle the reallocation correctly.
+ Affected
+
+ The affected file is lib/silccore/silcpacket.c.
+
+ * Fixed buffer overflow in silc_parse_nickname in the file
+ lib/silcutil/silcutil.c.
+
+Tue Jun 19 13:40:09 CEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * make install generates new server keys only if there is not
+ keys already.
+
+Mon Jun 18 18:49:07 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Set SILC_MESSAGE_FLAG_NOREPLY when sending the away message.
+ Added check that if the NOREPLY is set then we will not send
+ the away message. This avoids infinite loop of away messages
+ if both clients are away. The affected file is
+ lib/silcclient/client_prvmsg.c.
+
+ * Fixed client crash if /NICK was given without arguments.
+ Affected file lib/silcclient/command.c.
+
+ * Server does not send the invite list in INVITE command back
+ to the client if the list was not altered. Added this notion
+ to the protocol spec as well. Affected file silcd/command.c.
+
+ Fixed possible crash in INVITE command by checking the
+ value of silc_server_get_client_route command.
+
+ * Fixed the INVITE notify type handling. The arguments are now
+ taken in correct order and client does not crash. The affected
+ file is irssi/src/silc/core/silc-channels.c.
+
+ Removed the "Inviting xxx to channel" message from the
+ client library away and let the application handle it.
+ Affected file lib/silcclient/command.c. Added that message
+ to Irssi SILC client's message formats.
+
+ * Fixed CMODE command crash in client. It now checks the
+ amount of arguments correctly and does not crash. The affected
+ file is lib/silcclient/command.c.
+
+ * Do not create new channel automatically in silc_channels_join
+ but check whether the channel by that name already exists.
+ Affected file irssi/silc/core/silc-channels.c.
+
+ * Do not send the SERVER_SIGNOFF to router if the disconnected
+ entity was the router. Affected file silcd/server.c.
+
+ * Added the handling of the SERVER_SIGNOFF notify to the Irssi
+ SILC client as it was missing from there.
+
+ Added the handling of the KICK notify to the Irssi SILC client
+ as it was missing. Added "you have been kicked" message to
+ Irssi SILC client's message modules formats.
+
+ Added the handing of the KILL notify to the Irssi SILC client
+ as it was missing. Added the kill message module formats
+ as well.
+
+ The affected file is irssi/src/silc/core/silc-channels.c.
+
+ * The router did not save the channel mode the server announced.
+ Affected file silcd/packet_receive.c.
+
+ * Fixed a possible crash in INFO command in server. If the
+ server did not provide the server info it crashed. Affected
+ file silcd/command.c.
+
+Sun Jun 17 15:26:05 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed the GETKEY command in the server to check also the
+ global list. Otherwise the GETKEY would not work correctly
+ in normal SILC server. Affected file silcd/command.c.
+
+Sat Jun 16 18:00:00 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed GETKEY crash, it crashed if the command did not succseed.
+
+Tue Jun 12 21:36:18 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Redefined the SILC MP API in lib/silcmath/silcmp.h. The API
+ is now real and not just an macro interface to GMP.
+
+ Removed the entire GMP from the source tree and imported new
+ NSS MPI library instead. Reason for removing GMP is that it is
+ extremely large and compiles extremely slow. The NSS MPI
+ is only a few files and compiles in less than 10 seconds.
+ The speed is also about the same as GMP. The MPI is imported
+ to lib/silcmath/mpi.
+
+ If the system has GMP installed we will still use the GMP.
+ If it is not then the NSS MPI will be compiled.
+
+Mon Jun 11 18:07:24 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Merged a long nickname (127 characters long) crash bugfix from
+ Irssi CVS tree. Affected file irssi/src/core/misc.c.
+
+ * Merged a freed memory reference bugfix from Irssi CVS tree.
+ Affected file irssi/src/core/commands.c.
+
+Sun Jun 10 16:08:35 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added the server's public key sving and verification to the
+ server when performing the SKE. This was missing and the
+ remote server's (or router's) public key was accepted without
+ checking whether we have it previously or trust it at all.
+ Affected file silcd/protocol.c.
+
+Sat Jun 9 20:17:30 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Check in the silc_server_timeout_remote if protocol is active
+ and make sure that the protocol's final callback is called so
+ that all memory if freed. Affected file silcd/server.c.
+
+Sat Jun 9 12:51:27 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * silc_server_whois_send_reply crashed the server if the nickname
+ was 127 characters long. Affected file silcd/command.c.
+
+Thu Jun 7 16:29:56 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added sanity check to the silc_server_new_client. If the hostname
+ is provided inside username then check that the provided hostname
+ really is the same as the resolved one. If the hostname was not
+ resolved then check it from the public key. Affected file is
+ silcd/packet_receive.c.
+
+ * Fixed a fatal bug in Irssi SILC client. Do not send QUIT command
+ if the server disconnected us and the connection is not valid
+ anymore. Affected file irssi/src/silc/core/silc-channels.c.
+
+ * Moved the silc_client_[chmode|chumode|chumode_char] away from
+ the library to the lib/silcutil/silcutil.[ch].
+
+Thu Jun 7 08:57:16 CEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Close log file after open. Affected file
+ lib/silcutil/silclog.c.
+
+ * Check whether sock == NULL in silc_client_send_packet and return
+ if it is. Affected file lib/silcclient/silcclient.c.
+
+ * Check rec->entry == NULL in the Irssi SILC Client before
+ sending the channel message. Affecte file is
+ irssi/src/silc/core/silc-servers.c.
+
+Tue Jun 5 08:08:21 CEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Merged a splitted window bugfix from Irssi CVS tree. The
+ affected file is irssi/src/fe-text/textbuffer-view.c.
+
+ * Fixed the ME, ACTION and NOTICE printing in Irssi Client.
+ It did not print nickname.
+
+ * Improved the distributions system a bit.
+
+Mon Jun 4 17:57:16 CEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Merged /WINDOW bugfix from irssi CVS tree. Affected file is
+ irssi/src/fe-text/gui-window.c.
+
+ * Fixed a fatal bug in Irssi SILC client. Crashed if sent message
+ to in-active server. The affected file is
+ irssi/src/silc/core/client_ops.c.
+
+ * Resolve the client in USERS command reply if the entry does
+ not have username resolved. The affected file is
+ lib/silcclient/command_reply.c. Also, changed the IDENTIFY
+ command to WHOIS command to really resolve stuff. The USERS
+ is not used any more in any critical section so WHOIS can
+ be used even though it might be slower than IDENTIFY.
+
+ * Changed the lib/silcutil/silchashtable.h header to ROBODoc
+ format.
+
+Sun Jun 3 14:21:32 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Changed the protocol API a bit more consistent in the
+ lib/silccore/silcprotocol.[ch].
+
+ * Changed the following headers to ROBODoc format:
+
+ lib/silccore/silcpayload.h
+ lib/silccore/silcprotocol.h
+ lib/silccore/silcsockconn.h
+
+ All core library headers are now formatted.
+
+Sat Jun 2 10:45:09 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed a bug in Irssi SILC client; do not show that you are
+ server/router operator if you really are not. Affected file is
+ irssi/src/silc/core/client_ops.c.
+
+ * Renamed silc_command_free_payload to silc_command_payload_free.
+ Affected file lib/silccore/silccommand.h
+
+ * Added silcmath.h to include the prototoypes of various routines
+ in the lib/silcmath. Removed the old modinv.h, mpbin.h and
+ silcprimegen.h.
+
+ * Changed the following headers to ROBODoc format:
+
+ lib/silccore/silcchannel.h
+ lib/silccore/silccommand.h
+ lib/silccore/silcid.h
+ lib/silccore/silcidcache.h
+ lib/silccore/silcmode.h
+ lib/silccore/silcnotify.h
+ lib/silccore/silcpacket.h
+ lib/silcmath/silcmath.h
+
+Fri Jun 1 22:19:37 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added checking to the server code not to start the server if
+ ciphers and stuff are not configured properly. Affected files
+ silcd/serverconfig.[h] and silcd/server.c.
+
+ * Changed the layout of the header files of the public interfaces
+ in the SILC libraries. The new layout supports ROBODoc
+ documentation tool (and some others) so that it is easy to create
+ a library reference manual. All the other headers and source
+ code must still follow the CodingStyle document. Also source
+ code must not include these ROBODoc stuffs, only the headers.
+ Furthermore, all public interface headers must now be named
+ by using `silc' prefix, example: silcapi.h, silccipher.h.
+ Some files were renamed due to this. All the other headers
+ must not be used as public interfaces. I will update the
+ CodingStyle document later. Changed following headers, so far:
+
+ lib/silcclient/silcapi.h
+ lib/silccore/silcauth.h
+ lib/silccore/silcprivate.h
+ lib/silccrypt/silcdh.h
+
+Fri Jun 1 10:28:09 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Updated TODO.
+
+ * Removed silc_client_packet_send_flush from the client library
+ as it is not needed. Affected file lib/silcclient/client.[ch].
+
+ * Added printing of message of unresolved authentication method
+ to the Irssi SILC client. Added it to the module formats.
+ Removed the same message from the client library.
+
+Thu May 31 13:57:33 CEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added new distribution feature, DISTLABEL. Every distribution
+ can define own preprocessor label that can be used in the
+ source code. For example: #ifdef SILC_DIST_CLIENT. Affected
+ file distributions, acconfig.h.pre and prepare.
+
+Tue May 29 22:16:40 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added Makefile.defines_int to include the actual definitions
+ for Makefile.defines.in. Tested the new distribution system,
+ created distributions and tested installation.
+
+ * Added AWAY message printing to the Irssi SILC client. Added
+ the messages to the irssi/src/fe-common/silc/module-formats.[ch].
+
+ * Added SCONNECT command to call the SILC's CONNECT command.
+ Cannot use CONNECT directly since Irssi uses that internally.
+ Affected file irssi/src/silc/core/silc-servers.c.
+
+ Added ACTION local command. It is same as ME command but takes
+ the channel as mandatory argument.
+
+ Rewrote some of the Irssi's help files to suite for SILC
+ protocol.
+
+Mon May 28 19:05:22 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added Makefile.defines[.in] that should for now on be included
+ in all Makefile.am file in the source tree. That file includes
+ all common compilation definitions for SILC source tree.
+
+Mon May 28 10:30:51 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Minor changes to the ./prepare script to change the package
+ name according the distribution name to the configure.in.
+
+Sun May 27 22:24:57 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Created new distribution system. Added file `distributions'
+ that defines all the distributions that can be created out of
+ the SILC source tree. The ./prepare script now reads that
+ file to determine how to prepare the distributions. The
+ first argument to the ./prepare is the name of the distribution
+ and second is the version of the distribution. If given
+ without arguments it creates the default (toolkit) distribution
+ with the default version (defined in ./prepare).
+
+ All Makefile.am files that are subject to the distributions
+ are now named as Makefile.am.pre. These are ./Makefile.am
+ and lib/Makefile.am. Others may be changed later.
+
+Sun May 27 15:57:17 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added invite list, ban list, some key management and connection
+ error message printing to module formats in the Irssi SILC client.
+
+ * Added new silc_client_set_away_message to set the away message
+ that is back to the person who sent private message. The
+ affected file lib/silcclient/silcapi.h and the
+ lib/silcclient/client_prvmsg.c.
+
+Sun May 27 12:39:48 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed the private message sending in the Irssi SILC client,
+ added local command KEY to the Irssi SILC client.
+
+ Added key management and key agreement message formats to the
+ irssi/src/fe-common/silc/module-formats.[ch].
+
+ Added USERS (alias WHO) printing, server/router operator
+ indication and LIST command printing to the module formats.
+
+Sat May 26 17:43:42 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed channel joining notify handling, cumode notify handling
+ from Irssi SILC client.
+
+ * Added SILC specific module-formats to the Irssi SILC client so
+ that SILC specific message hilighting, colors etc is possible.
+ Affected file irssi/src/fe-common/silc/module-formats.[ch].
+
+ Added channel mode, channel user mode, actions, notices,
+ whois and whowas printing to the the module-formats.c.
+
+ * Fixed a bug in channel deletion in the server. The channel
+ is not left to the cache even if the channel founder auth mode
+ is set when there are no users anymore on the channel. Affected
+ file silcd/server.c.
+
+ * The silc_net_localhost now resolves the entire hostname including
+ the domain name. Affected file lib/silcutil/silcnet.c.
+
+Sat May 26 12:13:37 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Changed the ask_passphrase client operation to be ascynchronous.
+ It has now a completion callback and a context that the
+ application must call after it has got the passphrase from
+ the user. Affected files lib/silcclient/silcapi.h,
+ lib/silcclient/protocol.c, lib/silcclient/command.c and
+ silc/client_ops.c.
+
+ Added SilcAskPassphrase callback that the application calls
+ to deliver the passphrase to the library.
+
+ * Changed the SKE protocol's SilcSKEVerifyCb to be asynchronous.
+ The public key verification and especially a certificate
+ verification is asynchronous procedure.
+
+ Added new SILC_SKE_STATUS_PENDING status to indicate the
+ request is pending and a callback will be called to finalize
+ the request.
+
+ Added also SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED status to
+ indicate that remote end did not send its public key (or
+ certificate), even though we require it. Added check for this
+ condition in the SKE. This was a security bug, now fixed.
+
+ Defined new SilcSKEVerifyCbCompletion callback that is called
+ when the verification process is completed.
+
+ The affected files lib/silcske/silcske_status.h and
+ lib/silcske/silcske.[ch].
+
+ * Changed the verify_public_key client operation to be async
+ as well. Defined SilcVerifyPublicKey callback that is used to
+ indicate the success of the public key verification process.
+
+ Changed the server and client to use the new async client
+ operations.
+
+ * Changed the Irssi SILC client's internal scheduler to be called
+ twice as many times as it used to be. As a result the client
+ should be a bit faster now. Affected file is
+ irssi/src/silc/core/silc-core.c.
+
+ * Added support to Irssi SILC client of asynchronous public key
+ verification and passphrase inquiry. Affected file is
+ irssi/src/silc/core/silc-core.c.
+
+Fri May 25 14:38:38 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Do not say "You have left channel %s" in client library.
+ Moved it to the application. Affected files are
+ lib/silcclient/command.c and silc/client_ops.c.
+
+ * Fixed silc_client_get_clients. Command context was not
+ duplicated and was freed memory in the callback. Affected
+ file lib/silcclient/idlist.c.
+
+ * Do not say "you are now talking..." on JOIN command in the
+ client library. The appliation must handle it.
+
+ * Do not say ".. changed topic to" in command reply in the
+ client libary. The application must handle it.
+
+ * Fixed TOPIC command sending in the client library.
+
+ * Fixed a memory leak in silc_client_command_free in the file
+ lib/silcclient/command.c.
+
+Thu May 24 19:08:55 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Imported a modified version of Irssi client to the source tree.
+ The Irssi will be used to create a new client called
+ Irssi SILC. Imported to irssi/.
+
+ Added silc_core_init_finish function to the Irssi. Affected
+ file irssi/configure.in.
+
+ A lot changes in the Makefile.ams around the irssi tree.
+
+Tue May 22 22:23:49 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Do not rehash if the new size is same as the old size of the
+ hash table, in the silc_hash_table_rehash*. The affected file
+ lib/silcutil/silchashtable.c.
+
+ * Replaced hash_table_del_by_context calls from the server
+ (when channel->user_list and client->channels) to the
+ hash_table_del as it is sufficient and faster.
+
+Tue May 22 17:27:16 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added silc_hash_table_list, silc_hash_table_get and the
+ SilcHashTableList structure to provide an alternative way to
+ traverse the hash table. The affected files are
+ lib/silcutil/silchashtable.[ch].
+
+ * Changed the server's idlist routines to use the hash table
+ routines to optimize the code.
+
+Mon May 21 21:46:20 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Replaced the client entry's `channel' list and channel entry's
+ `user_list' list to hash tables for optimized lookup. Changed
+ the code to use the hash table interface around the code.
+ Affected file lib/silcd/idlist.[ch].
+
+ * Added `auto_rehash' boolean argument to the function
+ silc_hash_table_alloc to indicate whether the hash table should
+ auto-rehash when it thinks is appropriate time. It will
+ increase the hash table size if the there is twice as much
+ entries in the table than the size of the table, and will
+ decrease the size if there are twice as less entries than
+ the size of the table.
+
+Mon May 21 09:51:11 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed silc_xxx_get_supported to not crash at some circumstances.
+
+Sun May 20 13:45:58 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * silc_idcache_purge_by_context deletes the entry now by context
+ as it is supposed to do. Affected file lib/silccore/idcache.c.
+
+ * Send the ERR_NO_SUCH_NICK in the WHOIS command reply if the
+ client is not anymore valid (WHOWAS givens the info) and not
+ the ERR_NO_SUCH_CLIENT_ID if the nickname still exists.
+
+Sat May 19 16:30:03 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Removed the `data' and `data_len' arguments from the ID Cache
+ interfaces and added `name' argument. ID Cache does not handle
+ anymore the binary data only a names associated with given ID.
+
+ * When hashing a Client ID with silc_hash_id the entire ID is
+ not hashed anymore, instead only the hash of the Client ID is
+ hashed. This way we can access the Client ID from the cache
+ with Client ID but with the hash of the ID (which is a hash of
+ the nickname) as well without any difference in performance.
+
+ Added also silc_idcache_find_by_id_one_ext to do one on one
+ searching when we have the actual ID. Added also function
+ silc_hash_client_id_compare. The affected files are
+ lib/silccore/idcache.[ch] and lib/silcutil/silcutil.[ch].
+
+ * When hashing the name associated with a ID it is always done
+ in lowercase. This way we can access the cache without worrying
+ about case-sensitivity, even though, for example nicknames are
+ case sensitive.
+
+ * Fixed a bug in server with channel message sending. It put
+ wrong ID type as destination ID. The affected file
+ silcd/packet_send.c.
+
+ * silc_idcache_del_by_context now deletes from all hash tables
+ by context. Affected file lib/silccore/idcache.c.
+
+Fri May 18 17:42:00 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Changed the client library to use the new ID Cache interface.
+ Changes around the source tree.
+
+ * Added silc_hash_table_rehash_ext to rehash with specific
+ hash function. Affected file lib/silcutil/silchashtable.[ch].
+
+ * Added silc_hash_string_compare to compare two strings in the
+ hash table. Affected file lib/silcutil/silcutil.[ch].
+
+Fri May 18 11:18:45 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added new function silc_idcache_del_by_context into the
+ lib/silccore/idcache.[ch].
+
+ * Changed the server's ID list routines to use the new ID Cache
+ interface. Changes around the source tree.
+
+Fri May 18 08:35:31 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added silc_hash_table_del[_by_context]_ext functions in to the
+ lib/silcutil/silchashtable.[ch].
+
+ Removed silc_hash_table_find_all* routines and added new
+ silc_hash_table_find_foreach to replace them.
+
+ Added silc_hash_table_replace_ext function as extended
+ replacing function. Separated the simple hash table interface
+ from the extended hash table interface in the file
+ lib/silcutil/silchashtable.h.
+
+ * Fixed minor bugs and changed it to use some of the new
+ hash table functions in lib/silccore/idcache.c
+
+Thu May 17 18:15:12 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added new function silc_hash_table_find_all to return all keys
+ in the hash table by the specified key. As the hash table is
+ collision resistant it also makes it possible to have several
+ duplicate keys in the hash table. This function may be used to
+ find all of the keys from the hash.
+
+ Added user_context arguments to the SilcHashFunction,
+ SilcHashCompare and SilcHashDestructor to deliver user specified
+ context.
+
+ Added new fuctions silc_hash_table_find[_all]_ext to do
+ extended lookup with specified hash and compare functions and
+ specified user contexts.
+
+ Added new function silc_hash_table_add_ext to add the key
+ with specified hash function and user context.
+
+ Added new function silc_hash_table_foreach to traverse all
+ entrys in the hash table. Added SilcHashForeach callback
+ function.
+
+ Added new function silc_hash_table_del_by_context to delete
+ the entry only if the context associated with the key matches.
+
+ Affected files are lib/silcutil/silchashtable.[ch].
+
+ * Removed silc_hash_[server/client/channel]_id and added just
+ silc_hash_id to the lib/silcutil/silcutil.[ch]. Added also
+ silc_hash_id_compare to compare two ID's using as the hash table
+ comparison function. Added also silc_hash_data to hash
+ binary data and silc_hash_data_compare to compare it.
+
+ * Removed silc_idlist_find_client_by_hash as it is not needed
+ anymore. Affected file silcd/idlist.[ch].
+
+ * Rewrote the entire ID Cache system (in lib/silccore/idcache.[ch])
+ to use internally the SilcHashTable. The new ID Cache is a lot
+ faster than the old one. Some of the ID Cache interface was also
+ rewritten and obsolete and stupid functions were removed.
+
+Wed May 16 23:03:30 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added entry_count field to the SilcHashTable to keep the number
+ of the entries in the table. Implemented the function
+ silc_hash_table_rehash. Added new function
+ silc_hash_table_count. Affected file lib/silcutil/silchashtable.c.
+
+ Fixed a minor bug in silc_hash_table_free.
+
+ * Added silc_hash_string, silc_hash_uint, silc_hash_ptr,
+ silc_hash_client_id, silc_hash_server_id and silc_hash_channel_id
+ into the lib/silcutil/silcutil.[ch].
+
+Wed May 16 20:02:47 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Implemented a collision resistant hash table into the
+ lib/silcutil/silchashtable[ch]. See the header and the source
+ for the SilcHashTable API.
+
+Tue May 15 22:05:46 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Merged dotconf version 1.0.2 into lib/dotconf.
+
+Sun May 13 19:32:09 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Do not compile anything in lib/silcsim/* if the SIM support
+ is not enabled. The tree should now compile without problems
+ under cygwin.
+
+Thu May 10 22:49:51 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Compiled the SILC under cygwin. Compiled and tested briefly
+ without problems. More tests needed. The SIMs didn't compile
+ though.
+
+ * Added various #ifdef HAVE_* stuff to lib/silccrypt/silrng.c.
+
+ * Fixed possible crash in silc_get_username in the
+ lib/silcutil/silcutil.c.
+
+Tue May 8 09:04:03 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed a va_arg in silc/client_ops.c.
+
+ * Oops, RC5 routines were named AES and caused some problems
+ when not using SIM's. Affected file lib/silccrypt/rc5.c.
+
+Sun May 6 13:59:48 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added new SilcIDIP structure into the lib/silccore/id.h and
+ replaced the old `ip' fields from all SILC ID's to that type.
+ This is a step towards IPv6 support.
+
+ The silc_id_get_len takes now the ID as an extra argument.
+ The silc_id_id2str, silc_id_str2id and silc_id_dup now supports
+ both IPv4 and IPv6 based ID's.
+
+ The affected files are lib/silccore/id.[ch] and other files
+ around the tree using these routines.
+
+ * Removed the ID length arguments in server from various
+ silc_server_send_notify_* routines -> they are not needed
+ anymore.
+
+Sat May 5 13:56:33 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed memory leak in silc_encode_pem_file in the file
+ lib/silcutil/silcutil.c.
+
+Thu May 3 21:23:50 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Check minor version as well in the SKE. Affected files are
+ silcd/protocol.c and lib/silcclient/protocol.c.
+
+ * Added --identifier option to the server so that an identifier
+ can be when creating the public key for the server. Affected
+ file is silcd/silcd.c.
+
+ * Fixed minor decoding bug in silc_pkcs_decode_identifier in
+ lib/silccrypt/silcpkcs.c.
+
+Wed May 2 20:50:49 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Register default ciphers and stuff when using -C option with
+ the server. Affected file sildc/silcd.c.
+
+ * Put back the servers public key filename format, it is better
+ than the new one. For now, the client keys are saved with the
+ new filename format. The affected file silc/client_ops.c.
+
+ * Implemented the Cipher API for the rest of the ciphers that
+ did not implement it or implemented it the wrong way.
+
+Wed May 2 13:31:26 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Register default ciphers and stuff when using the -S option
+ in the client. Affected file silc/silc.c. Same also when
+ creating new key pair with -C option.
+
+Tue May 1 14:18:13 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed the silc_verify_public_key client operation function to
+ save the public keys differently. The fingerprint is now
+ used as filename and not the hostname. This way also the
+ client keys are saved uniquely and not with hostnames. The
+ affected file is silc/client_ops.c.
+
+ * Trimmed the silc_hash_fingerprint function to remove extra
+ whitespaces from the end of the fingerprint. The affected
+ file is lib/silccrypt/silchash.c.
+
+ * Updated TODO.
+
+ * Added silc_cipher_register_default function to register all
+ default ciphers. It can be used when configuration files
+ does not exist and the application does not want any specific
+ ciphers in any specific order.
+
+ The SilcDList is now used as silc_cipher_list dynamically
+ allocated cipher list. Removed the static list all together
+ and now all ciphers must be allocated to the dynamic list.
+ The silc_cipher_alloc routine was changed to check only the
+ dynamic list.
+
+ All silc_cipher_* routines that used to return int returns
+ now bool.
+
+ The affected files lib/silccrypt/silccrypt.[ch].
+
+ * The same thing was done to silc_hash_* as for silc_cipher_*
+ routines. Affected files lib/silccrypt/silchash.[ch].
+
+ * The same thing was done to silc_pkcs_* as for silc_cipher_*
+ routines. Affected files lib/silccrypt/silcpkcs.[ch].
+ Added also silc_pkcs_[un]register[_default] functions.
+ Removed the data_context from the PKCS API.
+
+ * Added silc_hmac_register_default function to register default
+ hmacs. Affected files lib/silccrypt/silchmac.[ch]. Added also
+ SILC_ALL_HMACS macro that can be used with silc_hmac_unregister
+ to unregister all hmacs at once.
+
+ * Register the default ciphers, hash functions, PKCSs and HMACs
+ if client's configuration file does not exist. The affected
+ file silc/silc.c.
+
+ * The client did not load the hash functions from the SIM
+ modules at all. Added support for this. Affected file is
+ silc/clientconfig.c.
+
+ * When decoding public key with silc_pkcs_public_key_decode, check
+ the supported algorithm only if PKCS are registered. Affected
+ file lib/silccrypt/silcpkcs.c. The same was done with the
+ silc_pkcs_private_key_decode.
+
+ * Fixed the SILC List routines to keep the list always in order.
+ It used to change the list's order when traversing the list but
+ not it preserves the order. Affected file lib/trq/silclist.h.
+
+Mon Apr 30 17:29:03 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added the client library to use the SilcSocketConnection's
+ reference counter (by silc_socket_dup) to prevent the bug that
+ the socket object may be freed underneath async operation.
+
+ * The name resolv library checking fixes in the configure.in.pre.
+ The patch by salo.
+
+ * Created new version of the protocol drafts for future
+ development. The -03 drafts are the ones that will be changed
+ in the trunk now and the -02 will remain as they are.
+
+ * Send list of CUMODE notifys to the router when announcing
+ the channel users to the router. Affected file silcd/server.c.
+ If the router receiving channel founder CUMODE for a channel
+ that already has channel founder it will send CUMODE notify
+ to the sender to remove the channel founder rights from the
+ announced client. Affected file silcd/packet_receive.c.
+
+ * The CUMODE notify may now use Server ID as well as the entity
+ who changes the mode. Updated protocool specs.
+
+ * Updated INSTALL and README files.
+
+Sun Apr 29 23:17:50 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * New web pages in the http://silc.pspt.fi. The pages was
+ designed by salo.
+
+ * Updated CREDITS.
+
+Sun Apr 29 13:33:41 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Implemented the [DenyConnectin] config section in the server.
+ Added silc_server_config_denied_conn to check whether incoming
+ connection is denied. Affected file silcd/serverconfig.[ch].
+
+ * Do not check the ports when checking the incoming configuration
+ data if the port is 0, meaning any. Affected file is
+ silcd/serverconfig.c.
+
+Fri Apr 20 18:58:43 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed buffer overflow in silc_string_compare in the file
+ lib/silcutil/silcutil.c.
+
+ * Fixed double free in silc_server_command_leave in the file
+ silcd/command.c.
+
+Fri Apr 20 14:00:11 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed the version checking in the server. Affected file is
+ silcd/protocol.c.
+
+Thu Apr 19 19:52:46 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed the configuration data fetching when accepting new
+ connections in the server. Affected file silcd/server.c.
+
+Thu Apr 19 11:40:20 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added `sender_entry' argument to the function
+ silc_server_packet_relay_to_channel so that we can check
+ whether some destination actually belongs to the same route
+ the sender belongs (ie, we must not resend the packet to the
+ sender). Affected file silcd/packet_send.[ch].
+
+ * Added `servername' field to the SilcClientEntry in the server
+ to hold the name of the server where client is from. Affected
+ file is silcd/idlist.h.
+
+Wed Apr 18 22:19:03 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Moved the channel message encrypting in the router betwen
+ router connections from silc_server_channel_message to the
+ silc_server_packet_relay_to_channel since we want to check
+ whether we have anybody channel before encrypting anything.
+ Affected files silcd/packet_[receive/send].c.
+
+Tue Apr 17 21:18:19 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed the [AdminConnection] server config section to support
+ multiple entries. Affected file silcd/serverconfig.c.
+
+ * Added support into the server to check the validity of the
+ incoming connection before executing any KE or authentication
+ protocols.
+
+ * The connection configuration is now saved to the KE and
+ connection auth protocol contexts and not fetched anymore in
+ the protocol. Affected files silcd/server.c, silcd/protocol.[ch].
+
+ * The local hosts listenning address and port is also resolved
+ now when starting the server. We want to have the socket object
+ to include the real address and port for the listener. Added
+ new function silc_net_check_local_by_sock into the files
+ lib/silcutil/silcnet.[ch].
+
+ * Fixed a broadcast bug in server -> do not broadcast if we
+ are standalone.
+
+ * Fixed a routing bug. Do not route broadcast packets ever.
+ Broadcast packets must be processed always and not routed since
+ they may be destined to some other host than yourself and thus
+ would get routed without no good reason. Affected file is
+ silcd/server.c.
+
+ * Added function silc_server_config_is_primary_route to check
+ whether primary router connection has been configured (a router
+ configuration that we are initiating). If there is not, we
+ will assume that there is only two routers in the SILC network
+ and we will use the incoming router connection as our primary
+ route. Affected files silcd/serverconfig.[ch], silcd/server.c.
+
+ * Changed the order of the broadcasting. Broadcast _after_ the
+ packet has been processed not before. Affected file is
+ silcd/server.c.
+
+ * Fixed a [ClientConnection] parsing bug. The port was never
+ parsed correctly thus resulting to port 0. Affected file
+ silcd/serverconfig.c.
+
+ * Fixed silc_server_send_notify_args -> it ignored the `broadcast'
+ argument and did not set the broadcast packet flag. Affected
+ file silcd/packet_send.c. Fixed same bug in the function
+ silc_server_send_notify as well.
+
+ * If we receive NEW_ID packet for our own ID in the server, ignore
+ the packet.
+
+Mon Apr 16 12:10:33 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Updated TODO.
+
+ * Removed the nickname from the Private Message Payload.
+ Updated the code and the protocol specs.
+
+ * Updated protocol specs for submitting to the IETF.
+
+ * Tweaked the Random Number Generator a bit. Affected file
+ lib/silccrypt/silcrng.c. Exported a new function
+ silc_rng_[global]_add_noise which can be used to add more
+ noise to the RNG.
+
+Sat Apr 14 16:21:32 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Do not parse packets with different timeout when protocol
+ is active -> may cause problem with rekey. Affected file
+ silcd/server.c.
+
+ * When server receives signoff notify it must not create
+ new channel key if the client is on any channels since the
+ sender of the signoff notify will create it.
+
+Fri Apr 13 17:12:46 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added printing of error messages during SKE protocol from the
+ failure packet sent by server during SKE. Affected file
+ silc/client_ops.c.
+
+ * Removed the client's failure_callback handling with timeout
+ and handle it immediately when received.
+
+ * The SKE library returned wrong type in SUCCESS and FAILURE
+ packets. They must be 32 bit MSB not 16 bit MSB.
+
+Fri Apr 13 00:09:08 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Ok, rewrote the logic of the re-key and now it seems to work.
+ I tested it on high traffic with frequent re-keys without
+ problems. Added hmac_receive (and renamed hmac to hmac_send)
+ in SilcClientConnection in lib/silcclient/client.h and
+ in SilcIDListData in silcd/idlist.h. Also, removed the
+ SilcPacketParserContext's cipher and hmac fields as they are
+ not needed anymore and actually caused some problems when
+ the ciphers and hmac's changed underneath the packet parser.
+
+Thu Apr 12 14:42:51 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * If re-key protocol is active then process the incoming packets
+ synchronously since we must assure that icoming packets encrypted
+ with the old key is processed before the new keys is set to
+ use. This is true other packets than for REKEY packets.
+ Affected file silcd/server.c. The same was done to client library
+ as well, affected file lib/silcclient/client.c.
+
+Thu Apr 12 12:01:52 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed bug in client and server to accept the force send if
+ the packet is send from silc_[server/client]_packet_process
+ function. Otherwise the packets are never delivered, oops.
+
+Wed Apr 11 22:10:15 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Disable force sending of packets when REKEY protocol is active.
+ We must assure that no packet is sent directly when rekey is
+ performed. All packets must be sent through packet queue.
+ Added macro SILC_SERVER_IS_REKEY to silcd/server.h and
+ SILC_CLIENT_IS_REKEY to lib/silcclient/client.h. Affected
+ function is silc_[server/client]_packet_send_real to check
+ the situation.
+
+ * Replaced the SIM paths from example config files to
+ /usr/local/modules. Also, make install creates now
+ /usr/local/silc/logs directory to hold all the SILC server
+ logs.
+
+Wed Apr 11 16:59:59 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Made the configure.in.pre work on Solaris. Patch by salo.
+
+ * Made all ciphers compatible with non-x86 machines. Defined
+ CBC mode macros into lib/silccrypt/ciphers_def.h.
+
+Tue Apr 10 20:32:44 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed the make install.
+
+Tue Apr 10 16:20:34 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * When MAC computation fails the silc_packet_decrypt returned 0
+ even though it was supposed to return -1. Fixed this. The
+ affected file is lib/silccore/silcpacket.c.
+
+ * Do not replace the config files in /etc/silc (in make install)
+ if they already exist. Affected file ./Makefile.am.
+
+ * Do not send re-key packets immediately but through packet queue.
+ Affected file silcd/protocol.c and lib/silcclient/protocol.c.
+
+ * Changed silc_net_check_host_by_sock to return FALSE if the
+ IP/DNS could not be resolved. Though, it returns the IP address
+ now even if it could not resolve it (but returns also FALSE).
+ Affected file lib/silcutil/silcnet.[ch].
+
+Mon Apr 9 21:54:44 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added silc_pkcs_decode_identifier to decode the public key's
+ identifier. Affected file lib/silccrypt/silpkcs.[ch].
+ Added also silc_pkcs_free_identifier. Added also new context
+ SilcPublicKeyIdentifier.
+
+ * Added -S option to the silc client. It is used to dump the
+ contents of the specified public key file.
+
+ * Changed the PKCS api to return the public key length when
+ setting the public key.
+
+ * Fixed a fatal bug in the public and private key file loading.
+ Affected file lib/silccrypt/silcpkcs.c.
+
+ * Execute the packet parsing for client with zero (0) timeout
+ if the protocol is active. Affected file silcd/server.c.
+
+Sun Apr 8 19:30:56 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Made the key generation options to the silcd program. Added
+ -C option, equivalent to client's option.
+
+ * Added new [ServerKeys] config section to the server. It
+ configures the server's public and private key.
+
+ * Defined generic Public Key Payload into the protocol
+ specification to send specific type of public keys and
+ certificates.
+
+ * Defined new command SILC_COMMAND_GETKEY to fetch a client's
+ public key or certificate.
+
+ * Implemented the GETKEY command to the server and to the
+ client library and on user interface.
+
+Sun Apr 8 01:37:21 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Made preliminary `make install' work.
+
+Thu Apr 5 17:42:30 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added SilcServerRekey context into silcd/idlist.h.
+
+ * Added the PFS support as defined in the specification to the
+ SKE protocol. Affected files lib/silcske/*.c.
+
+ * Added `ske_group' field to the SilcServerRekey context to hold
+ the number of the SKE group that is used with PFS in re-key.
+ Affected file silcd/idlist.h.
+
+ * Added PFS re-key support to the server. Affected file is
+ silcd/protocol.c.
+
+ * Added silc_protocol_cancel to cancel execution of the next
+ state of the protocol. Affected file is
+ lib/silccore/silcprotocol.[ch].
+
+ * Added the re-key support with and without PFS to the client
+ library. Re-key is performed once in an hour, by default.
+
+ Added new protocol type SILC_PROTOCOL_CLIENT_REKEY.
+ Added silc_client_rekey_callback and silc_client_rekey_final.
+ Affected files are lib/silcclient/protocol.[ch] and
+ lib/silcclient/client.[ch].
+
+ * Removed the `hmac_key' and `hmac_key_len' fields from the
+ SilcClientConnection structure; not needed. Affected file is
+ lib/silcclient/client.h.
+
+ * Updated TODO.
+
+Wed Apr 4 16:32:31 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Do not ask whether user wants to use the negotiated private key
+ for private messages, just use it. Affected file is
+ silc/local_command.c.
+
+ * Added `send_enc_key' and `enc_key_len' fields to the
+ SilcIDListData structure since they are needed in the re-key
+ phase. Affected file is silcd/idlist.[ch].
+
+ * Implemented the simple re-key protocol into the server.
+ Affected files silcd/server.c and silcd/protocol.[ch]. The
+ re-key will be performed once in an hour, by default.
+
+ Added new protocol type SILC_PROTOCOL_SERVER_REKEY.
+ Added silc_server_rekey, silc_server_rekey_callback and
+ silc_server_rekey_final.
+
+ * Removed Tunneled flag from the protocol. Updated the code
+ and the specifications.
+
+ * Adde `pfs' field to the SilcIDListData to indicate whether
+ the PFS is to be performed in the re-key. Affected file is
+ silcd/idlist.h.
+
+Tue Apr 3 21:52:42 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Defined uint8, int8, uint16, int16, uint32, int32, uint64 and
+ int64 of at least the xintXX size. If void * is less that 4
+ bytes uint32 * will be used. Defined bool as boolean.
+
+ * Changed _ALL_ unsigned long and unsigned int to uint32,
+ unsgined short to uint16 in the source tree.
+
+ * Fixed a fatal bug in silc_server_remove_clients_by_server. Do
+ not handle clients that has entry->data.registered == FALSE.
+ They are not in the network anymore. Affected file is
+ silcd/server.c.
+
+Tue Apr 3 16:39:19 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Implemented the sending of the SERVER_SIGNOFF notify in the
+ server. Affected file is silcd/server.c.
+
+ * Added silc_server_send_notify_args into silcd/packet_send.[ch].
+ Added also silc_notify_payload_encode_args into the
+ lib/silccore/silcnotify.[ch].
+
+ * Implemented ther SERVER_SIGNOFF notify handling in the server.
+ Affected file silcd/packet_receive.c.
+
+ * Implemented the SERVER_SIGNOFF notify handling in the client
+ library. Affected file lib/silcclient/client_notify.c. Also,
+ implemnted the printing of the SERVER_SIGNOFF info to the
+ application. Affected file silc/client_ops.c.
+
+ * The silc_idlist_del_server now returns TRUE or FALSE to indicate
+ if the deleting was successful. Affected file silcd/idlist.[ch].
+
+ * Added support for public key authentication in the connection
+ authentication protocol in the client library. Affected file
+ lib/silcclient/protocol.c.
+
+ * Changed the server's silc_idlist_get_clients_by_* interface
+ to support already allocated array so that new entries may be
+ added to pre-allocated array. Affected file silcd/idlist.[ch].
+ This fixes some bugs with WHOIS, WHOWAS and IDENTIFY commands
+ and command replies.
+
+ * All command reply functions in the server now calls the
+ pending command callback even if error occured. This way the
+ error will be delivered to the client as well. Affected files
+ silcd/command.c and silcd/command_reply.c.
+
+ * Fixed INFO command to return local server's info if no server
+ was provided. Affected file lib/silcclient/command.c.
+
+ * Removed RESTART command for good. Updated the code and the
+ protocol specs.
+
+ * Rewrote parts of the task system. It is a bit simpler now.
+ Removed unsued task priorities. The affected files are
+ lib/silcutil/silctask.[ch].
+
+Mon Apr 2 20:02:33 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Moved the USERS printing from the library to the application.
+ Affected files lib/silcclient/command.c and silc/client_ops.c.
+
+Mon Apr 2 13:13:23 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Updated TODO.
+
+ * Added channel key re-key support. The re-key is perfomed
+ only by the router and is done once in an hour. Added `rekey'
+ field to the SilcChannelEntry in the server. Affected files
+ silcd/server.c and silcd/idlist.h.
+
+ * Added silc_task_unregister_by_context into the file
+ lib/silcutil/silctask.[ch].
+
+Sun Apr 1 19:49:34 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added SILC_UMODE_GONE mode to indicate when the client is not
+ present in the SILC network. Added also support to the local
+ command AWAY that will set this mode. Added support of showing
+ "xxx is gone" in WHOIS command. The USERS command shows the
+ gone status as well.
+
+ * Fixed setting server and router operator privileges in the
+ server's UMODE command. Affected file silcd/command.c.
+
+ * Merged the SKE KE1 and KE2 payloads into one payload. The
+ new KE payload is equivalent to the old KE2 payload.
+
+ Cleaned up the SKE Start Payload parsing. It now uses the
+ simple buffer unformatting to do the parsing. A lot faster
+ now.
+
+ Added new Mutual Authentication flag (SILC_SKE_SP_FLAG_MUTUAL)
+ to the SKE that is used to indicate whether both of the SKE
+ parties should perform authentication. By default only the
+ responder performs authentication. By setting this flag also
+ the initiator must do authentication. By default it is unset
+ since in normal SKE case, client to server connection, only
+ the responder should do authentication. When doing SKE between
+ two clients both should perform authentication. Updated the
+ code and the protocol specs.
+
+ * A little fix to IDENTIFY command in the server. Search the
+ client first by hash not nickname. Affected file is
+ silcd/command.c.
+
+ * Fixed the silc_client_close_connection to support closing
+ the client to client connections wihtout deleting too much
+ data. Affected file lib/silcclient/client.c.
+
+ * Fixed a fatal bug in server and client; if KE1 or KE2 packets
+ are received if protocol used to be active but is not anymore
+ the application would crash due to NULL pointer dereference.
+ Affected files silcd/server.c and lib/silcclient/client.c.
+
+ * Added `hash' field to the SilcClientConnection to include
+ the hash function negotiated in the SKE protocol.
+
+ * Added new channel mode SILC_CMODE_FOUNDER_AUTH that is used
+ to set the channel founder authentication data. A client can
+ claim the founder rights later by providing the authentication
+ data to the CUMODE command using SILC_CUMODE_FOUNDER mode.
+ This way the channel founder can regain the channel founder
+ privileges even it is left the channel. This works only on
+ local server and the client must be connected to the same
+ server to be able to regain the founder rights. Updated the
+ protocol specs accordingly.
+
+ Added support to the CMODE command in the client to set the
+ founder auth data. Read the README to see how to set it.
+
+ Added support to the CUMODE command to claim the founder
+ rights. Read the README to see how to do it.
+
+ Added support for the founder authentication to the Channel
+ Entry in the server. Affected file silcd/idlist.h.
+
+ Added support for the SILC_CMODE_FOUNDER_AUTH mode in the
+ server's CMODE command. Affected file silcd/command.c.
+
+ * Added the following new functions into lib/silccore/silcauth.[ch]:
+ silc_auth_get_method and silc_auth_get_data.
+
+ * The server now saves the remote hosts public key to the
+ SilcIDListData pointer. Affected file silcd/protocol.c.
+
+ * The normal server now does not remove the channel entry from
+ the cache if the founder authentication data is set. It used
+ to remove it if the founder was the last one on the channel on
+ the server and left the channel. The auth data is saved and
+ if the channel is re-joined later the old entry is used with
+ the old auth data. Affected files silcd/command_reply.c and
+ silcd/server.c.
+
+ * Removed the `pkcs' field from the SilcIDListData structure
+ in the server; it is not used. Affected file silcd/idlist.h.
+
+Sat Mar 31 15:38:36 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed packet processing on slow links. Partial packets were
+ never re-processed because the incoming data buffer was cleared
+ by the application. Application must not directly clear the
+ sock->inbuf, the packet processing routines handle it. Fixed
+ this in client library and in server.
+
+Fri Mar 30 16:35:27 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed the WHOIS and IDENTIFY send reply function to really
+ check whether to send list or just one entry. Affected file
+ silcd/command.c.
+
+ * Cleaned up the LEAVE command's channel key distribution. The
+ affected file silcd/command.c.
+
+ * Changed CMODE_CHANGE's <Client ID> to <ID Payload> as server
+ can enforce the channel mode as well. In that case the ID
+ includes the ID of the server. The code now enforces the
+ mode change if the router have different mode than the server.
+
+ * The notify client operation with CMODE_CHANGE notify can now
+ return NULL client_entry pointer if the CMODE was not changed
+ by client. Application must check for this.
+
+ * Added <Server ID> argument to INFO command to support server
+ info fetching by Server ID.
+
+ * Added silc_server_announce_get_channel_users to get assembled
+ packets of channel users of the specified channel. Affected
+ file silcd/server.[ch].
+
+ * Fixed bug in CHANNEL_CHANGE notify in the server. The new ID
+ was freed underneath the ID Cache.
+
+ * Re-announce clients when the server received CHANNEL_CHANGE
+ notify from the router. Affected file silcd/packet_send.c.
+
+Thu Mar 29 19:10:28 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed a fatal bug when client does /join 1 2 3 4 5 6 the server
+ crashed since it did not handle the fact that there is no cipher
+ called "3" and didn't check the error condition. Now fixed.
+
+ * Added SILC_MESSAGE_FLAG_REQUEST message flag as generic request
+ flag. It can be used to send message requests.
+
+Thu Mar 29 12:26:25 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Implemented the RESTART command in the client.
+
+ * Added SILC_MESSAGE_FLAG_NOTICE message flag for informational
+ notice type messages. Added notice printing to the user
+ interface.
+
+ * The channel keys are not re-generated if the channel's mode
+ is PRIVKEY, ie private key on the channel exists. Affected
+ files silcd/server.c and silcd/command.c.
+
+ * Fixed a little bug in channel message delivery when channel
+ private keys are set in the server. Affected file is
+ silcd/packet_send.c.
+
+ * Changed the setting on channel->on_channel = TRUE from the
+ silc_client_save_channel_key to the JOIN command reply. The
+ key payload is not received if the private channel key is set.
+ Affected file lib/silcclient/command_reply.c and the
+ lib/silcclient/client_channel.c.
+
+ * When the CMODE_CHANGE notify is sent and the channel private
+ key mode is removed the channel key must be re-generated in
+ other cells as well. Added this support for the router in the
+ silcd/packet_receive.c.
+
+ * Added new local command NOTICE to send notice message on
+ channel. Affected file silc/local_command.[ch].
+
+Wed Mar 28 23:55:54 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added new local command ME to the client. It is used to send
+ message to a channel with SILC_MESSAGE_FLAG_ACTION to indicate
+ some action. Affected file silc/local_command.[ch].
+
+ * Changed channel_message and private_message client operations
+ to deliver the message flags to the application. Added also
+ the `flags' arguments to the silc_client_send_channel_message
+ and silc_client_send_private_message functions. Affected file
+ silcapi.h.
+
+Wed Mar 28 20:50:47 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Redefined the Private Message Payload to support private message
+ keys and to support the new private message flags. Updated
+ the protocol specs. Flags makes it possible to have for example
+ CTCP style messages.
+
+ * Added new type SilcPrivateMessagePayload and defined an API
+ for it in the lib/silcclient/silcprivate.[ch].
+
+ * Tested private message private keys successfully. Tested the
+ private message key set, unset and list commands with the new
+ KEY command.
+
+ * Redefined the Channel Message Payload to include the channel
+ message flags (equal with private message flags) to support
+ for example CTCP style messages.
+
+ * Defined some of the message (for channel and private message)
+ flags. Updated the protocol specs and added the flags to the
+ lib/silccore/silcchannel.h. The type is SilcMessageFlags.
+
+Wed Mar 28 15:52:36 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added SilcKeyAgreementStatus type to the key agreement routines
+ to indicate the current status and error if one occured.
+ The status types are defined in the lib/silcclient/silcapi.h.
+
+ * Added new local command KEY that is used to set and unset private
+ keys for channels, set and unset private keys for private messages
+ with remote clients and to send key agreement requests and
+ negotiate the key agreement protocol with remote client. The
+ key agreement is supported only to negotiate private message keys,
+ it currently cannot be used to negotiate private keys for channels,
+ as it is not convenient for that purpose.
+
+ * Fixed a minor pending callback setting bug in the function
+ silc_client_get_client_by_id_resolve, now the function works.
+ Affected file lib/silcclient/idlist.c.
+
+ * Added function silc_net_get_local_port to get local bound
+ port by socket. Added to lib/silcutil/silcnet.[ch].
+
+ * Added `sockets' and `sockets_count' fields to the SilcClient
+ object. They hold the sockets of the listenning sockets in
+ the client. Listenning sockets may be for example the key
+ agreement server. Affected file lib/silcclient/client.[ch].
+ Added functions the silc_client_add_socket and the
+ silc_client_del_socket. They are exported to the application
+ as well.
+
+ * Added ~./silc/clientkeys to support other client's public keys.
+
+ * Renamed verify_server_key client operation to verify_public_key
+ and added one argument to indicate the type of the connection
+ (server, client etc.).
+
+Tue Mar 27 22:22:38 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added silc_server_connection_auth_request to handle the
+ incoming CONNECTION_AUTH_REQUEST packet. Affected file is
+ silcd/packet_receive.[ch].
+
+ * Added silc_server_send_connection_auth_request into the
+ silcd/packet_send.c to send the connection auth request packet.
+
+ * Cleaned up the silcd/protocol.c a bit and fixed some memory
+ leaks.
+
+ * Fixed the public key authentication in responder side in the
+ server. The `auth_data' pointer includes the SilcPublicKey
+ not the path to the public key. Affected file silcd/protocol.c.
+
+ * Implemented the public key authentication in the initiator side
+ in the server. Affected file silcd/protocol.c.
+
+ * Removed the [RedirectClient] config section from the server
+ configuration. Is not needed and I don't want to implement it.
+
+Tue Mar 27 12:49:56 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Cleaned up the CMODE command in the server. It now works
+ correctly and supports all the modes defined in the protocol.
+ Affected file is silcd/command.c.
+
+ * Added `hmac_name' field to the SilcChannelEntry in the server
+ to hold the default HMAC of the channel. It can be set when
+ creating the channel (with JOIN command). Affected files
+ silcd/idlist.[ch].
+
+ * Added <cipher> and <hmac> argument to the CMODE_CHANGE notify
+ type to indicate the change of the current cipher and hmac
+ on the channel. Client can safely ignore the <cipher> argument
+ (if it chooses to do so) since the CHANNEL_KEY packet will
+ force the channel key change anyway. The <hmac> argument is
+ important since the client is responsible of setting the new
+ HMAC and the hmac key into use.
+
+ * Fixed the CMODE command in the client library as well.
+
+ * Tested CMODE command in router environment successfully.
+
+Mon Mar 26 14:39:48 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Show the version of the remote client (or server) when connecting
+ to the server. It is logged to the log file. Affected file
+ is silcd/protocol.c.
+
+ * Fixed the KILLED notify handling in the client library. The
+ client must be removed from all channels when receiving the
+ KILLED notify.
+
+ Also, do not remove the client entry when giving the KILL
+ command but when the KILLED notify is received.
+
+ * Removed silc_idlist_find_client_by_nickname from the server.
+ Not needed anymore. Affected files silcd/idlist.[ch].
+
+ * Implemented the CHANNEL_CHANGE notify type handling to the
+ server. Affected file silcd/server.c.
+
+ * Updated TODO.
+
+Mon Mar 26 12:11:14 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added silc_server_send_notify_invite to send the INVITE
+ notify between routers.
+
+ * Implemented the INVITE command correctly to the server.
+
+ * Implemented the INVITE notify type handling in the server.
+
+ * Implemented the INVITE command to the client library and on the
+ user interface.
+
+Sun Mar 25 20:27:09 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added function silc_server_get_client_resolve to find the
+ client entry by ID from all ID lists and then resolve it
+ (using WHOIS) if it cannot be found. Affected file is
+ silcd/server.[ch].
+
+Sun Mar 25 13:52:51 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Implemented the BAN command to the client library.
+
+ * The JOIN command in the server now checks the invite list
+ and the ban list.
+
+ * Changed the silc_command_reply_payload_encode_va and the
+ silc_command_payload_encode_va to support that if argument is
+ NULL it ignores and checks the next argument. Affected file
+ lib/silccore/silccommand.c.
+
+ * Added silc_server_send_notify_ban to send the BAN notify
+ type between routers.
+
+ * Chaned the silc_notify_payload_encode to support that if
+ argument is NULL it ignores and checks the next argument.
+ Affected file lib/silccore/silcnotify.c.
+
+ * Tested ban lists in router environment successfully.
+
+Sat Mar 24 14:47:25 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Implemented BAN command to the server, in silcd/command.[ch].
+
+ * Removed the BAN and INVITE_LIST modes from the CMODE command
+ in the server code.
+
+ * Added function silc_string_match to regex match two strings.
+ Affected files lib/silcutil/silcutil.[ch].
+
+Fri Mar 23 22:02:40 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Redefined parts of the SilcChannelEntry in the server to support
+ the new ban and invite lists.
+
+Fri Mar 23 16:25:11 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Redefined the INVITE command. The same command can be used to
+ invite individuals to the channel but also to manage the invite
+ list of the channel (to add to and remove from the invite list).
+ Updated the protocol specs.
+
+ * Added new command SILC_COMMAND_BAN that can be used to manage
+ the ban list of the channel. Updated the protocol specs.
+
+ * Removed the channel modes: the SILC_CMODE_BAN and the
+ SILC_CMODE_INVITE_LIST as they were a bit kludge to be included
+ in the CMODE command. The equivalent features are now available
+ using INVITE and BAN commands. Updated the protocol specs.
+
+ * Added new SILC_NOTIFY_TYPE_BAN notify type to notify routers
+ in the network about change in the current ban list. The notify
+ type is not used by the client.
+
+ * Redefined parts of the SILC_NOTIFY_TYPE_INVITE command to
+ support the invite lists.
+
+Thu Mar 22 22:52:23 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added new function silc_string_regexify that converts string
+ including wildcard characters into regex string that can
+ be used by the GNU regex library. Added into the file
+ lib/silcutil/silcutil.[ch].
+
+ Added silc_string_regex_combine to combine to regex strings
+ into one so that they can be used as one regex string by
+ the GNU regex library. Added into the file
+ lib/silcutil/silcutil.[ch].
+
+ Added silc_string_regex_match to match two strings. It returns
+ TRUE if the strings match. Added into lib/silcutil/silcutil.[ch].
+
+Thu Mar 22 15:29:42 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Imported GNU regex to the soruce tree into lib/contrib.
+ Fixed some compiler warning from the regex.c.
+
+Wed Mar 21 15:27:58 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed MOTD command in the server to work in router environment.
+
+ * Fixed the MOTD command in the client library to support
+ the server argument in the command.
+
+ * Added `nickname_len' argument to the silc_idlist_add_client
+ in the server, as the `nickname' argument may be binary data
+ (it may be hash).
+
+ * Added silc_idlist_get_channels to return all channels from
+ the ID list.
+
+ * Implemented LIST command to the server. Affected file is
+ silcd/command.c.
+
+ * Implemented the LIST command to the client library and on the
+ user interface.
+
+ * Added [<user count>] argument to the LIST command reply.
+ With private channels the user count is not shown.
+
+ * Updated TODO and README.
+
+Tue Mar 20 21:05:57 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * The client entry's data.registered must be TRUE even with
+ global client entry on global client list. The data.registered
+ is used to check whether the client is anymore in the network,
+ for example with WHOWAS command so it must be valid.
+
+ * Fixed the WHOWAS command in the server. It now actually works
+ in router environment. Added function into silcd/command_reply.c
+ silc_server_command_reply_whowas_save.
+
+ * Added silc_idlist_purge function to the silcd/idlist.c
+ to periodically purge the ID Cache.
+
+ * Fixed INFO command in the server. It works now in router
+ environment. Added <server name> argument to the INFO command
+ reply. Updated the protocol specs.
+
+ * Fixed minor bug in silc_idcache_purge to not purge if the
+ expire value is zero.
+
+ * Fixed various bugs in WHOIS and IDENTIFY command handling as
+ they were buggy because of the WHOWAS information.
+
+ * Fixed local command MSG to handle the async resolving of
+ the remote client properly. It used to fail the first MSG.
+ Affected file silc/local_command.c.
+
+ * Added `data_len' field to SilcIDCache context.
+
+Tue Mar 20 16:29:00 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Update TODO. Todo in commands in the server.
+
+Tue Mar 20 15:45:14 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added new notify type SILC_NOTIFY_TYPE_UMODE_CHANGE that is
+ used by routers as broadcast packet to inform other routers
+ about the changed user mode.
+
+ Implemented the notify handling in the server. Affected file is
+ silcd/packet_receive.c. Added the function
+ silc_server_send_notify_umode to the silcd/packet_send.[ch].
+
+ * Added new generic Channel Payload and deprecated the New Channel
+ Payload. The New Channel Payload is now the generic Channel
+ Payload.
+
+ * Added new argument `mode' to the silc_server_send_new_channel
+ as it is required in the Channel Payload now.
+
+ * Renamed the SilcChannelPayload to SilcChannelMessagePayload
+ and created a new and real SilChannelPayload to represent the
+ new generic Channel Payload. Implemented the encode/decode
+ for Channel Payload. Affected file lib/silccore/silcchannel.[ch].
+
+ * Added silc_server_get_client_channel_list to return the list
+ of channels the client has joined for WHOIS command reply.
+ Affected file silcd/server.[ch].
+
+ * Implemented the channel list sending in the WHOIS command reply
+ in server and in the client.
+
+ Implemented the channel list displaying on the user interface
+ as well. Affected file silc/client_ops.c.
+
+ * Added silc_channel_payload_parse_list to parse list of Channel
+ Payloads. It returns SilcDList list of SilcChannelPayloads.
+ Client for example can use this function to parse the list of
+ channels it receives in the WHOIS command reply. The caller
+ must free the list by calling silc_channel_payload_list_free.
+ Affected files lib/silccore/silcchannel.[ch].
+
+Mon Mar 19 21:39:15 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added one new argument <user mode> to the WHOIS command reply
+ to return the mode of the user in SILC. Updated the protocol
+ specs.
+
+ Implemented it to the server and client.
+
+Mon Mar 19 18:43:06 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed the mode printing on the user interface on joining.
+ Affected file silc/client_ops.c.
+
+ * Implemented the UMODE command and user modes in general to the
+ client library and to the user interface.
+
+ * Implemented the UMODE command to the server.
+
+ * The server now sends UNKNOWN_COMMAND error status if client sends
+ unknown command. Affected file silcd/command.c.
+
+ * All server commands now handle the command identifier the right
+ way when sending the command reply to the client. The client can
+ use to identify the command replies with the identifier.
+
+Mon Mar 19 16:13:07 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added silc_server_get_client_route to resolve the route to
+ the client indicated by the client ID. Affected file is
+ silcd/server.[ch].
+
+ * Added silc_server_relay_packet as general function to relay
+ packet to arbitrary destination. This deprecates functions
+ like _send_private_message_key, _relay_notify etc. Affected
+ file is silcd/packet_send.[ch].
+
+ Removed silc_server_send_key_agreement,
+ silc_server_send_private_message_key and
+ silc_server_packet_relay_notify functions from the file
+ silcd/packet_send.[ch].
+
+ * Updated TODO.
+
+ * Implemented the SILC_NOTIFY_TYPE_KILLED notify handling in the
+ server. Affected file silcd/packet_receive.[ch].
+
+ * Implemented the KILL command to the client. Implemented the
+ SILC_NOTIFY_TYPE_KILLED notify handling in the client library.
+ Affected files lib/silcclient/command[_reply].c and
+ lib/silcclient/client_notify.c. Implemented the KILL notify
+ printing in the user inteface.
+
+ * Fixed a lot silc_parse_nick memory leaks from the client
+ library in the file lib/silcclient/command.c.
+
+ * Changed the silc_server_send_notify_on_channels's `sender'
+ argument from SilcSocketConnection to SilcClientEntry to
+ check the sender as entry and not as connection object and not
+ to send to the client provided as argument. The affected file
+ is silcd/packet_send.[ch].
+
+ * The notify packets that are destined directly to the client used
+ to not to be processed by the server. Now changed that and the
+ server processes all notify packets. After relaying the packet
+ to the client the notify packet is processed in the server.
+
+ * The silc_server_free_client_data now checks whether there is
+ pending outgoing traffic for the client and purges the data to
+ the network before removing the client entry.
+
+Sun Mar 18 21:02:47 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added SILC_NOTIFY_TYPE_KILLED notify type. It is sent when
+ an client is killed from the SILC Network. Updated the protocol
+ specs accordingly.
+
+ Added new function silc_server_send_notify_killed to the
+ silcd/packet_send.[ch].
+
+ * Added function silc_server_packet_relay_notify to relay notify
+ packets that are destined directly to a client. In this case
+ the server does not process the notify packets but merely relays
+ it to the client. Affected file silcd/packet_send.[ch].
+
+ Added also silc_server_packet_process_relay_notify to check
+ whereto relay the notify. Affected file is
+ silcd/packet_receive.[ch].
+
+ * Implemented the KILL command to the server.
+
+ * Updated TODO.
+
+ * Added the backup schema desgined last fall to the protocol
+ specs for everyone to see. The specification is in the
+ *-spec-xx.txt draft and the packet type definitions for the
+ backup routers is in *-pp-xx.txt draft. Thusly, added also
+ new packet type SILC_PACKET_CELL_ROUTERS.
+
+ * A big security problem in the implementation discovered. The
+ signoff of an client did not cause new channel key generation
+ which it of course should've done. The channel keys must be
+ always re-generated when client leaves (or signoffs) the channel.
+ The silc_server_remove_from_channels funtion now handles
+ the channel key re-generation.
+
+ * Added `sender' argument to the silc_server_send_notify_on_channels
+ to not to send the client provided as argument. Affected file
+ silcd/packet_send.[ch].
+
+Fri Mar 16 15:52:49 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Implemented OPER and SILCOPER commands into the server and
+ the client library.
+
+ * Added silc_auth_verify and silc_auth_verify_data to verify
+ the authentication directly from the authentication payload.
+ It supports verifying both passphrase and public key based
+ authentication. Affected file lib/silccore/silcauth.[ch].
+
+ * Added `hash' field to the SilcIDListData structure. It is the
+ hash negotiated in the SKE protocol. Affected file is
+ silcd/idlist.[ch].
+
+ * Slight redesigning of the SilcAuthPayload handling routines.
+ Do not send SilcPKCS but SilcPublicKey as argument.
+
+ * Implemented the public key authentication support to the
+ serverconfig. The public key is loaded from the provided path
+ and saved as authentication data to void * pointer. Thus,
+ changed the unsigned char *auth_data to void *auth_data;
+
+ * Fixed SHUTDOWN command to send the reply before the server
+ is shutdown. :) Affected file silcd/command.c.
+
+ * Fixed fatal bug in CONNECT command. The hostname was invalid
+ memory and server crashed. Affected file silcd/command.c.
+
+ * Fixed fatal bug in CLOSE command. The server_entry became
+ invalid but was referenced later in the command. Affected file
+ silcd/command.c.
+
+Thu Mar 15 12:46:58 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed fatal bug in failure packet handling. Server ignored
+ the failure and thus crashed when it came.
+
+ * Updated TODO.
+
+Wed Mar 14 20:37:35 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added new SILC_CF_LAG_STRICT command flag that strictly forces
+ that the command may be executed only once in (about) 2 seconds.
+ The old SILC_CF_LAG flag is same but allows command bursts up
+ to five before limiting.
+
+ Added the support for CF_LAG and CF_LAG_STRICT flags to the
+ server code. Various commands now includes the CF_LAG_STRICT
+ flag to disallow any kind of miss-use of the command.
+
+ * Fixed the silc_buffer_unformat to not to allocate any data
+ if the length of the data is zero. It used to allocate the
+ length + 1. Affected file lib/silcutil/silcbuffmt.c.
+
+Wed Mar 14 16:10:30 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Changed the format of AdminConnection configuration section
+ in the server. Added username of the admin to the format.
+ Affected files silcd/serverconfig.[ch].
+
+ Added silc_server_config_find_admin into silcd/serverconfig.[ch]
+ to return admin configuration data by host, username and/or
+ nickname.
+
+Wed Mar 14 13:18:16 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Implemented WHOWAS command to the server. Added the functions:
+
+ silc_server_command_whowas_parse,
+ silc_server_command_whowas_send_reply,
+ silc_server_command_whowas_from_client and
+ silc_server_command_whowas_from_server
+
+ * Added <Client ID> argument to the WHOWAS command reply. Updated
+ the protocol specs accordingly.
+
+ * Implemented WHOWAS command and command_reply to the client
+ library.
+
+ Implemented the WHOWAS printing on the user interface.
+
+Tue Mar 13 22:17:34 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added new argument to the WHOWAS command reply, the real name.
+ It is an optional argument. Updated the protocol specs.
+
+ * Added SilcIDCacheDestructor callback that is registered when
+ the SilcIDCache is allocated. The callback is called when
+ an cache entry in the ID Cache expires, or is purged from the
+ cache. Added into lib/silccore/idcache.[ch].
+
+ Added silc_idlist_client_destructor to the silcd/idlist.[ch]
+ to destruct the client entries when the cache entry expires.
+ Other ID Cache's in server and in the client library ignores
+ the destructor.
+
+ * If the ID Cache entry's `expire' field is zero then the entry
+ never expires. Added boolean `expire' argument to the
+ silc_idcache_add function in the lib/silccore/idcache.[ch].
+ If it is TRUE the default expiry value is used.
+
+ * Added silc_server_free_client_data_timeout that is registered
+ when client disconnects. By default for 5 minutes we preserve
+ the client entry for history - for WHOWAS command.
+
+Tue Mar 13 13:26:18 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added support to the server to enforce that commands are not
+ executed more than once in 2 seconds. If server receives
+ commands from client more frequently, timeout is registered
+ to process the commands. Affected file silcd/command.c.
+ Added new function silc_server_command_process_timeout.
+
+ * Changed NICK_NOTIFY handling in client library to check that
+ if the client's nickname was changed, so there is no need to
+ resolve anything from the server.
+
+ * Removed error printing from the WHOIS and IDENTIFY commands.
+ If error occurs then it is ignored silently in the client library.
+ The application, however, may map the received error to
+ human readable error string. The application currently maps
+ the NO_SUCH_NICKNAME error to string.
+
+ * Made the command status message public to the application. Moved
+ them from lib/silcclient/command_reply.c to
+ lib/silcclient/command_reply.h. The application can map the
+ received command status to the string with the
+ silc_client_command_status_message function.
+
+ * Added check to the server to check that client's ID is same
+ as the Source ID in the packet the client sent. They must
+ match.
+
+Tue Mar 13 12:49:21 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added dist-bzip hook to the Makefile.am to make bzip2
+ compressed distributions.
+
+Mon Mar 12 18:43:38 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Server now enforces the maximum length for the nickname and
+ the channel as protocol specification dictates. 128 bytes for
+ nickname and 256 bytes for channel name.
+
+ * Moved the WHOIS printing to the application. The client libary
+ does not print out the WHOIS information anymore, the application
+ must do it. Renamed silc_client_command_reply_whois_print to
+ the silc_client_command_reply_whois_save.
+
+ The client's idle time is also sent to the application now, and
+ the idle is shown on screen.
+
+ * Added silc_client_command_reply_identify_save to save the
+ received IDENTIFY entries.
+
+ * Do not check for channel private keys in message sending and
+ reception if the channel does not have the PRIVKEY mode set.
+ Affected file lib/silclient/client_channel.c.
+
+Sun Mar 11 20:25:06 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed a minor bug if WHOIS and IDENTIFY command parsing that
+ just surfaced after chaning the JOIN procedure.
+
+Sun Mar 11 14:59:05 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added silc_client_get_clients_by_list to get client entries
+ from Client ID list, that is returned for example by JOIN
+ and USERS command replies. The application should use this
+ function for example when JOIN command reply is received to
+ resolve the clients already on the channel (library does not
+ do that anymore as USERS command reply is not used in the JOIN
+ procedure anymore). Affected files lib/silcclient/silcapi.h and
+ lib/silcclient/idlist.c.
+
+ * JOIN command reply and USERS command reply returns now SilcBuffer
+ pointers instead of unsigned char pointers when returning
+ the client list and mode list.
+
+ * Added <Client ID> argument to the JOIN command reply, mainly
+ for the server to identify for which client the command was
+ originally sent. Updated protocol specs accordingly.
+
+ * Added SilcDlist private_key pointer to the SilcChannelEntry
+ in the client to support the channel private keys. Affected
+ file is lib/silcclient/idlist.h.
+
+ * Added SilcChannelPrivateKey argument to the function
+ silc_client_send_channel_message so that application can choose
+ to use specific private ke if it wants to. If it is not provided,
+ the normal channel key is used, unless private keys are set.
+ In this case the first (key that was added first) is used
+ as the encryption key.
+
+ * Implemented the support for channel private key handling.
+ Implemented the following functions:
+
+ silc_client_add_channel_private_key,
+ silc_client_del_channel_private_keys,
+ silc_client_del_channel_private_key,
+ silc_client_list_channel_private_keys and
+ silc_client_free_channel_private_keys
+
+ Affected file lib/silcclient/client_channel.c.
+
+ * Added the support for the private keys in the channel message
+ sending and encryption and in the message reception and
+ decryption. Affected funtions are
+ silc_client_send_channel_message and silc_client_channel_message.
+
+Sat Mar 10 21:36:22 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added SKE's key verify callback to the client library's
+ KE protocol context. Affected files lib/silcclient/protocol.[ch].
+
+ * Removed the statement that server (or router) must send USERS
+ command reply when joining to the channel so that the client
+ knows who are on the channel. Instead, the client list and
+ client's mode list is now sent in the JOIN command reply to the
+ client who joined channel. This is better solution.
+
+ * Added function silc_server_get_users_on_channel and function
+ silc_server_save_users_on_channel to the silcd/server.[ch].
+
+ * Removed function silc_server_command_send_users from the
+ silcd/command.c.
+
+ * Do not show topic on the client library anymore. The topic is
+ sent in the command reply notify to the application and the
+ application must show the topic now.
+
+Sat Mar 10 00:07:37 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added client searching by nickname hash into the IDENTIFY and
+ WHOIS commands in the server as they were clearly missing from
+ them. Affected file is silcd/command.c.
+
+ * Fixed a bug in private message receiving in the client library.
+ The remote ID was freed and it wasn't supposed, now it is
+ duplicated.
+
+Fri Mar 9 12:40:42 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Minor fix to the channel payload; allocate the data area, as it
+ needs to be of specific length.
+
+ * If the key agreement port is zero then the operating
+ system will define the bound port. Affected files are
+ lib/silcclient/silcapi.h and lib/silcclient/client_keyagr.c.
+
+ * Added new function silc_channel_payload_decrypt into the file
+ lib/silccore/silcchannel.[ch].
+
+ * Moved the channel message etc, check from silc_packet_decrypt
+ to applications. The library calls now a generic
+ SilcPacketCheckDecrypt callback which is to return TRUE or FALSE
+ when the packet is either normal or special. This was done to
+ allow more wide range of checking that was not allowed when
+ the code was in library. Now applications can do virtually any
+ checks to the packet and return to the library the decision how
+ the packet should be processed. Affected files are
+ lib/silccore/silcpacket.[ch].
+
+ Added silc_server_packet_decrypt_check to the server and
+ silc_client_packet_decrypt_check to the client library.
+
+ * Added silc_server_packet_send_srcdest into silcd/packet_send.[ch]
+ to send with specified source and destination information.
+
+ * Channel message delivery between routers was broken after the
+ channel key distribution was fixed earlier. The channel key
+ was used be to distributed to other routers as well which is not
+ allowed by the protocol. Now this is fixed and channel keys
+ really are cell specific and the channel message delivery between
+ routers comply with the protocol specification.
+
+ * Fixed various commands in server to check also the global list
+ for the channel entry and not just the local list. The affected
+ file silcd/command.c.
+
+Thu Mar 8 21:39:03 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added assert()s to buffer formatting and unformatting routines
+ to assert (if --enable-debug) when error occurs. Affected
+ file: lib/silcutil/silcbuffmt.c.
+
+ * Changed to auto-reconnect to check whether the remote host is
+ router and register the re-connect timeout if it is. It used
+ to check that whether we are normal server, but router must do
+ auto-reconnect with another router as well. Affected file
+ silcd/server.c.
+
+ * Removed the [<key len>] option from CMODE command as the cipher
+ name decides the key length, nowadays. See the defined ciphers
+ from the protocol specification.
+
+ * Added [<hmac>] option to the CMODE command to define the HMAC
+ for the channel. Added SILC_CMODE_HMAC channel mode.
+
+ * Added [<hmac>] option for the JOIN command so that user can
+ select which HMAC is used to compute the MACs of the channel
+ messages.
+
+ * Added Hmac field to the Channel Message Payload. The integrity
+ of plaintext channel messages are now protected by computing
+ MAC of the message and attaching the MAC to the payload. The
+ MAC is encrypted. Now, it is clear that this causes some
+ overhead to the size of the packet but rationale for this is that
+ now the receiver can verify whether the channel message decrypted
+ correctly and also when private keys are set for the channel the
+ receiver can decrypt the packet with several keys and check from
+ the MAC which key decrypted the message correctly.
+
+ * Added silc_cipher_encrypt and silc_cipher_decrypt into the
+ lib/silccrypt/silccipher.[ch].
+
+ * Added silc_hash_len to return the digest length into the
+ lib/silcrypt/silchash.[ch].
+
+ * Rewrote parts of Silc Channel Payload interface in the
+ lib/silccore/silcchannel.[ch]. The encode function now also
+ encrypts the packet and parse function decrypts it.
+
+Wed Mar 7 20:58:50 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed a minor formatting bug in the SKE's key material processing.
+ It actually might have processed the keys wrong way resulting
+ into wrong keys.
+
+ * Redefined the mandatory HMAC algorithms and added new algorithms.
+ Added hmac-sha1-96 and hmac-md5-96 which are normal hmac-sha1
+ and hmac-md5 truncated to 96 bits. The mandatory is now
+ hmac-sha1-96. Rest are optional (including the one that used
+ to be mandatory). Rationale for this is that the truncated HMAC
+ length is sufficient from security point of view and can actually
+ make the attack against the HMAC harder. Also, the truncated
+ HMAC causes less overhead to the packets. See the RFC2104 for
+ more information.
+
+ * Added new [hmac] configuration section. The SKE used to use
+ the hash names (md5 and sha1) in the SKE proposal as HMCAS which
+ is of course wrong. The official names that must be proposed in
+ the SKE are the ones defined in the protocol specification
+ (hmac-sha1-96 for example). The user can configure any hmac
+ using any hash function configured in the [hash] section. At
+ least, the mandatory must be configured.
+
+ Rewrote the HMAC interface in lib/silccrypt/silchmac.[ch].
+
+ * Added HMAC list to the SKE proposal list. It has now both
+ hash algorithm list and HMAC list. This makes the protocol
+ incompatible with previous versions. The SKE now seems to work
+ the way it is supposed to work, for the first time actually.
+
+ * Defined plain Hash algorithms to the protocol specification.
+ Added sha1 and md5.
+
+Tue Mar 6 15:36:11 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Implemented support for key agreement packets into the server.
+ Added functions silc_server_key_agreement and
+ silc_server_send_key_agreement. Other than these functions,
+ server has nothing to do with this packet.
+
+ * Added support for private message key packets into the server.
+ Added functions silc_server_private_message_key and
+ silc_server_send_private_message_key.
+
+ * Updated TODO.
+
+ * Changed the silc_[client|server]_protocol_ke_set_keys to be
+ called in the protocol's final callback instead in the END
+ protocol state. This makes a little more sense and in the same
+ time in client we can use the same protocol routines for normal
+ key exchange and to key agreement packet handling as well.
+
+ * Added to both client's and server's KE protocol context the
+ SilcSKEKeyMaterial pointer to save the key material. We will
+ bring the key material to the protocol's final callback by doing
+ this. The final callback must free the key material.
+
+ * Added SKE's packet_send callback into client's KE protocol
+ context so that the caller can choose what packet sending function
+ is used. This way we can use different packet sending when
+ doing normal SKE when doing key agreement packet handling (in
+ the key agreement packet handling we do not want to encrypt
+ the packets).
+
+ * Implemented the responder side of the key agreement routines
+ in the client. The client can now bind to specified port and
+ accept incoming key negotiation. The key material is passed
+ to the application after the protocol is over.
+
+ * Implemented the processing of incoming Key Agreement packet
+ in the client. Added function silc_client_key_agreement to
+ process the packet.
+
+ * Implemented the intiator side of the key agreement routines
+ in the client. The client can now initiate key agreement with
+ another remote client. The key material is passed to the
+ application after the protocol is over.
+
+ * Created client_keyagr.c to include all the key agreement
+ routines.
+
+ * Added macro SILC_TASK_CALLBACK_GLOBAL which is equal to the
+ SILC_TASK_CALLBACK except that it is not static.
+
+ * Created client_notify.c and moved the Notify packet handling
+ from the client.[ch] into that file.
+
+ * Created client_prvmsg.c and moved all private message and
+ private message key routines from the client.[ch] into that file.
+
+ * Create client_channel.c and moved all channel message and
+ channel private key routines from the client.[ch] into that file.
+
+ * Changed silc_client_get_client_by_id_resolve to resolve with
+ WHOIS command instead of IDENTIFY command, in the file
+ lib/silclient/idlist.c.
+
+Mon Mar 5 18:39:49 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Implemented the SKE's responder side to the Client library.
+
+ * When FAILURE is received to the protocol do not trust it
+ blindly. Register a timeout to wait whether the remote closes
+ the connection as it should do it, only after that process the
+ actual failure. This was changed to both client and server.
+
+ * Added client_internal.h to include some of the structures
+ there instead of client.h in lib/silcclient/.
+
+ * Added function silc_task_unregister_by_callback to unregister
+ timeouts by the callback function.
+
+Sat Mar 3 19:15:43 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Some "Incomplete WHOIS info" errors has been appearing on the
+ log files. Took away the entry->userinfo check from WHOIS
+ reply sending. The entry->userinfo is now " " if client did not
+ provide one. I thought this was fixed earlier but something
+ is wrong still. Let's see if the error still appears.
+
+Wed Feb 28 20:56:29 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed a minor bug in the login when the channel key is
+ re-generated in the server. It used to generate the key in
+ wrong order and thus caused problems in the channel traffic.
+
+ * Fixed a minor bug in channel key distsribution after
+ KICK command. The key was not sent to the router even though
+ it should've been.
+
+Tue Feb 27 20:24:25 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added silc_ske_process_key_material_data as generic routine
+ to process any key material as the SILC protocol dictates. The
+ function is used by the actual SKE library but can be used by
+ applications as well. This relates to the private message keys
+ and the channel private keys since they must be processed the
+ same way the normal SILC session keys. The protocol dictates
+ this. Affected files: lib/silcske/silcske.[ch].
+
+ Added also silc_ske_free_key_material to free the
+ SilcSKEKeyMaterial structure.
+
+ * Defined silc_cipher_set_key function to set the key for
+ cipher without using the object's method function. The affected
+ files: lib/silccrypt/silccipher.[ch].
+
+ * Implemented silc silc_client_add_private_message_key,
+ silc_client_add_private_message_key_ske,
+ silc_client_del_private_message_key,
+ silc_client_list_private_message_keys and
+ silc_client_free_private_message_keys functions in the
+ client library.
+
+ Added functions silc_client_send_private_message_key to send
+ the Private Message Key payload and silc_client_private_message_key
+ to handle incoming Private Message Key payload.
+
+ * Added Cipher field to the Private Message Key payload to set
+ the cipher to be used. If ignored, the default cipher defined
+ in the SILC protocol (aes-256-cbc) is used.
+
+Tue Feb 27 13:30:52 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Removed lib/silcclient/ops.h file.
+
+ Redefined parts of the SILC Client Library API. Created new
+ file silcapi.h that deprecates the ops.h file and defines the
+ published Client Library API. Defined also private message key
+ API and channel private key API into the file.
+
+ This is the file that the application must include from the
+ SILC Client Library. Other files need not be included by
+ the application anymore.
+
+ * Added new key_agreement client operation callback and also
+ defined the Key Agreement library API for the application.
+
+Tue Feb 27 11:28:31 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added new packet type: SILC_PACKET_KEY_AGREEMENT. This packet
+ is used by clients to request key negotiation between another
+ client in the SILC network. If the negotiation is started it
+ is performed using the SKE protocol. The result of the
+ negotiation, the secret key material, can be used for example
+ as private message key.
+
+ Implemented the Key Agreement payload into the files
+ lib/silccore/silauth.[ch].
+
+Mon Feb 26 12:13:58 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Redefined ciphers for the SILC protocol. Added some new ciphers
+ and defined the key lengths for the algorithms. Changed the
+ code accordingly. The default key length is now 256 bits.
+
+ * Fixed SKE key distribution function silc_ske_process_key_material
+ when the key length is more than 128 bits. The default key
+ length in SILC is now 256 bits.
+
+ * Added new command status type: SILC_STATUS_ERR_UNKOWN_ALGORITHM
+ to indicate unsupported algorithm.
+
+ * Renamed rijndael.c to aes.c and all functions as well.
+
+ * Fixed a long standing channel key setting bug in client library.
+ Weird that it has never surfaced before.
+
+ * Fixed bug in channel deletion. If the entire channel is removed
+ then it must also delete the references of the channel entry
+ from the client's channel list as the client's channel entry and
+ the channel's client entry share same memory.
+
+Sun Feb 25 20:47:29 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Implemented CONNECT and SHUTDOWN commands in the client.
+
+ * Implemented CLOSE command to the client.
+
+ * Added the function silc_idlist_find_server_by_name into the
+ files silcd/idlist.[ch].
+
+ Added the function silc_idlist_find_server_by_conn into the
+ files silcd/idlist.[ch].
+
+Sat Feb 24 23:45:49 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * DIE command was renamed to SHUTDOWN. Updated the both code
+ and protocol specs.
+
+ * Defined SILC_UMODE_NONE, SILC_UMODE_SERVER_OPERATOR and
+ SILC_UMODE_ROUTER_OPERATOR modes into lib/silccore/silcmode.h.
+
+ * Implemented CONNECT, CLOSE and SHUTDOWN commands to the server
+ side.
+
+ * Added function silc_server_create_connection function to create
+ connection to remote router. My server implementation actually
+ does not allow router to connect to normal server (it expects
+ that normal server always initiates the connection to the router)
+ so the CONNECT command is only good for connecting to another
+ router.
+
+Sat Feb 24 16:03:45 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added SILC_NOTIFY_TYPE_KICKED to indicate that the client
+ or some other client was kicked from the channel.
+
+ Implemented the handling of the notify type to both client
+ and server.
+
+ Implemented silc_server_send_notify_kicked to send the KICKED
+ notify. It is used to send it to the server's primary router.
+
+ * Implemented the KICK command into server and client.
+
+ * Added `query' argument to the silc_idlist_get_client function
+ to indicate whether to query the client from server or not if
+ it was not found.
+
+ * Added new command status type SILC_STATUS_ERR_NO_CHANNEL_FOPRIV
+ to indicate that the client is not channel founder.
+
+ * Updated TODO.
+
+Sat Feb 24 00:00:55 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Removed the rng context from SilcPacketContext structure and
+ changed that the packet routine uses the Global RNG API.
+
+Fri Feb 23 11:22:57 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added support for quit message that client can "leave" on the
+ channel when it quits the SILC. It is ditributed inside the
+ SILC_NOTIFY_TYPE_SIGNOFF notify type.
+
+ Added silc_server_free_client_data that will take the
+ signoff message as argument.
+
+ * Changed SKE routines to use the silc_pkcs_sign/verify routines.
+
+Thu Feb 22 23:05:36 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Updated parts of the protocol specification to keep it up
+ to date.
+
+Thu Feb 22 15:08:20 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added List flag (SILC_PACKET_FLAG_LIST) to indicate list of
+ payloads in one packet.
+
+ * Deprecated following packet types: NEW_ID_LIST, NEW_CHANNEL_LIST,
+ NEW_CHANNEL_USER_LIST, SET_MODE and SET_MODE_LIST. List packets
+ use now the new List flag.
+
+ * Also deprecated the following packet types: REPLACE_ID,
+ NEW_CHANNEL_USER and REMOVE_CHANNEL_USER packet types.
+
+ * Added list support for Notify packet in server.
+
+ * Added silc_server_send_notify_channel_change to send the
+ CHANNEL_CHANGE notify type to replace channel ID's. Deprecates
+ the silc_server_send_replace_id.
+
+ * Added silc_server_send_notify_nick_change to send the
+ NICK_CHANGE notify type. Deprecates the function
+ silc_server_send_replace_id.
+
+ * Added silc_server_send_notify_join to send the JOIN notify type.
+ Deprecates the function silc_server_send_new_channel_user.
+
+ * Added silc_server_send_notify_leave to send LEAVE notify type.
+ Deprecates the function silc_server_send_remove_channel_user.
+
+ * Added silc_server_send_notify_cmode and
+ silc_server_send_notify_cumode to send CMODE and CUMODE notify
+ types. Deprecates the silc_server_send_set_mode function.
+
+ * Added SERVER_SIGNOFF notify type to indicate that server has
+ quit. This means that all clients on the channel from that
+ server will drop. This can be also used when netsplit happens.
+
+ Deprecated REMOVE_ID packet type since it is not needed anymore
+ even from server.
+
+ Added silc_server_send_notify_server_signoff to send the
+ SERVER_SIGNOFF notify type. Deprecates the function
+ silc_server_send_remove_id.
+
+ Added also silc_server_send_notify_signoff to send the
+ SIGNOFF notify type.
+
+ * Employed the PKCS #1. It is the mandatory way to do RSA in the
+ SILC protocol from this day on. Changed the protocol
+ specification as well.
+
+ * Added silc_server_send_notify_topic_set to send TOPIC_SET
+ notify type. It is used between routers to notify about
+ topic changes on a channel.
+
+ * Added silc_id_dup into lib/silccore/id.[ch] to duplicate
+ ID data.
+
+ * Partly updated the protocol specification to comply with the
+ changes now made. It is still though a bit outdated.
+
+ * The JOIN notify type now takes one extra argument <Channel ID>.
+ The packet used to be destined to the channel but now the
+ JOIN type may be sent as list thus it is impossible to
+ destine it to any specific channel. By adding this argument
+ it is again possible.
+
+Wed Feb 21 22:39:30 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added CREDITS file. The CHANGES and CREDITS file will appear
+ in the distribution as well.
+
+Wed Feb 21 14:17:04 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Implemented CMODE_CHANGE, CUMODE_CHANGE and TOPIC_SET notify
+ types in the server's silcd/packet_receive.c.
+
+ * Implemented CMODE and CUMODE to work in router environment.
+
+ * Fixed minor encoding and decoding buglet from the
+ lib/silccore/silcmode.c.
+
+ * Fixed buffer overflow from lib/silcclient/command.c in USERS
+ command parsing.
+
+Wed Feb 21 12:44:00 EET 2001 Mika Boström <bostik@lut.fi>
+
+ * Changed all SilcConfigServer* and silc_config_server* to
+ SilcServerConfig* and silc_server_config*, respectively.
+ Patch by Bostik.
+
+Wed Feb 21 00:10:00 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Associated the ID (client or server ID) to the Authentication
+ Payload to avoid any possibility of forging. Updated the
+ protocol specification and the code accordingly.
+
+Tue Feb 20 14:14:14 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * The RSA key length is now save to the RsaKey context in the
+ key generation process in lib/silccrypt/rsa.c. The key length
+ is now used to figure out the maximum size of the block allowed
+ to be encrypted/signed.
+
+ * Added silc_mp_mp2bin_noalloc into lib/silcmath/mpbin.[ch]. It
+ is equivalent to the silc_mp_mp2bin but does not allocate any
+ memory.
+
+ * Changed silc_mp_mp2bin API to take length argument. If it is
+ non-zero then the buffer is allocated that large. If zero, then
+ the size is approximated using silc_mp_sizeinbase, which however
+ is not relieable.
+
+ * Created Global RNG API which is global RNG that application can
+ initialize. After initializing, any routine anywhere in the
+ code (including library) can use RNG without allocating a new
+ RNG object. This was done to allow this sort of use of the
+ RNG in code that has no chance to allocate RNG object. All
+ applications currently allocate this and many routines in the
+ library use this. Affected file lib/silccrypt/silcrng.[ch].
+
+ * Removed the RNG kludge from lib/silcmath/primegen.c and changed
+ it to use the Global RNG API.
+
+ * Defined Authentication Payload into protocol specification that
+ is used during SILC session to authenticate entities. It is
+ used for example by client to authenticate itself to the server
+ to obtain server operator privileges.
+
+ Implemented this payload into the lib/silccore/silcauth.[ch].
+ Implemented also routines for public key based authentication
+ as the new protocol specification dictates.
+
+ Moved definitions of different authentication methods from
+ lib/silccore/silcprotocol.h into lib/silccore/silcauth.h.
+
+ * Added silc_pkcs_encrypt, silc_pkcs_decrypt, silc_pkcs_sign,
+ silc_pkcs_verify and silc_pkcs_sign_with_hash and
+ silc_pkcs_verify_with_hash functions into the file
+ lib/silccrypt/silcpkcs.[ch].
+
+Mon Feb 19 19:59:28 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * The client entry's userinfo pointer must be always valid.
+ Otherwise the [<unknown>] bug will surface beacuse the WHOIS
+ will fail since it requires the userinfo. Now, the userinfo
+ is allocated as "" if actual userinfo does not exist. Actually,
+ it must exist and it is totally Ok to drop client connections
+ that does not announce the userinfo. However, we will make
+ this workaround for now.
+
+ * Added silc_net_get_remote_port into lib/silcutil/silcnet.[ch]
+ to return the remote port by socket.
+
+Mon Feb 19 14:26:49 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Changed SILC_SERVER_COMMAND_EXEC_PENDING macro to the name
+ SILC_SERVER_PENDING_EXEC and added an new macro
+ SILC_SERVER_PENDING_DESTRUCTOR which is called to free the
+ data or when error occurs while processing the pending command.
+
+ Added new argument `destructor' into silc_server_command_pending
+ and to the SilcServerCommandPending object. This destructor is
+ now called after calling the pending callback or if error occurs
+ immediately. If error occurs the actual pending callback won't
+ be called at all - only the destructor. The destructor may be
+ NULL if destructor is not needed.
+
+ All this applies for client library code as well. Similar
+ changes were made there as well for the pending commands.
+
+ In the client, the application must now allocate the
+ SilcClientCommandContext with the silc_client_command_alloc
+ function.
+
+ * Added reference counter to the SilcServerCommandContext. Added
+ function silc_server_command_alloc and silc_server_command_dup
+ functions.
+
+ Same type of functions added to the client library for the same
+ purpose as well.
+
+ * Removed the cmd_ident from IDListData away since it is now
+ global for all connections. It is the command identifier used
+ in command sending and with pending commands. The affected file
+ is silcd/idlist.h.
+
+ * Added reference counter to the SilcSocketConnection objecet to
+ indicate the usage count of the object. The object won't be
+ freed untill the reference counter hits zero. Currently only
+ server uses this, and client ignores it. The client must be
+ set to use this too later. The affected files are
+ lib/silccore/silcsockconn.[ch]. Added also the function
+ silc_socket_dup to increase the reference counter.
+
+ This was mainly added because it is possible that the socket
+ is removed underneath of pending command or other async
+ operation. Now it won't be free'd and proper DISCONNECTING
+ flags, etc. can be set to avoid sending data to connection that
+ is not valid anymore.
+
+ * Added SILC_SET_DISCONNECTING to server.c when EOF is read from
+ the connection. After that it sets SILC_SET_DISCONNECTED.
+ It is, however, possible that the socket data is not still freed.
+ The silc_server_packet_process now checks that data is not
+ read or written to connection that is DISCONNECTED. The socket
+ get's freed when the reference counter hits zero.
+
+Mon Feb 19 00:50:57 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Changed the client operation API: channel_message operation's
+ `sender' is now the client entry of the sender, not the nickname
+ and the `channel' is the channel entry, not the channel name.
+
+ In the private_message operation the `sender' is now also the
+ client entry of the sender not the nickname.
+
+ Affected file is lib/silcclient/ops.h and all applications
+ using the client operations.
+
+Sat Feb 17 22:11:50 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Moved the calling of ops->connect() from connect_to_server_final
+ into receive_new_id functin since that is the point when the
+ client is actually allowed to send traffic to network. The
+ affected file is lib/silcclient/client.c.
+
+Sat Feb 17 13:15:35 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * When receiving NEW_CHANNEL_LIST, NEW_CHANNEL_USER_LIST,
+ NEW_ID_LIST and SET_MODE_LIST packets, broadcast the list packet
+ (if needs broadcasting) instead of broadcasting the packets one
+ by one which would make a burst in the network traffic.
+
+ * Added `broadcast' argument to the functions in silcd/server.[ch]
+ silc_server_create_new_channel[_with_id] to indicate whether
+ to send New Channel packet to primary router.
+
+Sat Feb 17 01:06:44 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added new function into the silcd/server.[ch] files:
+ silc_server_create_new_channel_with_id to create new channel with
+ already existing Channel ID.
+
+ * Added new packet type SILC_PACKET_SET_MODE_LIST into the file
+ lib/silccore/silcpacket.h. This packet is used t send list of
+ Set Mode payloads inside one packet. Server uses this to set
+ the modes for the channels and clients on those channels, that it
+ announced to the router when it connected to it. The protocol
+ specification has been updated accordingly.
+
+ * The silc_server_new_channel did not handle the packet coming
+ from normal server as it normally does not send that. However,
+ when it announces its channels it does send it. Implemented
+ the support for that.
+
+ * Added SILC_ID_CHANNEL_COMPARE macro to compare to Channel ID's
+ into the file lib/silccore/id.h.
+
+Fri Feb 16 23:57:29 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed memory leaks in the functions silc_idlist_del_client,
+ silc_idlist_del_channel and silc_idlist_del_server in the file
+ silcd/idlist.c. All of those leaked like a sieve.
+
+ * Fixed some small memory leaks in the client's function
+ silc_client_notify_by_server.
+
+ * Added functions into silcd/server.c: silc_server_announce_clients,
+ silc_server_announce_channels and silc_server_announce_server.
+ These functions are used by normal and router server to announce
+ to its primary router about clients, channels and servers (when
+ router) that we own. This is done after we've connected to the
+ router.
+
+ These functions effectively implements the following packet types:
+ SILC_PACKET_NEW_CHANNEL_LIST, SILC_PACKET_NEW_CHANNEL_USER_LIST
+ and SILC_PACKET_NEW_ID_LIST.
+
+ * Added new functions into the silcd/packet_receive.[ch]:
+ silc_server_new_id_list, silc_server_new_channel_list and
+ silc_server_new_channel_user_list to handle the incoming
+ NEW_ID_LIST, NEW_CHANNEL_LIST and NEW_CHANNEL_USER_LIST packets.
+
+ * Added support of changing Channel ID in the function
+ silc_server_replace_id. If the server that announces a channel
+ to the router already exists in the router (with same name but
+ with different Channel ID), router is responsible to send
+ Replace ID packet to the server and force the server to change
+ the Channel ID to the one router has.
+
+ * Added new notify type SILC_NOTIFY_TYPE_CHANNEL_CHANGE to notify
+ client that the Channel ID has been changed by the router. The
+ normal server sends this to the client. Client must start using
+ the new Channel ID as the channel's ID.
+
+ Implemented handling of this new type into lib/silcclient/client.c
+ into the function silc_client_notify_by_server.
+
+ * Added new function silc_idlist_replace_channel_id into the files
+ silcd/idlist.[ch] to replace the Channel ID.
+
+Fri Feb 16 14:14:00 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Call silc_server_command_identify_check always when processing
+ the IDENTIFY command in silcd/command.c
+
+Thu Feb 15 20:07:37 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added new packet type SILC_PACKET_HEARTBEAT that is used to
+ send keepalive packets. The packet can be sent by clients,
+ servers and routers.
+
+ Added function silc_socket_set_heartbeat into the file
+ lib/silccore/silcsockconn.[ch] to set the heartbeat timeout.
+ If not set, the heartbeat is not performed. The actual
+ heartbeat is implemented in the low level socket connection
+ library. However, application is responsible of actually
+ sending the packet.
+
+ Added silc_server_send_heartbeat to send the actual heartbeat
+ packet into silcd/packet_send.[ch]. Server now performs
+ keepalive with all connections.
+
+ * Added silc_task_get_first function into lib/silcutil/silctask.c
+ to return the timeout task with shortest timeout. There was a bug
+ in task unregistration that caused problems. TODO has been
+ updated to include that task system must be rewritten.
+
+ * The client library will now resolve the client information when
+ receiving JOIN notify from server for client that we know but
+ have incomplete information.
+
+ * Rewrote parts of silc_server_remove_from_channels and
+ silc_server_remove_from_one_channel as they did not remove the
+ channel in some circumstances even though they should've.
+
+ * Encryption problem encountered in server:
+
+ The LEAVE command used to send the Channel Key packet to the
+ router immediately after generating it. However, the code
+ had earlier sent Remove Channel user packet but not immediately,
+ ie. it was put to queue. The order of packets in the router
+ was that Channel Key packet was first and Remove Channel User
+ packet was second, even though they were encrypted in the
+ reverse order. For this reason, MAC check failed. Now, this
+ is fixed by not sending the Channel Key packet immediately but
+ putting it to queue. However, this is more fundamental problem:
+ packets that are in queue should actually not be encrypted
+ because packets that are sent immediately gets encrypted
+ actually with wrong IV (and thus MAC check fails). So, packets
+ that are in queue should be encrypted when they are sent to
+ the wire and not when they put to the queue.
+
+ However, the problem is that the current system has not been
+ designed to work that way. Instead, the packet is encrypted
+ as soon as possible and left to the queue. The queue is then
+ just purged into wire. There won't be any fixes for this
+ any time soon. So, the current semantic for packet sending
+ is as follows:
+
+ o If you send packet to remote host and do not force the send
+ (the packet will be in queue) then all subsequent packets to the
+ same remote host must also be put to the queue. Only after the
+ queue has been purged is it safe again to force the packet
+ send immediately.
+
+ o If you send all packets immediately then it safe to send
+ any of subsequent packets through the queue, however, after
+ the first packet is put to queue then any subsequent packets
+ must also be put to the queue.
+
+ Follow these rules and everything works fine.
+
+Thu Feb 15 14:24:32 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added new function silc_server_remove_clients_by_server to
+ remove all client entries from ID list when the server connection
+ is lost. In this case it is also important to invalidate all
+ client entires as they hold the invalid server entry. This
+ fixes fatal bug when server has lost connection and will reconnect
+ again.
+
+Wed Feb 14 16:03:25 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Made some sanity checks to silc_server_daemonise like to check
+ whether the requested user and group actually exists.
+
+ * Added sanity check to SKE's silc_ske_responder_finish to check
+ that the public and private key actually is valid.
+
+ * Invalidate the client's nickname when receiving Replace ID
+ packet and the Client ID is being replaced. This means that the
+ server will query the nickname if someone needs it (client)
+ a bit later.
+
+ * Sort the ID Cache in client library when the ID Cache data
+ has changed (needs sorting).
+
+ * Do not allow for SILC client to create several connections to
+ several servers. The client does not support windows right now
+ and generating multiple connections causes weird behaviour.
+
+ Irssi-silc client does support windows and can handle several
+ connections without problems, see: www.irssi.org and SILC plugin.
+
+ * Fixed some places where client was added to the IDList. The
+ rule of thumb is following (in order to get everything right):
+ If the client is directly connected local client then the
+ `connection' argument must be set and `router' argument must be
+ NULL to silc_idlist_add_client function. If the client is not
+ directly connected client then the `router' argument must
+ bet set and the `connection' argument must be NULL to the
+ silc_idlist_add_client function.
+
+ * The funtion silc_server_packet_send_local_channel actually did
+ not check whether the client was locally connected or not. It
+ does that now. Fixed a bug related to LEAVE command.
+
+ * Fixed Remove Channel User payload parsing bug in server's
+ silcd/packet_receive.c. Fixed a bug related to LEAVE command.
+
+ * The server's silc_server_save_channel_key now checks also the
+ global ID list for the channel as it might not be in the local
+ list. Fixed a bug related to LEAVE command.
+
+ * Is this the end of the [<unknown>] buglet that has been lurking
+ around for a long time? A little for loop fix in server's
+ silc_server_command_whois_parse that is used by both IDENTIFY
+ and WHOIS command. At least, this was a clear bug and a cause
+ of one type of [<unknown>] buglet.
+
+ * WHOIS and IDENTIFY commands call the function
+ silc_server_command_[whois/identify]_check function even if
+ we are not router server.
+
+Tue Feb 13 19:55:59 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added --with-gmp configuration option. If set the GMP
+ is always compiled in the SILC source tree. If not set then
+ it is checked whether the system has the GMP3 installed. If
+ it has then the GMP won't be compiled (the system's headers
+ and library is used), if it doesn't have it then the GMP is
+ compiled in the SILC source tree.
+
+Mon Feb 12 11:20:32 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Changed RSA private exponent generation to what PKCS #1
+ suggests. We try to find the smallest possible d by doing
+ modinv(e, lcm(phi)) instead of modinv(e, phi). Note: this is
+ not security fix but optimization.
+
+Sun Feb 11 18:19:51 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added new config entry [Identity] to fork the server and run
+ it as specific user and group. A patch from Bostik.
+
+ * Imported Dotconf configuration library into lib/dotconf.
+ This will be used to create the SILC configuration files later.
+ It will appear in the distsribution after this commit.
+
+Sat Feb 10 21:13:45 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * A big code auditing weekend happening. Auditing code for
+ obvious mistakes, bugs and errors. Also, removing any code
+ that is obsolete.
+
+ Removed files for being obsolete:
+
+ o lib/silcutil/silcbuffer.c (the buffer interface is entirely in
+ inline in the file lib/silcutil/silcbuffer.h)
+
+ o lib/silcutil/silcbufutil.c (the header has inline versions)
+
+ Changed code to fix possible error conditions:
+
+ o The buffer formatting routines now check that the destination
+ buffer really has enough space to add the data. This applies for
+ both buffer formatting and unformatting
+ (lib/silcutil/silcbuffmt.[ch]). Also, the entire buffer
+ unformatting was changed to accomodate following rules:
+ XXX_*STRING_ALLOC will allocate space for the data into the pointer
+ sent to the function while XXX_*STRING will not allocate or copy
+ the data into the buffer. Instead it sets the pointer from the
+ buffer into the pointer sent as argument (XXX_*STRING used to
+ require that the pointer must be allocated already). This change
+ makes this whole thing a bit more consistent and more optimized
+ (note that the data returned in the unformatting with XXX_*STRING
+ must not be freed now). The routines return now -1 on error.
+
+ o Tried to find all code that use buffer_format and buffer_unformat
+ and added return value checking to prevent formatting and
+ especially unformatting errors and possible subsequent fatal
+ errors.
+
+ o Changed ske->x and ske->KEY to mallocated pointers in
+ lib/silcske/silcske.h. Fixed possible data and memory leak.
+
+ o Added return value checking to all *_parse* functions. Fixed
+ many memory leaks as well.
+
+ o Added length argument to silc_id_str2id in lib/silccore/id.[ch]
+ so that buffer overflows would not happen. All code now also
+ checks the return value as it can fail.
+
+Mon Feb 5 20:08:30 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added reconnection support to server if the normal server looses
+ its connection to the router (for example if router is rebooted).
+ The server performs normal reconnection strategy implemented
+ to the server. Affected file silcd/server.c.
+
+Sun Feb 4 13:18:32 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added new packet type SILC_PACKET_SET_MODE that is used to
+ distribute the information about changed modes (for clients,
+ channels and clients channel modes) to all routers in the
+ network. Updated the protocol specification accordingly.
+
+ Added functions into silcd/packet_send.c and
+ silcd/packet_receive.c: silc_server_send_set_mode,
+ silc_server_set_mode.
+
+ Added new files silcmode.[ch] into lib/silccore that implements
+ the encoding and decoding of Set Mode Payload. Added new type
+ SilcSetModePayload. Moved the definitions of different modes
+ from lib/silccore/silcchannel.h into lib/silccore/silcmode.h.
+
+Sat Feb 3 15:44:54 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Oops, a little mistake in server's connection authentication
+ protocol. The protocol is not ended with FAILURE but with
+ SUCCESS if the authentication is Ok. :) Affected file is
+ silcd/protocol.c.
+
+ * Implemented NICK_CHANGE notify handling in server in the file
+ silcd/packet_receive.c The NICK_CHANGE notify is distributed to
+ the local clients on the channel. After the changing nickname
+ in router environment snhould work and the [<unknown>] nickname
+ should appear no more.
+
+ The silc_server_replace_id function that receives the Replace ID
+ payload now sends the NICK_CHANGE notify type also in the file
+ silcd/packet_receive.c
+
+ * Changed WHOIS and IDENTIFY command to support the maximum amount
+ of arguments defined in protocol specs (3328 arguments). This
+ fixed a bug that caused problems when there were more than three
+ users on a channel.
+
+Fri Feb 2 11:42:56 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added extra parameter, command identifier, to the
+ silc_client_send_command so that explicit command identifier
+ can be defined.
+
+ Changed that ID list routines uses specific command identifier
+ when sending WHOIS/IDENTIFY requests to the server so that they
+ can be identified when the reply comes back.
+
+ Affected files lib/silcclient/command.[ch],
+ lib/silcclient/client.c and lib/silcclient/idlist.[ch].
+
+ * Added `sender' argument to silc_server_packet_send_to_channel
+ to indicaet the sender who originally sent the packet to us
+ that we are now re-sending. Ignored if NULL. Affected file
+ silcd/packet_send.[ch].
+
+ * Added some server statistics support in silcd/server_internal.h
+ SilcServerStatistics structure and around the server code. Also
+ send some nice statistics information when client is connecting
+ to the client.
+
+Thu Feb 1 23:31:21 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed channel ID decoding in server's JOIN command reply in
+ silcd/command_reply.c
+
+ * Fixed braodcasting of replace ID payload to not to send it if
+ we are standalone server in silcd/packet_receive.c.
+
+ * Fixed all channel message sending routines to not to send
+ packets to clients that has router set, since they are routed
+ separately in the same function earlier. Affects file
+ silcd/packet_send.c and all channel packet sending functions.
+
+ * In USERS reply, res_argv[i] are not allocated, the table
+ is allocated. Thus changed that free the table, not its
+ internals.
+
+ * In server's whois_check and identify_check if the client is
+ locally connected do not send any WHOIS commands - they are not
+ needed.
+
+Thu Feb 1 21:32:27 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed some minor bugs in client when sending WHOIS command. The
+ arguments was in wrong order.
+
+ * Removed statis function add_to_channel from server in
+ silcd/command.c that was previously used with the joining but
+ is obsolete now.
+
+ * Tested USERS command in router environment successfully with two
+ routers, two servers and two clients.
+
+Thu Feb 1 00:54:26 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Reorganized the USERS command and command reply in client library
+ in lib/silcclient/command.c and lib/silcclient/command_reply.c.
+ When the command is given by user we register a pending command
+ callback that will reprocess the command after the reply has been
+ received from the server. When reprocessing the packet we then
+ display the information. Thus, the USERS information is displayed
+ now in the command callback instead of in the command reply
+ callback. The processing of the command is same as previously
+ when server has sent the command reply in the JOINing process.
+
+ * Added to USERS command in silcd/command_reply.c to join the client,
+ we didn't use to know about, to the channel after we've created
+ a client entry for it. Also, for clienet we did know already still
+ check whether it is on the channel or not and add it if not.
+
+ * Removed silc_server_command_join_notify as the function and its
+ use was obsolete.
+
+Tue Jan 30 22:39:15 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Changed the client's pending command handling to the same as the
+ server's pending command handling. It is also now possible to
+ execute command reply functions from other command reply
+ function as the function callbacks for commands and command
+ replies are one and same. The pending commands are not static
+ list anymore, it is mallocated SilcDList in lib/silcclient/client.h
+ in client connection context. Thus, pending commands are server
+ connection specific as it is convenient.
+
+ Changed the function silc_client_command_pending and
+ silc_client_command_pending_del and added new function
+ silc_client_command_pending_check. Removed the
+ SILC_CLIENT_CMD_REPLY_EXEC, and SILC_CLIENT_PENDING_COMMAND_CHECK
+ macros.
+
+ * Added cmd_ident, current command identifier, to the client
+ connection context in lib/silcclient/client.h to keep track on
+ command identifiers used in command sending. Client's command reply
+ function handling now supports the mandatory command identifiers.
+
+ * Added SILC_CLIENT_COMMAND_EXEC_PENDING macros to all command reply
+ funtions in client to fully support pending command callbacks.
+
+ * NOTE: the name_list in USERS (old NAMES) command is NOT sent anymore
+ as one of the arguments to the application in the command reply
+ client operation.
+
+ * NOTE: The FORWARDED flag is depracated. It used to be depracated
+ before first releasing SILC but came back. Now it is removed again
+ and should come back nomore. The FORWARDED flag was used only
+ by the JOINing procedure by forwarding the command packet to router.
+ Now, the JOINing procedure has been changed to more generic (due
+ to various router environment issues) and FORWARDED is not needed
+ anymore for anything. The protocol specification is yet to be
+ updated.
+
+ Now, removed silc_server_packet_forward from server and the flag
+ SILC_PACKET_FORWARDED from lib/silccore/silcpacket.h.
+
+Tue Jan 30 00:05:05 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Renamed NAMES command to USERS command. The NAMES was named that
+ due to historical reasons. Now it is renamed. Also, rewrote
+ parts of the USERS command. The nickname list is not sent anymore
+ by the server. Only Client ID and mode lists are sent in the USERS
+ command. Changed this also to the protocol specification.
+
+ The client now resolves the names and stuff after it receives
+ the USERS list from the server when joining to the channel.
+
+ * WHOIS and IDENTIFY commands has been changed to support multiple
+ Client ID's per command. One can now search for multiple users
+ in the network by sending only one WHOIS or IDENTIFY command.
+ Changed the code and the protocol specifications.
+
+ * Removed silc_server_command_identify_parse and changed that IDENTIFY
+ uses silc_server_command_whois_parse to parse the request. */
+
+ * If normal server, do not parse the WHOIS and IDENTIFY requests
+ before sending it to the router. Saves some time.
+
+Sun Jan 28 16:19:49 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed JOIN command on client library. Wrong number of arguments
+ used to crash the client.
+
+ * Added silc_server_channel_has_global function to check whether
+ channel has global users or not.
+
+ * Added silc_server_channel_has_local function to check whether channel
+ has locally connected clients on the channel.
+
+ * The silc_server_remove_from_one_channel now checks whether the
+ channel has global users or not after given client was removed from
+ the channel. It also checks whether the channel has local clients
+ on the channel anymore. If it does not have then the channel entry
+ is removed as it is not needed anymore.
+
+ * The silc_server_notify now checks on JOIN notify whether the joining
+ client is one of locally connected or global. If it is global then
+ the channel has now global users on the channel and that is marked
+ to the channel entry. Also, it now saves the global client to
+ global list who is joining and JOINs it to the channel. This is
+ for normal server, that is.
+
+ Changed silc_server_send_notify_on_channel,
+ silc_server_packet_relay_to_channel and
+ silc_server_packet_send_to_channel check if we are normal server
+ and client has router set (ie. global client) do not send the
+ message to that client, as it is already routed to our router.
+
+ * Implemented LEAVE notify type handling in silc_server_notify
+ function.
+
+ * Tested LEAVE command in router environment successfully. Tested
+ with two routers, two servers and two clients.
+
+ * Updated TODO.
+
+ * idlist_find_xxx_by_id routines now dumps the ID on the debug mode.
+
+ * Implemented SIGNOFF notify type handling in silc_server_notify
+ function.
+
+ * silc_server_remove_id now removes the client entry from all channels
+ it has joined and thusly sends SIGNOFF notify type.
+
+ * Rewrote the NAMES list generation in server by removing two excess
+ loops. The lists are created now inside one loop.
+
+Sat Jan 27 22:34:56 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * silc_server_remove_channel_user checks now also global list
+ for channel and client.
+
+ * silc_server_new_channel_user checks now both local and global
+ list for channel and client. Fixed a bug in client id decoding.
+ Used to decode wrong buffer.
+
+ * silc_server_channel_message checks now both local and global
+ list for channel entry.
+
+ * Tested channel joining (hence JOIN) in router environment
+ successfully. Tested with two routers, two servers and two
+ clients.
+
+ * Tested channel message sending in router environment successfully.
+
+Thu Jan 11 03:22:57 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added silc_server_save_channel_key into server.[ch] to save the
+ received channel key in Channel Key payload processing. It is
+ also used in JOIN command reply handling.
+
+ Equivalent function silc_client_save_channel_key added into
+ client.[ch] into client library.
+
+ * Changed JOIN command reply to send information whether the channel
+ was created or not (is existing already) and the channel key
+ payload. Changed protocol specs accordingly.
+
+ * Fixed bugs in WHOIS and IDENTIFY command reply sending when
+ the request was sent by ID and not by nickname. Crashed on
+ NULL dereference.
+
+Sat Dec 23 21:55:07 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed a bug in Client library. IDENTIFY and WHOIS reply functions
+ now correctly save the received data.
+
+ * silc_server_free_sock_user_data now notifies routers in the
+ network about entities leaving the network.
+
+ At the same time implemented functions silc_server_remove_id
+ and silc_server_send_remove_id to receive and send REMOVE_ID
+ packets. The packet is used to notify routers in the network
+ about leaving entities. The ID removed will become invalid in
+ the network.
+
+ * Added function silc_idlist_del_server into server. Removes and
+ free's server entry from ID list.
+
+ * silc_server_private_message function now checks, if we are router,
+ that the destination ID really is valid ID, naturally.
+
+ * In router when NEW_ID packet is received (for new client) the
+ hash of the Client ID is saved in the ID Cache but the
+ client->nickname is set to NULL, instead of putting the hash
+ to it as well.
+
+ IDENTIFY command now also checks that client->nickname must be
+ valid. If it is not if will request the data from the server who
+ owns the client. Added new function
+ silc_server_command_identify_check.
+
+ * Added silc_command_set_command into lib/silccore/silcommand.[ch]
+ to set the command to already allocated Command Payload.
+
+ * Tested private message sending in router environment with two
+ routers, two servers and two clients. Fixed minor bugs and now
+ it works fine.
+
+ * Fixed segfault from client's NAMES command. Used to crash if
+ not on any channel.
+
+ * Forwarded packets must not be routed even if it is not destined
+ to the receiver. Changed server code comply with this.
+
+Sun Dec 17 14:40:08 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added `require_reverse_mapping' boolean value to ServerParams
+ structure. If TRUE (not default) the server will require that
+ the connecting host has fully qualified domain name.
+
+ If the reverse mapping is not required and hostname could not be
+ found the IP address is used as hostname.
+
+Sat Dec 16 17:39:54 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Implemented version string checking to both client and server.
+ The check is incomplete currently due to the abnormal version
+ strings used in development version of SILC.
+
+ * Changed all command functions in server to use the new
+ CHECK_ARGS macro.
+
+Fri Dec 15 15:55:12 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Changed char *data to unsigned char *data in ID Cache system to
+ support binary data as ID Cache data. Changed code to support
+ binary data in lib/silccore/idcache.c.
+
+ * Renamed silc_server_packet_relay_command_reply to
+ silc_server_command_reply as it is normal packet receiving
+ function. Rewrote the function to accept command replys for
+ servers and not only for clients.
+
+ * Mark remote router always as registered server if we are connecting
+ to it. Otherwise, commands sent by the router to us are ignored.
+
+ * All ID List find routines now returns the ID Cache Entry pointer
+ as well if requested.
+
+ * WHOIS command works now in router environment, tested with two
+ routers, two servers and two clients.
+
+ * Cleaned up and rewrote IDENTIFY command. IDENTIFY should work now
+ in router environment (as it is almost equivalent to WHOIS) but
+ hasn't been tested thoroughly. Added new functions:
+
+ silc_server_command_identify_parse
+ silc_server_command_identify_send_reply
+ silc_server_command_identify_from_client
+ silc_server_command_identify_from_server
+
+ * Disabled route cache adding because adding two different ID's with
+ same IP replaces the old cache entry thus giving wrong route.
+ The entry->router->connection is always the fastest route anyway
+ so route cache may not be needed. Of course, new routes maybe
+ established after receiving the ID when the entry->router->connection
+ might not be anymore the most optimal.
+
+Thu Dec 14 15:55:35 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Add route cache for received ID for fast routing.
+
+ * Added silc_server_packet_route to route received packet on router
+ that is not destined to us.
+
+ * Renamed silc_server_get_route to silc_server_route_get.
+
+ * Added id_string and id_string_len fields into SilcServer to
+ include encoded ServerID for fast comparing without excess
+ encoding of the ID's.
+
+ * Cleaned up WHOIS command on server side. Added following static
+ functions:
+
+ silc_server_command_whois_parse
+ silc_server_command_whois_check
+ silc_server_command_whois_send_reply
+ silc_server_command_whois_from_client
+ silc_server_command_whois_from_server
+
+ * Added macro SILC_SERVER_COMMAND_CHECK_ARGC to check mandatory
+ arguments in command replies. All command functions should be
+ updated to use this macro.
+
+Sun Dec 10 23:52:00 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Minor typo fixes on command reply handling on server.
+
+Tue Nov 28 11:05:39 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added silc_server_command_add_to_channel internal routine to add
+ the client to the channel after router has created the channel and
+ sent command reply to the server.
+
+ * Added generic silc_server_send_command to send any command from
+ server.
+
+ * Use static buffer with ID rendering instead of duplicating data.
+
+Mon Nov 27 21:39:40 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed a channel user mode bug when joining to a channel server gave
+ everybody channel founder rights, oops.
+
+ * We mark ourselves as the router of the incoming server connection
+ if we are router ourselves. This way we can check in some packet
+ sending functions whether it is locally connected server. For
+ incoming router connections we put NULL.
+
+ * For router sending packets locally means now always sending the
+ packet cell wide; to local clients and local servers. For normal
+ server sending packet locally means sending it to only local
+ clients.
+
+ * Fixed the JOIN command to really work in router environment. If the
+ channel is created it is always created by the router. Router is
+ also responsible of making the initial joining to the channel,
+ sending JOIN notify to the sending server and distributing
+ NEW_CHANNEL and NEW_CHANNEL_USER packets. Hence, if the channel
+ does not exist server doesn't do anything else but forward the
+ command to the router which performs everything.
+
+ * Added silc_server_send_channel_key function to send the Channel Key
+ payload.
+
+ * Added silc_server_create_channel_key to create new channel key. The
+ channel key is now re-generated everytime someone joins or leaves
+ a channel, as protocol dictates. Note: channel->key_len is the
+ key length in bits.
+
+Wed Nov 22 22:14:19 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Splitted server.[ch] finally. Created now packet_send.[ch] and
+ packet_receive.[ch] to separate packet sending and receiving
+ routines. The server.[ch] now includes everything else including
+ actual packet processing (writing and reading data) and other
+ server issues.
+
+ Renamed silc_server_private_message_send_internal to
+ silc_server_send_private_message. The routine is still though
+ used only to relay private messages as server does not send
+ private messages itself.
+
+ Renamed silc_server_new_channel to silc_server_create_new_channel
+ and added new function sicl_server_new_channel that handles the
+ incoming New Channel packet. Added also new sending function
+ silc_server_send_new_channel to send New Channel Payload.
+
+ * Added new function silc_server_notify to process incoming notify
+ packet to the server/router. Server may then relay the notify
+ to clients if needed.
+
+ * Added new function silc_server_new_channel_user to process incoming
+ New Channel User packet. Router will redistribute the packet and
+ send JOIN notify to its local clients and locally connected servers
+ if needed. Normal server will send JOIN notify to its local client
+ on same channel when received this packet. Added also corresponding
+ sending function silc_server_send_new_channel_user to sent the
+ payload.
+
+ * Added boolean route argument to send_notif_to_channel and
+ packet_send_to_channel functions to attempt to route the packet
+ if it is TRUE and send only locally if it is FALSE.
+
+Tue Nov 21 19:49:31 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * silc_server_replace_id now broadcasts the received replace ID
+ packet if it is not broadcast packet already. The router must
+ broadcast to inform other routers about changed ID.
+
+ * Added backpointer to server's router into SilcServer context in
+ silcd/server_internal.h.
+
+ * Fixed silc_server_packet_broadcast to send correct broadcast
+ packets.
+
+ * The channel key is now distributed to the local client as soon
+ as it is received from the router (in router environment) so that
+ no other packet may be sent for the channel until client has
+ received the key.
+
+ * silc_server_remove_channel_user now broadcasts the received
+ Remove Channel User packet if it is not broadcast packet already.
+ The router must broadcast to inform other routers about removed
+ channel user.
+
+ * Added users field into SilcPacketContext that is a reference count
+ of the context. One can increase the reference count by calling
+ silc_packet_context_dup which is now changed to just increase the
+ reference count instead of duplicating the data. The reference
+ count is decresed by calling silc_packet_context_free that will
+ free the data after the reference count hits zero.
+
+ For now on the packet context and everything allocated into it
+ (including the raw packet from network) must be freed by calling
+ the new silc_packet_context_free function. Added also new function
+ silc_packet_context_alloc that must be used now to allocate the
+ context. This also means that if a routine is asynchronous from
+ silc_[client/server]_packet_parse_type the packet context must
+ be duplicated by calling silc_packet_context_dup. Otherwise it
+ gets free'd after silc_[client/server]_packet_parse_type returns.
+ Also, one must remember that if packet is duplicated then its
+ reference count must be decresed by calling the free function as
+ many times as it was duplicated.
+
+ * Changed SilcBuffer field from protocol contexts to SilcPacketContext
+ from both client and server.
+
+Mon Nov 20 23:47:03 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Made joining to a channel working in router environment.
+
+ * Cleaned up JOIN command on server side and create function
+ silc_server_command_join_channel internal routine to make the
+ joining happen.
+
+Thu Nov 9 21:12:39 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Changed silc_command_pending list to SilcDList. Also, added
+ `ident' field to SilcServerCommandPending structure to identify
+ the reply and to call correct callback.
+
+ Added silc_server_command_pending_check function to replace the
+ corresnponding macro. The silc_command_pending list is not
+ extern anymore.
+
+ * Added silc_command_set_ident into lib/silccore/silccommand.[ch]
+ to set identifier to previously allocated Command Payload. It
+ is used to set identifier for command when resending Command
+ Payload.
+
+ * Added silc_command_payload_encode_payload to encode Command
+ Payload buffer from SilcCommandPayload structure.
+
+ * Added silc_argument_payload_encode_payload to encode Argument
+ payload buffer from SilcArgumentPayload structure.
+
+Wed Nov 8 21:03:28 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Changed WHOIS command to support router connection on server side.
+ The whois request is always sent to router unless the server is
+ standalone server. After server has received the reply from the
+ router will it send the reply to the client.
+
+ * Added silc_server_packet_broadcast into silcd/server.[ch] to
+ broadcast received broadcast packet. The function is used only
+ by router. The broadcast packet is always sent to the router's
+ primary route.
+
+ * Added silc_id_render function in lib/silcutil/silcutil.[ch] to
+ render given ID to printable string, for log files for example.
+
+Tue Nov 7 22:14:19 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Made basic router to router connections working. At least they
+ can now connect to each other but nothing really works the way
+ they are supposed - yet.
+
+ * Added new initiator token to RouterConnection configuration
+ file in silcd/serverconfig.[ch]. It is used to tell whether we
+ are the initiator to the remote router or whether we'll expect
+ the other end to connect.
+
+ * Moved registering of listener task to silc_server_init, hence
+ the server starts listenning as soon as it is run, even if it
+ does not have connections to other routers. Let's see how well
+ this will work.
+
+ * Changed default connection retry timeouts for more suitable in
+ silcd/server.h.
+
+ * Removed cipher and such arguments from silc_idlist_add_client
+ and silc_idlist_add_server prototypes from silcd/idlist.[ch].
+ Added new function silc_idlist_add_data to add the keys and stuff
+ to any ID entry.
+
+ * Added SilcIDListData structure and added it to SilcClientEntry
+ and SilcServerEntry as their first field in the structure. This
+ way we can explicitly cast the ID entries to the SilcIDListData
+ structure and get common data for the entries. In past, we had
+ to first check what type of connection it is and then cast it to
+ correct ID entry type. Now, we can directly cast the opaque
+ pointer to the SilcIDListData (no matter what ID entry it actually
+ is) and get the data needed.
+
+Mon Nov 6 21:56:12 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Wow, found a bug in scheduler. The scheduler uninitialized itself
+ in some circumstances even if threre were timeout tasks, though not
+ IO tasks, but tasks anyway. Now fixed.
+
+ * Defined SilcServerConnection structure to hold connection specific
+ stuff about directly connected servers and routers. The definition
+ is currently in silcd/server_internal.h. I thought about having
+ a bit more important role fro this struct but for now it is used
+ only when connecting to other server (or router actually).
+
+ * Added connecting retry support in server when connecting to
+ router(s). The retry feature implement exponential backoff
+ algorithm. Also, added SilcServerParams structure to hold default
+ parameters for server. For now, it include these retry settings
+ and are hard coded. After server is moded to be as Silc Server
+ Library this structure will be more important.
+
+Sun Nov 5 22:28:44 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Changed client librarys channel->clients table to SilcList and
+ changed code accordingly.
+
+Thu Nov 2 16:28:01 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Changed client's channel table to SilcList and changed code
+ accordingly. Also changed SilcChannelClientEntry to include back-
+ pointer to the channel so that client entry can use that structure
+ as list as well and we have fast cross-reference to the channel.
+ This change dramatically decreased the complexity of channel
+ handling with client entry and vice versa (removed one extra
+ loop when searching for channel entry from many functions).
+
+ * Changed server->sim from table to SilcDList and changed code
+ accordingly.
+
+ * NAMES command can now be used from user interface. It will show
+ the user list on the channel, neatly.
+
+ * Added realname pointer to SilcClientEntry in lib/silcclient/idlist.h.
+ Code now saves realname of the user if it becomes available.
+
+ * Renamed configure.in to configure.in.pre and made ./prepare
+ script to automatically add correct version string to
+ configure.in which it creates from configure.in.pre.
+
+Wed Nov 1 17:21:26 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * NAMES command reply now shows users mode with the nickname when
+ joining to channel.
+
+ * Moved silc_client_ch[u]mode[_char] functions from
+ silc/clientutil.[ch] to lib/silcclient/client.[ch]. Though, that
+ place sucks, they are utility functions and should be in some
+ other file.
+
+ * Fixed some unsigned int's to unsigned short's. Patch by cras.
+
+ * Fixed contrib/getopt*.[ch] to not require config.h. Patch by
+ cras.
+
+Tue Oct 31 20:10:37 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Updated README.
+
+ * Added TRQ (efficient deque and list library) into lib/trq. This is
+ a very good list library that is currently used in the SILC. Defined
+ SilcList API over the library because I didn't like the API very
+ much. See lib/trq/silclist.h for the API and examples of how to
+ use the API. Fixed various places in the code to use the new
+ SilcList API. The SilcList is meant for lists that has a structure
+ already defined as a list. It is not suitable to add just some
+ context to the list (in TRQ, the context is the list actually).
+
+ So, I defined SilcDList that can be used for the purpose where
+ predefined list structure does not exit. This can be used as
+ such list. Now some context just can be added to the SilcDList.
+ Currently this list is not used in the SILC just yet, though there
+ are a lot places where this can replace dynamically allocated
+ tables and I will fix these places, later, to use SilcDList.
+ See lib/trq/silcdlist.h for SilcDList (they are all inline functions,
+ and use TRQ internally).
+
+ Also fixed some annoying warning messages that the original TRQ
+ code generated. Also minor changes to TRQ's Makefile.in.
+
+ * Added support for querying by Client ID to both WHOIS and
+ IDENTIFY commands into server, as required by the protocol.
+
+ * Removed method function pointers from SilcBuffer structure. They
+ weren't used to anything and just increased the context size for
+ no good reason. This change also made silc_buffer_alloc and
+ silc_buffer_free functions inline functions.
+
+ * Disabled command flooding detection support until it's fixed so
+ that it accepts commands in but does not execute them more than once
+ in two seconds.
+
+ * Added silc_net_localhost(), to return local hostname, into
+ lib/silcutil/silcnet.[ch]. Also added client->hostname pointer
+ that must be initialized before calling silc_client_init.
+
+ * Added new function: silc_server_send_notify_on_channels to send
+ notify messages to all channels client has joined. It is assured
+ that the message is sent only once per client.
+
+ * Moved silc_log_format (from lib/silcutil/silclog.[ch] into
+ lib/silcutil/silcutil.[ch] as silc_format function. The new
+ function is generic and is used by server as well, not only by
+ the logging routines.
+
+ * Added new SKE status type: SILC_SKE_STATUS_BAD_VERSION to indicate
+ the provided version string was not acceptable. Added new function:
+ silc_ske_check_version into lib/silcske/silcske.h. The function
+ must be implemented by the application (client or server) and it
+ does not reside in the SKE library. The function checks the version
+ string remote end sent.
+
+ * Added back pointers (to opaque context and to SilcSocketConnection)
+ into SilcPacketContext structure into lib/silccore/silcpacket.h.
+
+ * Added silc_packet_context_dup into lib/silccore/silcpacket.[ch] to
+ duplicate packet context structure.
+
+ * Changed `notify' client operation to send same arguments as client
+ receives from server except for ID's. ID's are mapped to correct
+ ID entry and that is returned. Also, if channel entry is not sent
+ by server but the notify is for channel the channel entry is sent
+ to application (otherwise application doesn't know that it is for
+ channel (library gets it from packet's Destination ID)).
+
+ * Added silc_client_remove_from_channels into client library to
+ remove a client from all channels it has joined to. Used when
+ received SIGNOFF notify from server. Added also new function
+ silc_client_replace_from_channels to replace old ID entry with
+ new ID entry on all channels. Used when received NICK_CHANGE
+ notify from server.
+
+ * Fixed ID Cache list handling in silc_idlist_get_client in
+ lib/silcclient/idlist.c. Also, added silc_idlist_get_client_by_id
+ to get (or query) client by ID.
+
+ * Updated TODO list.
+
+ * Added connection authentication status message defined by the
+ protocol: SILC_CONN_AUTH_OK and SILC_CONN_AUTH_FAILED and added the
+ support for these into the code in client and server side.
+
+ * Added generic function silc_client_send_command to send any command
+ with variable argument list. Application should use this function
+ to send commands if the command functions provided by the library
+ does not suite for the application's user interface needs.
+
+ * Added new `failure' client operation. Application is notified about
+ received failure packet if client is executing a protocol. In this
+ case the protocol's execution has failed.
+
+ * Added SKE's end notify to send the SKE_SUCCESS notify message that
+ is required by the protocol.
+
+ * Added SILC_PROTOCOL_STATE_FAILURE to indicate received failure
+ packet from remote. SILC_PROTOCOL_STATE_ERROR indicates local
+ error at our end.
+
+ * Added status flag to SilcSKE object to indicate realtime status
+ of the SKE protocol.
+
+ * Application receives now exactly same command reply arguments as
+ the library receives from server. However, if ID is received the
+ corresponding ID entry is returned to the application (eg. Client
+ ID is mapped to correct SilcClientEntry entry and that is returned).
+ Changed command_reply client operation due to this change.
+
+ * Changed all ID's in commands and in command replys as ID Payloads.
+ Change affected both client and server side codes.
+
+ All ID's sent in SILC network (with execption of ID's in SILC
+ Packet header) are sent in ID Payload to support variable length
+ ID's.
+
+ * Server now notifies nick changes and notifies all clients on
+ the channels about the new nickname (about the new Client ID,
+ actually).
+
+ * Implemented CMODE command to change channel modes. Supports all
+ channel modes defined by the protocol specs except ban and invite
+ lists. (Also, private channel key mode is supported but support for
+ setting private channel key in client is missing, thus, this mode
+ has no effect on client side (except that server requires that the
+ client uses private channel key and normal channel traffic does not
+ work anymore)).
+
+ Also, invite mode works per se, but INVITE command does not work
+ yet correctly, so you can set channel as invite only channel but
+ inviting clients to the channel does not work (it is yet to be
+ thought what's the best way to do it).
+
+ * Added new command SILC_COMMAND_CUMODE to change user mode on the
+ channel. Defined user modes: CHANNEL_FOUNDER and CHANNEL_OPERATOR.
+ Implemented CUMODE command to change user's mode on the channel.
+ Supports all modes defined by the protocol specs.
+
+ * Added NAMES command reply to return users modes on the channel.
+
+ * Removed unnecessary and slow ciphers from lib/silccrypt.
+
+ * Set SO_KEEPALIVE option to connection sockets by default.
+
+ * Added new command reply status: SILC_STATUS_USER_NOT_ON_CHANNEL.
+
+ * Added notify types: MOTD, CMODE_CHANGE and CUMODE_CHANGE. Also,
+ redefined the Notify Payload into protocol specs.
+
+ * Added silc_id_payload_parse_id to get ID directly from raw
+ ID payload data.
+
+Mon Oct 9 20:57:02 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Changed SILC_COMMAND_IDENTIFY in protocol specification to
+ accept searching by Client ID as well.
+
+ * Added support for LEAVE and SIGNOFF notify types in client library.
+
+ * Added silc_id_payload_parse_data into lib/silccore/silcpayload.[ch]
+ to parse ID Payload from raw data.
+
+Sun Oct 8 19:33:08 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added flags parameter into silc_ske_assemble_security_properties
+ function in lib/silcske/silcske.[ch].
+
+ * Changed notify client operation to fit better for notify messages
+ sent by server. The notify payload received from server is now
+ passed to the application (after parsing it to SilcNotifyPayload).
+ It is application's responsibility to retrieve the arguments
+ from the payload and show the message the way it wants. The message
+ sent by server is implementation specific.
+
+ * Changed public keys to comply with the protocol specification.
+ Old public keys are not supported anymore and are not compatible.
+
+ * Removed nickname from Channel Payload as the latest draft removed
+ it. The client must resolve the nickname from the NAMES command
+ reply received when it joined the channel.
+
+ Also, changed all channel_xxxx_payload to channel_payload_xxxx.
+
+Sat Oct 7 21:55:01 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed some errors in protocol specification drafts.
+
+ * Created lib/silccore/silcnotify.c to implement Notify Payload
+ encoding and decoding, lib/silccore/silcpayload.[ch] to implement
+ generic payloads described by protocol specifications. The file
+ includes implementations for ID Payload and Argument Payload.
+
+ * Changed Command Payload implementation to use the new Argument
+ Payload. Changed command_xxxx_payload to command_payload_xxxx
+ to comply with SILC coding conventions.
+
+ * Added suppport for Argument Payload handling in Notify Payload
+ implementation as protocol requires it. Added the new support
+ into server and client lib as well.
+
+Thu Oct 5 21:16:28 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added support for multiple nicknames on same channel. [n] is
+ added locally to the nickname if there are more than one same
+ nicknames on the channel.
+
+ * Server now sends all nicknames that matched WHOIS request.
+ Client also shows the list received from server.
+
+ * Added TOPIC command to client side. User can now set and show
+ current topic on channel.
+
+ * Added MOTD command to client and server. Also, server sends the
+ motd when client connects to the server.
+
+ * Changed version strings to comply ISO 8601.
+
+Wed Oct 4 23:29:06 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed protocol error handling in client library. It should now
+ cope even if the SKE fails for some reason.
+
+ * Made new protocol specification drafts for submitting to IETF.
+
+ * Implemented TOPIC command to server in silcd/command.c.
+
+ * Added two new notify types into lib/silccore/silcnotify.h:
+ SILC_NOTIFY_TYPE_NICK_CHANGE and SILC_NOTIFY_TYPE_TOPIC_SET to
+ notify nickname change and topic setting/change on a channel.
+
+ * API change of command_reply operation in client library. The
+ application gets now the status type received from server as well.
+
+Sat Sep 30 16:57:42 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Removed the function just added to lib/silcutil/silcschedule.[ch].
+
+ * Cras fixed and optimized the packet handling even further and
+ it should work now. Minor change to the prototype of function
+ silc_packet_receive_process in lib/silccore/silcpacket.[ch].
+
+Sat Sep 30 08:48:47 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added new function into lib/silcutil/silcschedule.[ch]:
+ silc_schedule_with_fd to select() a specified fd. The function
+ returns after timeout expires or data arrives or goes. The
+ function is used by packet routines to wait that all data is
+ received from network.
+
+ * Fixed data reading from network in lib/silccore/silcpacket.c.
+ The code now assures that all data is read from the fd and then
+ continues packet processing. This was a bug fix since the code
+ used to drop some data in some circumstances.
+
+ * Added new function into lib/silcclient/client.[ch]:
+ silc_client_start_key_exchange to start key exchange after
+ connection has been established to server. The code internally
+ now uses this funtion but its main purpose was to provide it
+ for applications that perform their own connecting. After
+ application has created a connection it merely calls this
+ function to start the key exchange between client and server.
+ The library takes care of everything else after that.
+
+ Updated also lib/silcclient/README to explain the usage of
+ this new function.
+
+ * Do not send to application information that connection has
+ been established. Application gets notified it by connect
+ operation anyway.
+
+Thu Sep 28 23:40:19 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Applied cras's patch to add silc_schedule_one function. The
+ function runs scheduler once and returns.
+
+ * Fixed the scheduler after cras messed it up. The timeout
+ handling works now as it's supposed to work.
+
+ * Added into lib/silccore/ silcnotify.h to include notify
+ message types support. Changed silc_server_send_notify*
+ functions, in server.[ch], to support those new notify types.
+ Added the support for the notify types into client library,
+ as well. Added new notify client operation into ops.h in
+ lib/silcclient/.
+
+ * Changed silc_server_packet_send_to_channel to send normal
+ packets instead of just channel message packets. The function
+ is now used to send the notify packets to channels. It is not
+ used to send channel message packets anymore, as server never
+ sends them anymore.
+
+ * Added explicit casting into lib/silcutil/silcbuffmt.c to few
+ va_arg()s as it seems to require it nowadays. I guess, if SILC
+ is compiled with older va_arg() the new code should work anyway.
+
+Wed Sep 13 18:10:14 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Splitted core library. Core library (lib/silccore) includes
+ now only SILC protocol specific core (and common) components.
+ Created new utility library (lib/silcutil) that includes more
+ generic purpose stuff. The stuff for util library was taken
+ from the old core library. This was minor and easy split.
+
+ * Created SILC Client Library (lib/silcclient) that includes
+ implementation of the SILC client without user interface. This
+ was major move from silc/ directory. The code has been changed
+ so that it is transparent towards the user interface. The
+ silc/ directory includes now the same user interface as before
+ and it uses the new client library. Read lib/silcclient/README.
+ Basicly, the client library performs everything else related
+ to SILC except user interface handling. Also, configuration
+ files are considered to be part of user interface and library
+ does not handle them.
+
+ This change also changed a lot of structures, function naming etc.
+ Most important change was that SilcClientWindow object was
+ renamed to SilcClientConnection in the client library. Created
+ also new file lib/silcclient/ops.h. Also added new files
+ silc/local_command.[ch] and silc/client_ops.[ch].
+
+ All these changes were made to make it easier for user interface
+ designers to create what ever user interface for the SILC client
+ they want.
+
+ It is also expected that the server will be moved to lib
+ directory as well and SILC Server Library will be created;
+ sometimes in the future.
+
+ * Removed Local commands from lib/silccore/silccommand.h as
+ they are application specific and new client library does not
+ handle any of those anymore.
+
+ * Several functions moved to lib/silcutil/silcutilc.[ch] from
+ old client implementation in silc/.
+
+ * Added support for callback functions in SILC_LOG_* macros.
+ Application can now set its own callbacks that will be called
+ instead of using the default functions that will always print
+ the debug messages to stderr (or stdout). Also, debugging can
+ now be disabled by setting silc_debug to FALSE and re-enabled by
+ setting it to TRUE. Note, that logging will still work even
+ if debugging is disabled.
+
+ New functions in lib/silcutil/silclog.[ch]: silc_log_set_callbacks,
+ silc_log_reset_callbacks, silc_log_set_debug_callbacks and
+ silc_log_reset_debug_callbacks.
+
+ * To enable debugging in silc client one must give now -d
+ option on command line.
+
+ * Changed silc_schedule_init to automatically allocate task queues
+ if they are not allocated before calling it.
+
+Thu Sep 7 10:49:33 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added GMP 3.1 into math library.
+
+Sun Aug 20 21:27:26 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added SILC_PACKET_REMOVE_CHANNEL_USER to remove a client from
+ a channel in SILC network. The packet is used by servers and
+ routers to notify other routers that user has left a channel.
+ This little feature was missing until now. Added the feature
+ to protocol specification as well.
+
+ Added functions: silc_server_send_remove_channel_user and
+ silc_server_remove_channel_user into server.[ch].
+
+ * Added SILC_PACKET_REKEY and SILC_PACKET_REKEY_DONE into
+ lib/silccore/silcpacket.h. However, they are not implemented
+ yet.
+
+Sat Aug 19 23:04:16 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed joining to a channel and sending channel messages
+ between server and router. The channel message sending should
+ now work inside a cell.
+
+Tue Jul 25 20:46:13 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed the private message sending between server and router.
+ The private message sending should now work inside a cell.
+
+ * Added silc_server_replace_id into server.[ch] to replace
+ existing ID in the SILC network.
+
+ * Added silc_idlist_find_server_by, silc_idlist_replace_client_id
+ and silc_idlist_replace_server_id into idlist.[ch] in server.
+
+Mon Jul 24 18:33:31 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed the server to server connections. Server can again now
+ connect to router. Router to router connections probably does
+ not work just yet.
+
+Thu Jul 20 13:15:01 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added dynamic protocol registering support. Now protocols can
+ registered and unregistered on the fly. Patch by cras.
+
+Wed Jul 19 19:08:46 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added lib/contrib directory to hold routines that some platforms
+ don't have but are needed by SILC.
+
+ * Added getopt.c, getopt1.c and getopt.h from GNU C library
+ into lin/contrib to provide getopt() and getopt_long() for
+ those who don't have it.
+
+Tue Jul 18 20:41:20 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added AWAY command to client. When away message is set and
+ client receives a private message packet the client automatically
+ replies to the sender with the away message.
+
+ * Fixed a bug in lib/silcmath/mpbin.c: silc_mp_mp2bin. This
+ bug seemed to be the cause of recent problems when compiling
+ with gcc-2.95.
+
+ * Added version detection support to SKE protocol specification
+ and added the new changes to the SKE implementation as well.
+ There were other minor changes in the SKE protocol as well.
+
+ Many changes in lib/silcske/silcske.[ch] and in
+ lib/silcske/payload.[ch].
+
+ * Added ^U functionality, clear input line. Patch from cras.
+
+Mon Jul 17 23:33:26 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Mainly small bugfixes on core library. Fixed some debugging
+ logging and buffer overflow in silclog.c.
+
+ * Updated config.sub and config.guess on the distribution tree.
+
+Sat Jul 15 15:33:48 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added command lagging support in server. Client may execute
+ commands now only once in two seconds.
+
+Thu Jul 13 22:10:21 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Optimized packet reception. MAC computation and checking is now
+ also more optimized. A lot previously duplicated code is now
+ used as generic by both client and server.
+
+ * Fixed key pair generation in clientutil.c
+
+Wed Jul 12 18:28:07 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added into lib/silccore/silcbufutil.[ch] new function;
+ silc_buffer_realloc.
+
+ * Moved generic packet sending/encryption functions to
+ lib/silccore/silcpacket.[ch] from client and server. Some
+ rewriting of the functions.
+
+ * Moved all generic packet reception/decryption functions to
+ lib/silccore/silcpacket.[ch] from client and server. The
+ packet processing is now much cleaner in both client and server.
+ These were major changes in both client and server.
+
+ * Created many common functions in server to do packet sending.
+ Previously code were duplicated a lot, this has been removed
+ with these changes.
+
+Tue Jul 11 20:27:26 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Rewrote major parts of the ID cache system. Don't know
+ whether it is better now or not but at least the API is more
+ cleaner now.
+
+ * Major rewrite on ID cache stuff on client because of the ID
+ cache API changes. Added idlist.c to client.
+
+ * Also major rewrite on ID cache stuff on server as well.
+ Major rewrite of idlist.[ch]. SilcXXXList's are now named
+ SilcXXXEntry's. We won't keep anymore idlist specific pointers
+ in hand, instead they are all put into the ID cache system now.
+ All server_idlist_* routines uses ID cache now instead of
+ traversing its own lists (those lists does not exist anymore).
+ SilcIDList though still exists. Also, SilcXXXEntry's are
+ now pointers.
+
+Sun Jul 9 15:19:24 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Finally made the SKE implementation compliant to the protocol
+ specification. All mp integers are now binary encoded as
+ opposed being HEX encoded.
+
+ * Added lib/silcmath/mpbin.[ch]. Encoding mp intergers to and
+ from binary data.
+
+ * Added into lib/silccore/silcutil.[ch] PEM encoding/decoding
+ functions: silc_[encode/decode]_pem. Also added function
+ silc_encode_pem_file to PEM encode with newlines ('\n') for
+ saving into a file.
+
+ * SILC public keys are now encoded either PEM or binary. Same
+ option is for private keys as well. By default private keys
+ are binary encoded and public keys PEM encoded. Silly HEX
+ encoding were removed.
+
+ * Added into lib/silccrypt/silchash.[ch] silc_hash_fingerprint
+ function to create fingerprints.
+
+ * Fixed a bug in SHA1; does not change the original data anymore.
+
+ * Partly implemented INFO command on client and server side.
+ Fixed CLEAR command. Changes to SERVER command; show current
+ server(s) when giving command without arguments. Added
+ VERSION command to client.
+
+ * Added check to server that unregistered connections cannot
+ execute commands (unless it is specificly allowed).
+
+Thu Jul 6 18:12:24 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed screen refresh.
+
+ * Fixed channel joining bug from client. On some circumstances
+ client tried to join to a channel it had already joined.
+
+ * Added public key verification process into client's protocol.c.
+ The client now verifies the public key from user and saves
+ it into ~./silc/serverkeys/ directory.
+
+ Added into: clientutil.[ch]: silc_client_verify_server_key.
+
+ * Changed SKE protocol's silc_ske_initiator_finish function
+ to accept callback function that verifies the received public
+ key. Removed old silc_ske_verify_public_key function.
+
+Wed Jul 5 19:19:02 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added into silcpkcs[ch]: silc_pkcs_public_key[_data]_set and
+ silc_pkcs_private_key[_data]_set.
+
+ * Made the password and public authentication more cleaner in
+ server's protocol.c.
+
+ * Removed historic and obsolete protocol `channel_auth' from
+ both client and server.
+
+ * Removed wrong way of sending command status messages from
+ server to client in server's command.c. The old way violated
+ protocol specification.
+
+ Changes to silccore/silccommand.[ch]: removed
+ silc_command_encode_status_payload -> not needed anymore,
+ changed silc_command_encode_payload_va to accept extra
+ argument on variable argument list. The argument type must
+ now be provided to the function. Also, added new function:
+ silc_command_encode_reply_payload_va which is same as
+ normal command_encode_payload_va except command status type
+ is provided as extra argument.
+
+Tue Jul 4 18:26:39 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added ~./silc directory handling. The directory includes the
+ public and private keys for the client.
+
+ Added silc_client_check_silc_dir, silc_client_create_identifier
+ and silc_client_load_keys.
+
+ * Implemented SILC protocol compliant public key. Added public
+ and private key saving to and loading from files.
+
+ Added into silcpkcs.[ch]: silc_pkcs_encode_identifier,
+ silc_pkcs_public_key_encode[_data], silc_pkcs_public_key_decode,
+ silc_pkcs_private_key_encode[_data], silc_pkcs_private_key_decode,
+ silc_pkcs_public_key_alloc, silc_pkcs_public_key_free,
+ silc_pkcs_private_key_alloc and silc_pkcs_private_key_free.
+
+ Implemented: silc_pkcs_save_[public/private]_key[_data] and
+ silc_pkcs_load_[public/private]_key.
+
+Mon Jul 3 18:51:27 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added silc_server_get_route (route.[ch]) to get connection
+ data for the fastest route for given ID.
+
+ * Implemented INVITE command on client and server. The command
+ were re-defined in the SILC Protocol Specification and the
+ implementation now complies with the specification.
+
+ * Implemented PING command on client and server.
+
+ * Implemented NAMES command on client and server. The server side
+ supports currently only normal server not router server yet.
+ Some changes to NAMES definition in SILC protocol specification.
+
+Sun Jul 2 18:23:01 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Implemented LEAVE command on client and server.
+
+ * Previously deprecated SILC_PACKET_FORWARDED flag is now in use
+ again. This change was made to the protocol as well. Server
+ should not violate the protocol specification anymore.
+
+Fri Jun 30 14:03:26 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added SOCKS4 and SOCKS5 support to SILC client. SOCKS5
+ was tested. SOCKS4 was not but should work anyway.
goto out;
}
- ok:
- /* Send IDENTIFY reply */
- id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
- tmp = silc_command_get_first_arg(cmd->payload, NULL);
- sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
- packet = silc_command_encode_payload_va(SILC_COMMAND_IDENTIFY, 3,
- sp_buf->data, sp_buf->len,
- id_string, SILC_ID_CLIENT_LEN,
- nick, strlen(nick));
- if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
- void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
- silc_server_packet_send_dest(cmd->server, cmd->sock,
- SILC_PACKET_COMMAND_REPLY, 0,
- id, cmd->packet->src_id_type,
- packet->data, packet->len, FALSE);
- silc_free(id);
- } else
- silc_server_packet_send(cmd->server, cmd->sock,
- SILC_PACKET_COMMAND_REPLY, 0,
- packet->data, packet->len, FALSE);
+ /* Router always finds the client entry if it exists in the SILC network.
+ However, it might be incomplete entry and does not include all the
+ mandatory fields that WHOIS command reply requires. Check for these and
+ make query from the server who owns the client if some fields are
+ missing. */
+ if (!silc_server_command_whois_check(cmd, clients, clients_count)) {
+ ret = -1;
+ goto out;
+ }
- silc_free(id_string);
- silc_buffer_free(packet);
- silc_free(sp_buf);
+ /* Send the command reply */
+ silc_server_command_whois_send_reply(cmd, clients, clients_count,
+ count, nick, client_id);
out:
- if (nick)
- silc_free(nick);
- if (server)
- silc_free(server);
- silc_server_command_free(cmd);
+ if (client_id_count) {
+ for (i = 0; i < client_id_count; i++)
+ silc_free(client_id[i]);
+ silc_free(client_id);
+ }
+ silc_free(clients);
+ silc_free(nick);
+ silc_free(server_name);
+
+ return ret;
}
-/* Checks string for bad characters and returns TRUE if they are found. */
+/* Server side of command WHOIS. Processes user's query and sends found
+ results as command replies back to the client. */
-static int silc_server_command_bad_chars(char *nick)
+SILC_SERVER_CMD_FUNC(whois)
{
- if (strchr(nick, '\\')) return TRUE;
- if (strchr(nick, '\"')) return TRUE;
- if (strchr(nick, '´')) return TRUE;
- if (strchr(nick, '`')) return TRUE;
- if (strchr(nick, '\'')) return TRUE;
- if (strchr(nick, '*')) return TRUE;
- if (strchr(nick, '/')) return TRUE;
- if (strchr(nick, '@')) return TRUE;
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ int ret = 0;
- return FALSE;
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOIS, cmd, 1, 3328);
+
+ ret = silc_server_command_whois_process(cmd);
+ silc_server_command_free(cmd);
}
-/* Server side of command NICK. Sets nickname for user. Setting
- nickname causes generation of a new client ID for the client. The
- new client ID is sent to the client after changing the nickname. */
+/******************************************************************************
-SILC_SERVER_CMD_FUNC(nick)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
- SilcServer server = cmd->server;
- SilcBuffer packet, sp_buf;
- SilcClientID *new_id;
- char *id_string;
- char *nick;
+ WHOWAS Functions
- SILC_LOG_DEBUG(("Start"));
+******************************************************************************/
-#define LCC(x) server->local_list->client_cache[(x) - 32]
-#define LCCC(x) server->local_list->client_cache_count[(x) - 32]
+static int
+silc_server_command_whowas_parse(SilcServerCommandContext cmd,
+ char **nickname,
+ char **server_name,
+ int *count)
+{
+ unsigned char *tmp;
+ uint32 len;
- /* Check number of arguments */
- if (silc_command_get_arg_num(cmd->payload) < 1) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOWAS,
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- /* Check nickname */
- nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
- if (silc_server_command_bad_chars(nick) == TRUE) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
- SILC_STATUS_ERR_BAD_NICKNAME);
- goto out;
+ return FALSE;
}
- /* Create new Client ID */
- silc_id_create_client_id(cmd->server->id, cmd->server->rng,
- cmd->server->md5hash, nick,
- &new_id);
+ /* Get the nickname@server string and parse it. */
+ silc_parse_userfqdn(tmp, nickname, server_name);
- /* Send notify about nickname change to our router. We send the new
- ID and ask to replace it with the old one. */
- if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
- silc_server_send_replace_id(server, server->id_entry->router->connection,
- FALSE, id_entry->id,
- SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
- new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
-
- /* If we are router we have to distribute the new Client ID to all
- routers in SILC. */
- if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
- silc_server_send_replace_id(server, server->id_entry->router->connection,
- TRUE, id_entry->id,
- SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
- new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
+ /* Get the max count of reply messages allowed */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ if (tmp)
+ *count = atoi(tmp);
+ else
+ *count = 0;
- /* Remove old cache entry */
- silc_idcache_del_by_id(LCC(id_entry->nickname[0]),
- LCCC(id_entry->nickname[0]),
- SILC_ID_CLIENT, id_entry->id);
-
- /* Free old ID */
- if (id_entry->id) {
- memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
- silc_free(id_entry->id);
- }
+ return TRUE;
+}
- /* Save the nickname as this client is our local client */
- if (id_entry->nickname)
- silc_free(id_entry->nickname);
+static char
+silc_server_command_whowas_check(SilcServerCommandContext cmd,
+ SilcClientEntry *clients,
+ uint32 clients_count)
+{
+ SilcServer server = cmd->server;
+ int i;
+ SilcClientEntry entry;
- id_entry->nickname = strdup(nick);
- id_entry->id = new_id;
+ for (i = 0; i < clients_count; i++) {
+ entry = clients[i];
- /* Update client cache */
- LCCC(nick[0]) = silc_idcache_add(&LCC(nick[0]), LCCC(nick[0]),
- id_entry->nickname, SILC_ID_CLIENT,
- id_entry->id, (void *)id_entry);
+ if (!entry->nickname || !entry->username) {
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
- /* Send the new Client ID as reply command back to client */
- id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
- sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
- packet = silc_command_encode_payload_va(SILC_COMMAND_NICK, 2,
- sp_buf->data, sp_buf->len,
- id_string, SILC_ID_CLIENT_LEN);
- silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
- 0, packet->data, packet->len, FALSE);
+ if (!entry->router)
+ continue;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ /* Send WHOWAS command */
+ silc_server_packet_send(server, entry->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply */
+ silc_server_command_pending(server, SILC_COMMAND_WHOWAS,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_whowas,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_command_set_ident(cmd->payload, old_ident);
- silc_free(id_string);
- silc_buffer_free(packet);
- silc_free(sp_buf);
+ silc_buffer_free(tmpbuf);
+ return FALSE;
+ }
+ }
- out:
- silc_server_command_free(cmd);
-#undef LCC
-#undef LCCC
+ return TRUE;
}
+static void
+silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
+ SilcClientEntry *clients,
+ uint32 clients_count)
+{
+ SilcServer server = cmd->server;
+ char *tmp;
+ int i, k, count = 0, len;
+ SilcBuffer packet, idp;
+ SilcClientEntry entry = NULL;
+ SilcCommandStatus status;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+ char nh[256], uh[256];
+ int valid_count;
+
+ status = SILC_STATUS_OK;
+
+ /* Process only entries that are not registered anymore. */
+ valid_count = 0;
+ for (i = 0; i < clients_count; i++) {
+ if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
+ clients[i] = NULL;
+ else
+ valid_count++;
+ }
+
+ if (!valid_count) {
+ /* No valid entries found at all, just send error */
+ unsigned char *tmp;
+
+ tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ if (tmp)
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, tmp, strlen(tmp));
+ return;
+ }
+
+ if (valid_count > 1)
+ status = SILC_STATUS_LIST_START;
+
+ for (i = 0, k = 0; i < clients_count; i++) {
+ entry = clients[i];
+ if (!entry)
+ continue;
+
+ if (k >= 1)
+ status = SILC_STATUS_LIST_ITEM;
+ if (valid_count > 1 && k == valid_count - 1)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 == count)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 > count)
+ break;
+
+ /* Send WHOWAS reply */
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+ tmp = silc_argument_get_first_arg(cmd->args, NULL);
+ memset(uh, 0, sizeof(uh));
+ memset(nh, 0, sizeof(nh));
+
+ strncat(nh, entry->nickname, strlen(entry->nickname));
+ if (!strchr(entry->nickname, '@')) {
+ strncat(nh, "@", 1);
+ if (entry->servername) {
+ strncat(nh, entry->servername, strlen(entry->servername));
+ } else {
+ len = entry->router ? strlen(entry->router->server_name) :
+ strlen(server->server_name);
+ strncat(nh, entry->router ? entry->router->server_name :
+ server->server_name, len);
+ }
+ }
+
+ strncat(uh, entry->username, strlen(entry->username));
+ if (!strchr(entry->username, '@')) {
+ strncat(uh, "@", 1);
+ strcat(uh, "*private*");
+ }
+
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
+ status, ident, 4,
+ 2, idp->data, idp->len,
+ 3, nh, strlen(nh),
+ 4, uh, strlen(uh),
+ 5, entry->userinfo,
+ entry->userinfo ?
+ strlen(entry->userinfo) : 0);
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+ 0, packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+
+ k++;
+ }
+}
+
+static int
+silc_server_command_whowas_process(SilcServerCommandContext cmd)
+{
+ SilcServer server = cmd->server;
+ char *nick = NULL, *server_name = NULL;
+ int count = 0;
+ SilcClientEntry *clients = NULL;
+ uint32 clients_count = 0;
+ int ret = 0;
+ bool check_global = FALSE;
+
+ /* Protocol dictates that we must always send the received WHOWAS request
+ to our router if we are normal server, so let's do it now unless we
+ are standalone. We will not send any replies to the client until we
+ have received reply from the router. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ /* Send WHOWAS command to our router */
+ silc_server_packet_send(server, (SilcSocketConnection)
+ server->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_WHOWAS,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_whowas,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_command_set_ident(cmd->payload, old_ident);
+
+ silc_buffer_free(tmpbuf);
+ ret = -1;
+ goto out;
+ }
+
+ /* We are ready to process the command request. Let's search for the
+ requested client and send reply to the requesting client. */
+
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+ check_global = TRUE;
+ else if (server->server_type != SILC_SERVER)
+ check_global = TRUE;
+
+ /* Parse the whowas request */
+ if (!silc_server_command_whowas_parse(cmd, &nick, &server_name, &count))
+ return 0;
+
+ /* Get all clients matching that nickname from local list */
+ if (!silc_idlist_get_clients_by_nickname(server->local_list,
+ nick, server_name,
+ &clients, &clients_count))
+ silc_idlist_get_clients_by_hash(server->local_list,
+ nick, server->md5hash,
+ &clients, &clients_count);
+
+ /* Check global list as well */
+ if (check_global) {
+ if (!silc_idlist_get_clients_by_nickname(server->global_list,
+ nick, server_name,
+ &clients, &clients_count))
+ silc_idlist_get_clients_by_hash(server->global_list,
+ nick, server->md5hash,
+ &clients, &clients_count);
+ }
+
+ if (!clients) {
+ /* Such a client really does not exist in the SILC network. */
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, nick, strlen(nick));
+ goto out;
+ }
+
+ if (!silc_server_command_whowas_check(cmd, clients, clients_count)) {
+ ret = -1;
+ goto out;
+ }
+
+ /* Send the command reply to the client */
+ silc_server_command_whowas_send_reply(cmd, clients, clients_count);
+
+ out:
+ silc_free(clients);
+ silc_free(nick);
+ silc_free(server_name);
+ return ret;
+}
+
+/* Server side of command WHOWAS. */
+
+SILC_SERVER_CMD_FUNC(whowas)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ int ret = 0;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOWAS, cmd, 1, 2);
+
+ ret = silc_server_command_whowas_process(cmd);
+ silc_server_command_free(cmd);
+}
+
+/******************************************************************************
+
+ IDENTIFY Functions
+
+******************************************************************************/
+
+static void
+silc_server_command_identify_send_router(SilcServerCommandContext cmd)
+{
+ SilcServer server = cmd->server;
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ /* Send IDENTIFY command to our router */
+ silc_server_packet_send(server, (SilcSocketConnection)
+ server->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_identify,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+}
+
+static int
+silc_server_command_identify_parse(SilcServerCommandContext cmd,
+ SilcClientEntry **clients,
+ uint32 *clients_count,
+ SilcServerEntry **servers,
+ uint32 *servers_count,
+ SilcChannelEntry **channels,
+ uint32 *channels_count,
+ uint32 *count)
+{
+ SilcServer server = cmd->server;
+ unsigned char *tmp;
+ uint32 len;
+ uint32 argc = silc_argument_get_arg_num(cmd->args);
+ SilcIDPayload idp;
+ bool check_global = FALSE;
+ void *entry;
+ int i;
+ bool error = FALSE;
+
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+ check_global = TRUE;
+ else if (server->server_type != SILC_SERVER)
+ check_global = TRUE;
+
+ /* If ID Payload is in the command it must be used instead of names */
+ tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
+ if (!tmp) {
+ /* No ID, get the names. */
+
+ /* If we are normal server and have not resolved information from
+ router yet, do so now. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ silc_server_command_identify_send_router(cmd);
+ return -1;
+ }
+
+ /* Try to get nickname@server. */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ if (tmp) {
+ char *nick = NULL;
+ char *nick_server = NULL;
+
+ silc_parse_userfqdn(tmp, &nick, &nick_server);
+
+ if (!silc_idlist_get_clients_by_hash(server->local_list,
+ nick, server->md5hash,
+ clients, clients_count))
+ silc_idlist_get_clients_by_nickname(server->local_list,
+ nick, nick_server,
+ clients, clients_count);
+ if (check_global) {
+ if (!silc_idlist_get_clients_by_hash(server->global_list,
+ nick, server->md5hash,
+ clients, clients_count))
+ silc_idlist_get_clients_by_nickname(server->global_list,
+ nick, nick_server,
+ clients, clients_count);
+ }
+
+ silc_free(nick);
+ silc_free(nick_server);
+
+ if (!(*clients)) {
+ /* the nickname does not exist, send error reply */
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, tmp, strlen(tmp));
+ return 0;
+ }
+ }
+
+ /* Try to get server name */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ if (tmp) {
+ entry = silc_idlist_find_server_by_name(server->local_list,
+ tmp, TRUE, NULL);
+ if (!entry && check_global)
+ entry = silc_idlist_find_server_by_name(server->global_list,
+ tmp, TRUE, NULL);
+ if (entry) {
+ *servers = silc_realloc(*servers, sizeof(**servers) *
+ (*servers_count + 1));
+ (*servers)[(*servers_count)++] = entry;
+ }
+
+ if (!(*servers)) {
+ /* the server does not exist, send error reply */
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_SERVER,
+ 3, tmp, strlen(tmp));
+ return 0;
+ }
+ }
+
+ /* Try to get channel name */
+ tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
+ if (tmp) {
+ entry = silc_idlist_find_channel_by_name(server->local_list,
+ tmp, NULL);
+ if (!entry && check_global)
+ entry = silc_idlist_find_channel_by_name(server->global_list,
+ tmp, NULL);
+ if (entry) {
+ *channels = silc_realloc(*channels, sizeof(**channels) *
+ (*channels_count + 1));
+ (*channels)[(*channels_count)++] = entry;
+ }
+
+ if (!(*channels)) {
+ /* The channel does not exist, send error reply */
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL,
+ 3, tmp, strlen(tmp));
+ return 0;
+ }
+ }
+
+ if (!(*clients) && !(*servers) && !(*channels)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return 0;
+ }
+ } else {
+ /* Command includes ID, we must use that. Also check whether the command
+ has more than one ID set - take them all. */
+
+ /* Take all ID's from the command packet */
+ for (i = 0; i < argc; i++) {
+ void *id;
+
+ tmp = silc_argument_get_arg_type(cmd->args, i + 5, &len);
+ if (!tmp)
+ continue;
+
+ idp = silc_id_payload_parse(tmp, len);
+ if (!idp) {
+ silc_free(*clients);
+ silc_free(*servers);
+ silc_free(*channels);
+ silc_server_command_send_status_reply(
+ cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return 0;
+ }
+
+ id = silc_id_payload_get_id(idp);
+
+ switch (silc_id_payload_get_type(idp)) {
+
+ case SILC_ID_CLIENT:
+ entry = (void *)silc_idlist_find_client_by_id(server->local_list,
+ id, TRUE, NULL);
+ if (!entry && check_global)
+ entry = (void *)silc_idlist_find_client_by_id(server->global_list,
+ id, TRUE, NULL);
+ if (entry) {
+ *clients = silc_realloc(*clients, sizeof(**clients) *
+ (*clients_count + 1));
+ (*clients)[(*clients_count)++] = (SilcClientEntry)entry;
+ } else {
+ /* If we are normal server and have not resolved information from
+ router yet, do so now. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ silc_server_command_identify_send_router(cmd);
+ silc_free(*clients);
+ silc_free(*servers);
+ silc_free(*channels);
+ return -1;
+ } else {
+ silc_server_command_send_status_data(
+ cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+ 2, tmp, len);
+ error = TRUE;
+ }
+ }
+
+ break;
+
+ case SILC_ID_SERVER:
+ entry = (void *)silc_idlist_find_server_by_id(server->local_list,
+ id, TRUE, NULL);
+ if (!entry && check_global)
+ entry = (void *)silc_idlist_find_server_by_id(server->global_list,
+ id, TRUE, NULL);
+ if (entry) {
+ *servers = silc_realloc(*servers, sizeof(**servers) *
+ (*servers_count + 1));
+ (*servers)[(*servers_count)++] = (SilcServerEntry)entry;
+ } else {
+ /* If we are normal server and have not resolved information from
+ router yet, do so now. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ silc_server_command_identify_send_router(cmd);
+ silc_free(*clients);
+ silc_free(*servers);
+ silc_free(*channels);
+ return -1;
+ } else {
+ silc_server_command_send_status_data(
+ cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
+ 2, tmp, len);
+ error = TRUE;
+ }
+ }
+ break;
+
+ case SILC_ID_CHANNEL:
+ entry = (void *)silc_idlist_find_channel_by_id(server->local_list,
+ id, NULL);
+ if (!entry && check_global)
+ entry = (void *)silc_idlist_find_channel_by_id(server->global_list,
+ id, NULL);
+ if (entry) {
+ *channels = silc_realloc(*channels, sizeof(**channels) *
+ (*channels_count + 1));
+ (*channels)[(*channels_count)++] = (SilcChannelEntry)entry;
+ } else {
+ /* If we are normal server and have not resolved information from
+ router yet, do so now. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ silc_server_command_identify_send_router(cmd);
+ silc_free(*clients);
+ silc_free(*servers);
+ silc_free(*channels);
+ return -1;
+ } else {
+ silc_server_command_send_status_data(
+ cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
+ 2, tmp, len);
+ error = TRUE;
+ }
+ }
+ break;
+ }
+
+ silc_free(id);
+ }
+ }
+
+ if (error) {
+ silc_free(*clients);
+ silc_free(*servers);
+ silc_free(*channels);
+ return FALSE;
+ }
+
+ /* Get the max count of reply messages allowed */
+ tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
+ if (tmp)
+ *count = atoi(tmp);
+ else
+ *count = 0;
+
+ return 1;
+}
+
+/* Checks that all mandatory fields in client entry are present. If not
+ then send WHOIS request to the server who owns the client. We use
+ WHOIS because we want to get as much information as possible at once. */
+
+static bool
+silc_server_command_identify_check_client(SilcServerCommandContext cmd,
+ SilcClientEntry *clients,
+ uint32 clients_count)
+{
+ SilcServer server = cmd->server;
+ SilcClientEntry entry;
+ SilcServerResolveContext resolve = NULL, r = NULL;
+ uint32 resolve_count = 0;
+ int i, k;
+ bool no_res = TRUE;
+
+ for (i = 0; i < clients_count; i++) {
+ entry = clients[i];
+ if (!entry)
+ continue;
+
+ if (entry->nickname ||
+ !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
+ if (!entry->router)
+ continue;
+
+ /* If we are normal server, and we've not resolved this client from
+ router and it is global client, we'll check whether it is on some
+ channel. If not then we cannot be sure about its validity, and
+ we'll resolve it from router. */
+ if (cmd->server->server_type != SILC_SERVER || cmd->pending ||
+ entry->connection || silc_hash_table_count(entry->channels))
+ continue;
+ }
+
+ /* We need to resolve this entry since it is not complete */
+
+ if (!cmd->pending && entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
+ /* The entry is being resolved (and we are not the resolver) so attach
+ to the command reply and we're done with this one. */
+ silc_server_command_pending(server, SILC_COMMAND_NONE,
+ entry->resolve_cmd_ident,
+ silc_server_command_identify,
+ silc_server_command_dup(cmd));
+ no_res = FALSE;
+ } else {
+ if (entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
+ /* We've resolved this and it still is not ready. We'll return
+ and are that this will be handled again after it is resolved. */
+ for (i = 0; i < resolve_count; i++) {
+ for (k = 0; k < r->res_argc; k++)
+ silc_free(r->res_argv[k]);
+ silc_free(r->res_argv);
+ silc_free(r->res_argv_lens);
+ silc_free(r->res_argv_types);
+ }
+ silc_free(resolve);
+ return FALSE;
+ } else {
+ /* We'll resolve this client */
+ SilcBuffer idp;
+
+ r = NULL;
+ for (k = 0; k < resolve_count; k++) {
+ if (resolve[k].router == entry->router) {
+ r = &resolve[k];
+ break;
+ }
+ }
+
+ if (!r) {
+ resolve = silc_realloc(resolve, sizeof(*resolve) *
+ (resolve_count + 1));
+ r = &resolve[resolve_count];
+ memset(r, 0, sizeof(*r));
+ r->router = entry->router;
+ r->ident = ++server->cmd_ident;
+ resolve_count++;
+ }
+
+ r->res_argv = silc_realloc(r->res_argv, sizeof(*r->res_argv) *
+ (r->res_argc + 1));
+ r->res_argv_lens = silc_realloc(r->res_argv_lens,
+ sizeof(*r->res_argv_lens) *
+ (r->res_argc + 1));
+ r->res_argv_types = silc_realloc(r->res_argv_types,
+ sizeof(*r->res_argv_types) *
+ (r->res_argc + 1));
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+ r->res_argv[r->res_argc] = silc_calloc(idp->len,
+ sizeof(**r->res_argv));
+ memcpy(r->res_argv[r->res_argc], idp->data, idp->len);
+ r->res_argv_lens[r->res_argc] = idp->len;
+ r->res_argv_types[r->res_argc] = r->res_argc + 3;
+ r->res_argc++;
+ silc_buffer_free(idp);
+
+ entry->resolve_cmd_ident = r->ident;
+ entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
+ entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
+ }
+ }
+ }
+
+ /* Do the resolving */
+ for (i = 0; i < resolve_count; i++) {
+ SilcBuffer res_cmd;
+
+ r = &resolve[i];
+
+ /* Send WHOIS request. We send WHOIS since we're doing the requesting
+ now anyway so make it a good one. */
+ res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
+ r->res_argc, r->res_argv,
+ r->res_argv_lens,
+ r->res_argv_types,
+ r->ident);
+ silc_server_packet_send(server, r->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ res_cmd->data, res_cmd->len, FALSE);
+
+ /* Reprocess this packet after received reply */
+ silc_server_command_pending(server, SILC_COMMAND_WHOIS,
+ r->ident,
+ silc_server_command_identify,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+
+ silc_buffer_free(res_cmd);
+ for (k = 0; k < r->res_argc; k++)
+ silc_free(r->res_argv[k]);
+ silc_free(r->res_argv);
+ silc_free(r->res_argv_lens);
+ silc_free(r->res_argv_types);
+ no_res = FALSE;
+ }
+ silc_free(resolve);
+
+ return no_res;
+}
+
+static void
+silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
+ SilcClientEntry *clients,
+ uint32 clients_count,
+ SilcServerEntry *servers,
+ uint32 servers_count,
+ SilcChannelEntry *channels,
+ uint32 channels_count,
+ int count)
+{
+ SilcServer server = cmd->server;
+ int i, k, len, valid_count;
+ SilcBuffer packet, idp;
+ SilcCommandStatus status;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+ char nh[256], uh[256];
+ SilcSocketConnection hsock;
+
+ status = SILC_STATUS_OK;
+
+ if (clients) {
+ SilcClientEntry entry;
+
+ /* Process only valid entries. */
+ valid_count = 0;
+ for (i = 0; i < clients_count; i++) {
+ if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
+ valid_count++;
+ else
+ clients[i] = NULL;
+ }
+
+ if (!valid_count) {
+ /* No valid entries found at all, just send error */
+ unsigned char *tmp;
+
+ tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ if (tmp) {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, tmp, strlen(tmp));
+ } else {
+ tmp = silc_argument_get_arg_type(cmd->args, 5, (uint32 *)&len);
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+ 2, tmp, len);
+ }
+ return;
+ }
+
+ /* Process all valid client entries and send command replies */
+
+ if (valid_count > 1)
+ status = SILC_STATUS_LIST_START;
+
+ for (i = 0, k = 0; i < clients_count; i++) {
+ entry = clients[i];
+ if (!entry)
+ continue;
+
+ if (k >= 1)
+ status = SILC_STATUS_LIST_ITEM;
+ if (valid_count > 1 && k == valid_count - 1
+ && !servers_count && !channels_count)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 == count)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 > count)
+ break;
+
+ /* Send IDENTIFY reply */
+
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+ memset(uh, 0, sizeof(uh));
+ memset(nh, 0, sizeof(nh));
+ strncat(nh, entry->nickname, strlen(entry->nickname));
+ if (!strchr(entry->nickname, '@')) {
+ strncat(nh, "@", 1);
+ if (entry->servername) {
+ strncat(nh, entry->servername, strlen(entry->servername));
+ } else {
+ len = entry->router ? strlen(entry->router->server_name) :
+ strlen(server->server_name);
+ strncat(nh, entry->router ? entry->router->server_name :
+ server->server_name, len);
+ }
+ }
+
+ if (!entry->username) {
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ status, ident, 2,
+ 2, idp->data, idp->len,
+ 3, nh, strlen(nh));
+ } else {
+ strncat(uh, entry->username, strlen(entry->username));
+ if (!strchr(entry->username, '@')) {
+ strncat(uh, "@", 1);
+ hsock = (SilcSocketConnection)entry->connection;
+ len = strlen(hsock->hostname);
+ strncat(uh, hsock->hostname, len);
+ }
+
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ status, ident, 3,
+ 2, idp->data, idp->len,
+ 3, nh, strlen(nh),
+ 4, uh, strlen(uh));
+ }
+
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+ 0, packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+
+ k++;
+ }
+ }
+
+ if (servers) {
+ SilcServerEntry entry;
+
+ if (status == SILC_STATUS_OK && servers_count > 1)
+ status = SILC_STATUS_LIST_START;
+
+ for (i = 0, k = 0; i < servers_count; i++) {
+ entry = servers[i];
+
+ if (k >= 1)
+ status = SILC_STATUS_LIST_ITEM;
+ if (servers_count > 1 && k == servers_count - 1 && !channels_count)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 == count)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 > count)
+ break;
+
+ /* Send IDENTIFY reply */
+ idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ status, ident, 2,
+ 2, idp->data, idp->len,
+ 3, entry->server_name,
+ entry->server_name ?
+ strlen(entry->server_name) : 0);
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+ 0, packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+
+ k++;
+ }
+ }
+
+ if (channels) {
+ SilcChannelEntry entry;
+
+ if (status == SILC_STATUS_OK && channels_count > 1)
+ status = SILC_STATUS_LIST_START;
+
+ for (i = 0, k = 0; i < channels_count; i++) {
+ entry = channels[i];
+
+ if (k >= 1)
+ status = SILC_STATUS_LIST_ITEM;
+ if (channels_count > 1 && k == channels_count - 1)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 == count)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 > count)
+ break;
+
+ /* Send IDENTIFY reply */
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ status, ident, 2,
+ 2, idp->data, idp->len,
+ 3, entry->channel_name,
+ entry->channel_name ?
+ strlen(entry->channel_name): 0);
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+ 0, packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+
+ k++;
+ }
+ }
+}
+
+static int
+silc_server_command_identify_process(SilcServerCommandContext cmd)
+{
+ uint32 count = 0;
+ int ret = 0;
+ SilcClientEntry *clients = NULL;
+ SilcServerEntry *servers = NULL;
+ SilcChannelEntry *channels = NULL;
+ uint32 clients_count = 0, servers_count = 0, channels_count = 0;
+
+ /* Parse the IDENTIFY request */
+ ret = silc_server_command_identify_parse(cmd,
+ &clients, &clients_count,
+ &servers, &servers_count,
+ &channels, &channels_count,
+ &count);
+ if (ret < 1)
+ return ret;
+ ret = 0;
+
+ /* Check that all mandatory fields are present and request those data
+ from the server who owns the client if necessary. */
+ if (clients && !silc_server_command_identify_check_client(cmd, clients,
+ clients_count)) {
+ ret = -1;
+ goto out;
+ }
+
+ /* Send the command reply to the client */
+ silc_server_command_identify_send_reply(cmd,
+ clients, clients_count,
+ servers, servers_count,
+ channels, channels_count,
+ count);
+
+ out:
+ silc_free(clients);
+ silc_free(servers);
+ silc_free(channels);
+ return ret;
+}
+
+SILC_SERVER_CMD_FUNC(identify)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ int ret = 0;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_IDENTIFY, cmd, 1, 3328);
+
+ ret = silc_server_command_identify_process(cmd);
+ silc_server_command_free(cmd);
+}
+
+/* Server side of command NICK. Sets nickname for user. Setting
+ nickname causes generation of a new client ID for the client. The
+ new client ID is sent to the client after changing the nickname. */
+
+SILC_SERVER_CMD_FUNC(nick)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ SilcServer server = cmd->server;
+ SilcBuffer packet, nidp, oidp = NULL;
+ SilcClientID *new_id;
+ uint32 nick_len;
+ char *nick;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+ int nickfail = 0;
+
+ if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ goto out;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_NICK, cmd, 1, 1);
+
+ /* Check nickname */
+ nick = silc_argument_get_arg_type(cmd->args, 1, &nick_len);
+ if (nick_len > 128)
+ nick[128] = '\0';
+ if (silc_server_name_bad_chars(nick, nick_len) == TRUE) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
+ SILC_STATUS_ERR_BAD_NICKNAME);
+ goto out;
+ }
+
+ /* Check for same nickname */
+ if (!strcmp(client->nickname, nick)) {
+ nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ goto send_reply;
+ }
+
+ /* Create new Client ID */
+ while (!silc_id_create_client_id(cmd->server, cmd->server->id,
+ cmd->server->rng,
+ cmd->server->md5hash, nick,
+ &new_id)) {
+ nickfail++;
+ snprintf(&nick[strlen(nick) - 1], 1, "%d", nickfail);
+ }
+
+ /* Send notify about nickname change to our router. We send the new
+ ID and ask to replace it with the old one. If we are router the
+ packet is broadcasted. Send NICK_CHANGE notify. */
+ if (!server->standalone)
+ silc_server_send_notify_nick_change(server, server->router->connection,
+ server->server_type == SILC_SERVER ?
+ FALSE : TRUE, client->id,
+ new_id);
+
+ oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
+ /* Remove old cache entry */
+ silc_idcache_del_by_context(server->local_list->clients, client);
+
+ /* Free old ID */
+ silc_free(client->id);
+
+ /* Save the nickname as this client is our local client */
+ silc_free(client->nickname);
+
+ client->nickname = strdup(nick);
+ client->id = new_id;
+
+ /* Update client cache */
+ silc_idcache_add(server->local_list->clients, client->nickname,
+ client->id, (void *)client, 0, NULL);
+
+ nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
+ /* Send NICK_CHANGE notify to the client's channels */
+ silc_server_send_notify_on_channels(server, NULL, client,
+ SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
+ oidp->data, oidp->len,
+ nidp->data, nidp->len);
+
+ send_reply:
+ /* Send the new Client ID as reply command back to client */
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK,
+ SILC_STATUS_OK, ident, 1,
+ 2, nidp->data, nidp->len);
+ silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+ 0, packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+ silc_buffer_free(nidp);
+ if (oidp)
+ silc_buffer_free(oidp);
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+/* Sends the LIST command reply */
+
+static void
+silc_server_command_list_send_reply(SilcServerCommandContext cmd,
+ SilcChannelEntry *lch,
+ uint32 lch_count,
+ SilcChannelEntry *gch,
+ uint32 gch_count)
+{
+ int i, k;
+ SilcBuffer packet, idp;
+ SilcChannelEntry entry;
+ SilcCommandStatus status;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+ char *topic;
+ unsigned char usercount[4];
+ uint32 users;
+ int valid_lcount = 0, valid_rcount = 0;
+
+ for (i = 0; i < lch_count; i++) {
+ if (lch[i]->mode & SILC_CHANNEL_MODE_SECRET)
+ lch[i] = NULL;
+ else
+ valid_lcount++;
+ }
+ for (i = 0; i < gch_count; i++) {
+ if (gch[i]->mode & SILC_CHANNEL_MODE_SECRET)
+ gch[i] = NULL;
+ else
+ valid_rcount++;
+ }
+
+ status = SILC_STATUS_OK;
+ if ((lch_count + gch_count) > 1)
+ status = SILC_STATUS_LIST_START;
+
+ /* Local list */
+ for (i = 0, k = 0; i < lch_count; i++) {
+ entry = lch[i];
+ if (!entry)
+ continue;
+
+ if (k >= 1)
+ status = SILC_STATUS_LIST_ITEM;
+ if (valid_lcount > 1 && k == valid_lcount - 1 && !valid_rcount)
+ status = SILC_STATUS_LIST_END;
+
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
+
+ if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
+ topic = "*private*";
+ memset(usercount, 0, sizeof(usercount));
+ } else {
+ topic = entry->topic;
+ users = silc_hash_table_count(entry->user_list);
+ SILC_PUT32_MSB(users, usercount);
+ }
+
+ /* Send the reply */
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
+ status, ident, 4,
+ 2, idp->data, idp->len,
+ 3, entry->channel_name,
+ strlen(entry->channel_name),
+ 4, topic, topic ? strlen(topic) : 0,
+ 5, usercount, 4);
+ silc_server_packet_send(cmd->server, cmd->sock,
+ SILC_PACKET_COMMAND_REPLY, 0, packet->data,
+ packet->len, FALSE);
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+ k++;
+ }
+
+ /* Global list */
+ for (i = 0, k = 0; i < gch_count; i++) {
+ entry = gch[i];
+ if (!entry)
+ continue;
+
+ if (k >= 1)
+ status = SILC_STATUS_LIST_ITEM;
+ if (valid_rcount > 1 && k == valid_rcount - 1)
+ status = SILC_STATUS_LIST_END;
+
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
+
+ if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
+ topic = "*private*";
+ memset(usercount, 0, sizeof(usercount));
+ } else {
+ topic = entry->topic;
+ users = silc_hash_table_count(entry->user_list);
+ SILC_PUT32_MSB(users, usercount);
+ }
+
+ /* Send the reply */
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
+ status, ident, 4,
+ 2, idp->data, idp->len,
+ 3, entry->channel_name,
+ strlen(entry->channel_name),
+ 4, topic, topic ? strlen(topic) : 0,
+ 5, usercount, 4);
+ silc_server_packet_send(cmd->server, cmd->sock,
+ SILC_PACKET_COMMAND_REPLY, 0, packet->data,
+ packet->len, FALSE);
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+ k++;
+ }
+}
+
+/* Server side of LIST command. This lists the channel of the requested
+ server. Secret channels are not listed. */
+
SILC_SERVER_CMD_FUNC(list)
{
- server->config->admin_info->location,
- server->config->admin_info->server_type,
- server->config->admin_info->admin_name,
- server->config->admin_info->admin_email);
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcChannelID *channel_id = NULL;
+ unsigned char *tmp;
+ uint32 tmp_len;
+ SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
+ uint32 lch_count = 0, gch_count = 0;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LIST, cmd, 0, 1);
+
+ /* If we are normal server, send the command to router, since we
+ want to know all channels in the network. */
+ if (!cmd->pending && server->server_type == SILC_SERVER &&
+ !server->standalone) {
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+ silc_server_packet_send(server, server->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_LIST,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_list,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+ goto out;
+ }
+
+ /* Get Channel ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (tmp) {
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_LIST,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
+ }
+
+ /* Get the channels from local list */
+ lchannels = silc_idlist_get_channels(server->local_list, channel_id,
+ &lch_count);
+
+ /* Get the channels from global list */
+ gchannels = silc_idlist_get_channels(server->global_list, channel_id,
+ &gch_count);
+
+ /* Send the reply */
+ silc_server_command_list_send_reply(cmd, lchannels, lch_count,
+ gchannels, gch_count);
+
+ silc_free(lchannels);
+ silc_free(gchannels);
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+/* Server side of TOPIC command. Sets topic for channel and/or returns
+ current topic to client. */
+
+SILC_SERVER_CMD_FUNC(topic)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ SilcChannelID *channel_id;
+ SilcChannelEntry channel;
+ SilcChannelClientEntry chl;
+ SilcBuffer packet, idp;
+ unsigned char *tmp;
+ uint32 argc, tmp_len;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_TOPIC, cmd, 1, 2);
+
+ argc = silc_argument_get_arg_num(cmd->args);
+
+ /* Get Channel ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
+
+ /* Check whether the channel exists */
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ goto out;
+ }
+ }
+
+ if (argc > 1) {
+ /* Get the topic */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ if (strlen(tmp) > 256) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* See whether the client is on channel and has rights to change topic */
+ if (!silc_hash_table_find(channel->user_list, client, NULL,
+ (void *)&chl)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+ SILC_STATUS_ERR_NOT_ON_CHANNEL);
+ goto out;
+ }
+
+ if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+ if (channel->mode & SILC_CHANNEL_MODE_TOPIC) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+ goto out;
+ }
+ }
+
+ /* Set the topic for channel */
+ silc_free(channel->topic);
+ channel->topic = strdup(tmp);
+
+ /* Send TOPIC_SET notify type to the network */
+ if (!server->standalone)
+ silc_server_send_notify_topic_set(server, server->router->connection,
+ server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, channel,
+ client->id, SILC_ID_CLIENT,
+ channel->topic);
+
+ idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
+ /* Send notify about topic change to all clients on the channel */
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+ SILC_NOTIFY_TYPE_TOPIC_SET, 2,
+ idp->data, idp->len,
+ channel->topic, strlen(channel->topic));
+ silc_buffer_free(idp);
+ }
+
+ /* Send the topic to client as reply packet */
+ idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC,
+ SILC_STATUS_OK, ident, 2,
+ 2, idp->data, idp->len,
+ 3, channel->topic,
+ channel->topic ?
+ strlen(channel->topic) : 0);
+ silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+ 0, packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+ silc_free(channel_id);
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+/* Server side of INVITE command. Invites some client to join some channel.
+ This command is also used to manage the invite list of the channel. */
+
+SILC_SERVER_CMD_FUNC(invite)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcSocketConnection sock = cmd->sock, dest_sock;
+ SilcChannelClientEntry chl;
+ SilcClientEntry sender, dest;
+ SilcClientID *dest_id = NULL;
+ SilcChannelEntry channel;
+ SilcChannelID *channel_id = NULL;
+ SilcIDListData idata;
+ SilcBuffer idp, idp2, packet;
+ unsigned char *tmp, *add, *del;
+ uint32 len;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INVITE, cmd, 1, 4);
+
+ /* Get Channel ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
+ channel_id = silc_id_payload_parse_id(tmp, len);
+ if (!channel_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
+
+ /* Get the channel entry */
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ goto out;
+ }
+ }
+
+ /* Check whether the sender of this command is on the channel. */
+ sender = (SilcClientEntry)sock->user_data;
+ if (!silc_server_client_on_channel(sender, channel)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+ SILC_STATUS_ERR_NOT_ON_CHANNEL);
+ goto out;
+ }
+
+ /* Check whether the channel is invite-only channel. If yes then the
+ sender of this command must be at least channel operator. */
+ if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
+ silc_hash_table_find(channel->user_list, sender, NULL, (void *)&chl);
+ if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+ goto out;
+ }
+ }
+
+ /* Get destination client ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (tmp) {
+ char invite[512];
+ bool resolve;
+
+ dest_id = silc_id_payload_parse_id(tmp, len);
+ if (!dest_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+ SILC_STATUS_ERR_NO_CLIENT_ID);
+ goto out;
+ }
+
+ /* Get the client entry */
+ dest = silc_server_get_client_resolve(server, dest_id, &resolve);
+ if (!dest) {
+ if (server->server_type != SILC_SERVER || !resolve) {
+ silc_server_command_send_status_reply(
+ cmd, SILC_COMMAND_INVITE,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+ goto out;
+ }
+
+ /* The client info is being resolved. Reprocess this packet after
+ receiving the reply to the query. */
+ silc_server_command_pending(server, SILC_COMMAND_WHOIS,
+ server->cmd_ident,
+ silc_server_command_invite,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_free(channel_id);
+ silc_free(dest_id);
+ goto out;
+ }
+
+ /* Check whether the requested client is already on the channel. */
+ if (silc_server_client_on_channel(dest, channel)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+ SILC_STATUS_ERR_USER_ON_CHANNEL);
+ goto out;
+ }
+
+ /* Get route to the client */
+ dest_sock = silc_server_get_client_route(server, NULL, 0, dest_id, &idata);
+ if (!dest_sock) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+ goto out;
+ }
+
+ memset(invite, 0, sizeof(invite));
+ strncat(invite, dest->nickname, strlen(dest->nickname));
+ strncat(invite, "!", 1);
+ strncat(invite, dest->username, strlen(dest->username));
+ if (!strchr(dest->username, '@')) {
+ strncat(invite, "@", 1);
+ strncat(invite, cmd->sock->hostname, strlen(cmd->sock->hostname));
+ }
+
+ len = strlen(invite);
+ if (!channel->invite_list)
+ channel->invite_list = silc_calloc(len + 2,
+ sizeof(*channel->invite_list));
+ else
+ channel->invite_list = silc_realloc(channel->invite_list,
+ sizeof(*channel->invite_list) *
+ (len +
+ strlen(channel->invite_list) + 2));
+ strncat(channel->invite_list, invite, len);
+ strncat(channel->invite_list, ",", 1);
+
+ /* Send notify to the client that is invited to the channel */
+ idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
+ idp2 = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
+ silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id,
+ SILC_ID_CLIENT,
+ SILC_NOTIFY_TYPE_INVITE, 3,
+ idp->data, idp->len,
+ channel->channel_name,
+ strlen(channel->channel_name),
+ idp2->data, idp2->len);
+ silc_buffer_free(idp);
+ silc_buffer_free(idp2);
+ }
+
+ /* Add the client to the invite list of the channel */
+ add = silc_argument_get_arg_type(cmd->args, 3, &len);
+ if (add) {
+ if (!channel->invite_list)
+ channel->invite_list = silc_calloc(len + 2,
+ sizeof(*channel->invite_list));
+ else
+ channel->invite_list = silc_realloc(channel->invite_list,
+ sizeof(*channel->invite_list) *
+ (len +
+ strlen(channel->invite_list) + 2));
+ if (add[len - 1] == ',')
+ add[len - 1] = '\0';
+
+ strncat(channel->invite_list, add, len);
+ strncat(channel->invite_list, ",", 1);
+ }
+
+ /* Get the invite to be removed and remove it from the list */
+ del = silc_argument_get_arg_type(cmd->args, 4, &len);
+ if (del && channel->invite_list) {
+ char *start, *end, *n;
+
+ if (!strncmp(channel->invite_list, del,
+ strlen(channel->invite_list) - 1)) {
+ silc_free(channel->invite_list);
+ channel->invite_list = NULL;
+ } else {
+ start = strstr(channel->invite_list, del);
+ if (start && strlen(start) >= len) {
+ end = start + len;
+ n = silc_calloc(strlen(channel->invite_list) - len, sizeof(*n));
+ strncat(n, channel->invite_list, start - channel->invite_list);
+ strncat(n, end + 1, ((channel->invite_list +
+ strlen(channel->invite_list)) - end) - 1);
+ silc_free(channel->invite_list);
+ channel->invite_list = n;
+ }
+ }
+ }
+
+ /* Send notify to the primary router */
+ if (!server->standalone)
+ silc_server_send_notify_invite(server, server->router->connection,
+ server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, channel,
+ sender->id, add, del);
+
+ /* Send command reply */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+
+ if (add || del)
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
+ SILC_STATUS_OK, ident, 2,
+ 2, tmp, len,
+ 3, channel->invite_list,
+ channel->invite_list ?
+ strlen(channel->invite_list) : 0);
+ else
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
+ SILC_STATUS_OK, ident, 1,
+ 2, tmp, len);
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+
+ out:
+ silc_free(dest_id);
+ silc_free(channel_id);
+ silc_server_command_free(cmd);
+}
+
+typedef struct {
+ SilcServer server;
+ SilcSocketConnection sock;
+ char *signoff;
+} *QuitInternal;
+
+/* Quits connection to client. This gets called if client won't
+ close the connection even when it has issued QUIT command. */
+
+SILC_TASK_CALLBACK(silc_server_command_quit_cb)
+{
+ QuitInternal q = (QuitInternal)context;
+
+ /* Free all client specific data, such as client entry and entires
+ on channels this client may be on. */
+ silc_server_free_client_data(q->server, q->sock, q->sock->user_data,
+ TRUE, q->signoff);
+ q->sock->user_data = NULL;
+
+ /* Close the connection on our side */
+ silc_server_close_connection(q->server, q->sock);
+
+ silc_free(q->signoff);
+ silc_free(q);
+}
+
+/* Quits SILC session. This is the normal way to disconnect client. */
+
+SILC_SERVER_CMD_FUNC(quit)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcSocketConnection sock = cmd->sock;
+ QuitInternal q;
+ unsigned char *tmp = NULL;
+ uint32 len = 0;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_QUIT, cmd, 0, 1);
+
+ if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ goto out;
+
+ /* Get destination ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+ if (len > 128)
+ tmp = NULL;
+
+ q = silc_calloc(1, sizeof(*q));
+ q->server = server;
+ q->sock = sock;
+ q->signoff = tmp ? strdup(tmp) : NULL;
+
+ /* We quit the connection with little timeout */
+ silc_schedule_task_add(server->schedule, sock->sock,
+ silc_server_command_quit_cb, (void *)q,
+ 0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+/* Server side of command KILL. This command is used by router operator
+ to remove an client from the SILC Network temporarily. */
+
+SILC_SERVER_CMD_FUNC(kill)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ SilcClientEntry remote_client;
+ SilcClientID *client_id;
+ unsigned char *tmp, *comment;
+ uint32 tmp_len, tmp_len2;
+ bool local;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 2);
+
+ if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ goto out;
+
+ /* KILL command works only on router */
+ if (server->server_type != SILC_ROUTER) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+ SILC_STATUS_ERR_NO_ROUTER_PRIV);
+ goto out;
+ }
+
+ /* Check whether client has the permissions. */
+ if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+ SILC_STATUS_ERR_NO_ROUTER_PRIV);
+ goto out;
+ }
+
+ /* Get the client ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+ goto out;
+ }
+
+ /* Get the client entry */
+ remote_client = silc_idlist_find_client_by_id(server->local_list,
+ client_id, TRUE, NULL);
+ local = TRUE;
+ if (!remote_client) {
+ remote_client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, TRUE, NULL);
+ local = FALSE;
+ if (!remote_client) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+ goto out;
+ }
+ }
+
+ /* Get comment */
+ comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len2);
+ if (tmp_len2 > 128)
+ comment = NULL;
+
+ /* Send reply to the sender */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+ SILC_STATUS_OK);
+
+ /* Send the KILL notify packets. First send it to the channel, then
+ to our primary router and then directly to the client who is being
+ killed right now. */
+
+ /* Send KILLED notify to the channels. It is not sent to the client
+ as it will be sent differently destined directly to the client and not
+ to the channel. */
+ silc_server_send_notify_on_channels(server, remote_client,
+ remote_client, SILC_NOTIFY_TYPE_KILLED,
+ comment ? 2 : 1,
+ tmp, tmp_len,
+ comment, comment ? tmp_len2 : 0);
+
+ /* Send KILLED notify to primary route */
+ if (!server->standalone)
+ silc_server_send_notify_killed(server, server->router->connection, TRUE,
+ remote_client->id, comment);
+
+ /* Send KILLED notify to the client directly */
+ silc_server_send_notify_killed(server, remote_client->connection ?
+ remote_client->connection :
+ remote_client->router->connection, FALSE,
+ remote_client->id, comment);
+
+ /* Remove the client from all channels. This generates new keys to the
+ channels as well. */
+ silc_server_remove_from_channels(server, NULL, remote_client, FALSE,
+ NULL, TRUE);
+
+ /* Remove the client entry, If it is locally connected then we will also
+ disconnect the client here */
+ if (remote_client->connection) {
+ /* Remove locally conneted client */
+ SilcSocketConnection sock = remote_client->connection;
+ silc_server_free_client_data(server, sock, remote_client, FALSE, NULL);
+ silc_server_close_connection(server, sock);
+ } else {
+ /* Update statistics */
+ if (remote_client->connection)
+ server->stat.my_clients--;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.cell_clients--;
+ SILC_OPER_STATS_UPDATE(remote_client, server, SILC_UMODE_SERVER_OPERATOR);
+ SILC_OPER_STATS_UPDATE(remote_client, router, SILC_UMODE_ROUTER_OPERATOR);
+
+ /* Remove remote client */
+ silc_idlist_del_client(local ? server->local_list :
+ server->global_list, remote_client);
+ }
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+/* Server side of command INFO. This sends information about us to
+ the client. If client requested specific server we will send the
+ command to that server. */
+
+SILC_SERVER_CMD_FUNC(info)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcBuffer packet, idp;
+ unsigned char *tmp;
+ uint32 tmp_len;
+ char *dest_server, *server_info = NULL, *server_name;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+ SilcServerEntry entry = NULL;
+ SilcServerID *server_id = NULL;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INFO, cmd, 0, 2);
+
+ /* Get server name */
+ dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
+
+ /* Get Server ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (tmp) {
+ server_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!server_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+ SILC_STATUS_ERR_NO_SERVER_ID);
+ goto out;
+ }
+ }
+
+ if (server_id) {
+ /* Check whether we have this server cached */
+ entry = silc_idlist_find_server_by_id(server->local_list,
+ server_id, TRUE, NULL);
+ if (!entry) {
+ entry = silc_idlist_find_server_by_id(server->global_list,
+ server_id, TRUE, NULL);
+ if (!entry && server->server_type != SILC_SERVER) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+ SILC_STATUS_ERR_NO_SUCH_SERVER);
+ goto out;
+ }
+ }
+ }
+
+ /* Some buggy servers has sent request to router about themselves. */
+ if (server->server_type != SILC_SERVER && cmd->sock->user_data == entry)
+ goto out;
+
+ if ((!dest_server && !server_id && !entry) || (entry &&
+ entry == server->id_entry) ||
+ (dest_server && !cmd->pending &&
+ !strncasecmp(dest_server, server->server_name, strlen(dest_server)))) {
+ /* Send our reply */
+ char info_string[256];
+
+ memset(info_string, 0, sizeof(info_string));
+ snprintf(info_string, sizeof(info_string),
+ "location: %s server: %s admin: %s <%s>",
- if (server->config && server->config->motd &&
- server->config->motd->motd_file) {
++ server->config->server_info->location,
++ server->config->server_info->server_type,
++ server->config->server_info->admin,
++ server->config->server_info->email);
+
+ server_info = info_string;
+ entry = server->id_entry;
+ } else {
+ /* Check whether we have this server cached */
+ if (!entry && dest_server) {
+ entry = silc_idlist_find_server_by_name(server->global_list,
+ dest_server, TRUE, NULL);
+ if (!entry) {
+ entry = silc_idlist_find_server_by_name(server->local_list,
+ dest_server, TRUE, NULL);
+ }
+ }
+
+ if (!cmd->pending &&
+ server->server_type != SILC_SERVER && entry && !entry->server_info) {
+ /* Send to the server */
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ silc_server_packet_send(server, entry->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_INFO,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_info,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+ goto out;
+ }
+
+ if (!entry && !cmd->pending && !server->standalone) {
+ /* Send to the primary router */
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ silc_server_packet_send(server, server->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_INFO,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_info,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+ goto out;
+ }
+ }
+
+ silc_free(server_id);
+
+ if (!entry) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+ SILC_STATUS_ERR_NO_SUCH_SERVER);
+ goto out;
+ }
+
+ idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
+ if (!server_info)
+ server_info = entry->server_info;
+ server_name = entry->server_name;
+
+ /* Send the reply */
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
+ SILC_STATUS_OK, ident, 3,
+ 2, idp->data, idp->len,
+ 3, server_name,
+ strlen(server_name),
+ 4, server_info,
+ server_info ?
+ strlen(server_info) : 0);
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+/* Server side of command PING. This just replies to the ping. */
+
+SILC_SERVER_CMD_FUNC(ping)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcServerID *id;
+ uint32 len;
+ unsigned char *tmp;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INFO, cmd, 1, 2);
+
+ /* Get Server ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
+ SILC_STATUS_ERR_NO_SERVER_ID);
+ goto out;
+ }
+ id = silc_id_str2id(tmp, len, SILC_ID_SERVER);
+ if (!id)
+ goto out;
+
+ if (SILC_ID_SERVER_COMPARE(id, server->id)) {
+ /* Send our reply */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
+ SILC_STATUS_OK);
+ } else {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
+ SILC_STATUS_ERR_NO_SUCH_SERVER);
+ goto out;
+ }
+
+ silc_free(id);
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+/* Internal routine to join channel. The channel sent to this function
+ has been either created or resolved from ID lists. This joins the sent
+ client to the channel. */
+
+static void silc_server_command_join_channel(SilcServer server,
+ SilcServerCommandContext cmd,
+ SilcChannelEntry channel,
+ SilcClientID *client_id,
+ bool created,
+ bool create_key,
+ uint32 umode,
+ const unsigned char *auth,
+ uint32 auth_len)
+{
+ SilcSocketConnection sock = cmd->sock;
+ unsigned char *tmp;
+ uint32 tmp_len, user_count;
+ unsigned char *passphrase = NULL, mode[4], tmp2[4], tmp3[4];
+ SilcClientEntry client;
+ SilcChannelClientEntry chl;
+ SilcBuffer reply, chidp, clidp, keyp = NULL, user_list, mode_list;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+ char check[512], check2[512];
+ bool founder = FALSE;
+ bool resolve;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!channel)
+ return;
+
+ /* Get the client entry */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
+ client = (SilcClientEntry)sock->user_data;
+ } else {
+ client = silc_server_get_client_resolve(server, client_id, &resolve);
+ if (!client) {
+ if (cmd->pending)
+ goto out;
+
+ if (!resolve) {
+ silc_server_command_send_status_reply(
+ cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* The client info is being resolved. Reprocess this packet after
+ receiving the reply to the query. */
+ silc_server_command_pending(server, SILC_COMMAND_WHOIS,
+ server->cmd_ident,
+ silc_server_command_join,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ goto out;
+ }
+
+ cmd->pending = FALSE;
+ }
+
+ /*
+ * Check founder auth payload if provided. If client can gain founder
+ * privileges it can override various conditions on joining the channel,
+ * and can have directly the founder mode set on the channel.
+ */
+ if (auth && auth_len && channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+ SilcIDListData idata = (SilcIDListData)client;
+
+ if (channel->founder_key && idata->public_key &&
+ silc_pkcs_public_key_compare(channel->founder_key,
+ idata->public_key)) {
+ void *auth_data = (channel->founder_method == SILC_AUTH_PASSWORD ?
+ (void *)channel->founder_passwd :
+ (void *)channel->founder_key);
+ uint32 auth_data_len = (channel->founder_method == SILC_AUTH_PASSWORD ?
+ channel->founder_passwd_len : 0);
+
+ /* Check whether the client is to become founder */
+ if (silc_auth_verify_data(auth, auth_len, channel->founder_method,
+ auth_data, auth_data_len,
+ idata->hash, client->id, SILC_ID_CLIENT)) {
+ umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+ founder = TRUE;
+ }
+ }
+ }
+
+ /*
+ * Check channel modes
+ */
+
+ if (!umode) {
+ memset(check, 0, sizeof(check));
+ memset(check2, 0, sizeof(check2));
+ strncat(check, client->nickname, strlen(client->nickname));
+ strncat(check, "!", 1);
+ strncat(check, client->username, strlen(client->username));
+ if (!strchr(client->username, '@')) {
+ strncat(check, "@", 1);
+ strncat(check, cmd->sock->hostname, strlen(cmd->sock->hostname));
+ }
+
+ strncat(check2, client->nickname, strlen(client->nickname));
+ if (!strchr(client->nickname, '@')) {
+ strncat(check2, "@", 1);
+ strncat(check2, server->server_name, strlen(server->server_name));
+ }
+ strncat(check2, "!", 1);
+ strncat(check2, client->username, strlen(client->username));
+ if (!strchr(client->username, '@')) {
+ strncat(check2, "@", 1);
+ strncat(check2, cmd->sock->hostname, strlen(cmd->sock->hostname));
+ }
+
+ /* Check invite list if channel is invite-only channel */
+ if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
+ if (!channel->invite_list ||
+ (!silc_string_match(channel->invite_list, check) &&
+ !silc_string_match(channel->invite_list, check2))) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_NOT_INVITED);
+ goto out;
+ }
+ }
+
+ /* Check ban list if it exists. If the client's nickname, server,
+ username and/or hostname is in the ban list the access to the
+ channel is denied. */
+ if (channel->ban_list) {
+ if (silc_string_match(channel->ban_list, check) ||
+ silc_string_match(channel->ban_list, check2)) {
+ silc_server_command_send_status_reply(
+ cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_BANNED_FROM_CHANNEL);
+ goto out;
+ }
+ }
+
+ /* Check user count limit if set. */
+ if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
+ if (silc_hash_table_count(channel->user_list) + 1 >
+ channel->user_limit) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_CHANNEL_IS_FULL);
+ goto out;
+ }
+ }
+ }
+
+ /* Check the channel passphrase if set. */
+ if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+ /* Get passphrase */
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+ if (tmp) {
+ passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
+ memcpy(passphrase, tmp, tmp_len);
+ }
+
+ if (!passphrase || !channel->passphrase ||
+ memcmp(passphrase, channel->passphrase, strlen(channel->passphrase))) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_BAD_PASSWORD);
+ goto out;
+ }
+ }
+
+ /*
+ * Client is allowed to join to the channel. Make it happen.
+ */
+
+ /* Check whether the client already is on the channel */
+ if (silc_server_client_on_channel(client, channel)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_USER_ON_CHANNEL);
+ goto out;
+ }
+
+ /* Generate new channel key as protocol dictates */
+ if (create_key) {
+ if (!silc_server_create_channel_key(server, channel, 0))
+ goto out;
+
+ /* Send the channel key. This is broadcasted to the channel but is not
+ sent to the client who is joining to the channel. */
+ if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
+ silc_server_send_channel_key(server, NULL, channel,
+ server->server_type == SILC_ROUTER ?
+ FALSE : !server->standalone);
+ }
+
+ /* Join the client to the channel by adding it to channel's user list.
+ Add also the channel to client entry's channels list for fast cross-
+ referencing. */
+ chl = silc_calloc(1, sizeof(*chl));
+ chl->mode = umode;
+ chl->client = client;
+ chl->channel = channel;
+ silc_hash_table_add(channel->user_list, client, chl);
+ silc_hash_table_add(client->channels, channel, chl);
+
+ /* Get users on the channel */
+ silc_server_get_users_on_channel(server, channel, &user_list, &mode_list,
+ &user_count);
+
+ /* Encode Client ID Payload of the original client who wants to join */
+ clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
+ /* Encode command reply packet */
+ chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+ SILC_PUT32_MSB(channel->mode, mode);
+ SILC_PUT32_MSB(created, tmp2);
+ SILC_PUT32_MSB(user_count, tmp3);
+
+ if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
+ tmp = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+ keyp = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, tmp,
+ strlen(channel->channel_key->
+ cipher->name),
+ channel->channel_key->cipher->name,
+ channel->key_len / 8, channel->key);
+ silc_free(tmp);
+ }
+
+ reply =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
+ SILC_STATUS_OK, ident, 13,
+ 2, channel->channel_name,
+ strlen(channel->channel_name),
+ 3, chidp->data, chidp->len,
+ 4, clidp->data, clidp->len,
+ 5, mode, 4,
+ 6, tmp2, 4,
+ 7, keyp ? keyp->data : NULL,
+ keyp ? keyp->len : 0,
+ 8, channel->ban_list,
+ channel->ban_list ?
+ strlen(channel->ban_list) : 0,
+ 9, channel->invite_list,
+ channel->invite_list ?
+ strlen(channel->invite_list) : 0,
+ 10, channel->topic,
+ channel->topic ?
+ strlen(channel->topic) : 0,
+ 11, silc_hmac_get_name(channel->hmac),
+ strlen(silc_hmac_get_name(channel->
+ hmac)),
+ 12, tmp3, 4,
+ 13, user_list->data, user_list->len,
+ 14, mode_list->data,
+ mode_list->len);
+
+ /* Send command reply */
+ silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
+ reply->data, reply->len, FALSE);
+
+ /* Send JOIN notify to locally connected clients on the channel. If
+ we are normal server then router will send or have sent JOIN notify
+ already. However since we've added the client already to our channel
+ we'll ignore it (in packet_receive.c) so we must send it here. If
+ we are router then this will send it to local clients and local
+ servers. */
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+ SILC_NOTIFY_TYPE_JOIN, 2,
+ clidp->data, clidp->len,
+ chidp->data, chidp->len);
+
+ if (!cmd->pending) {
+ /* Send JOIN notify packet to our primary router */
+ if (!server->standalone)
+ silc_server_send_notify_join(server, server->router->connection,
+ server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, channel, client->id);
+
+ if (keyp)
+ /* Distribute the channel key to all backup routers. */
+ silc_server_backup_send(server, NULL, SILC_PACKET_CHANNEL_KEY, 0,
+ keyp->data, keyp->len, FALSE, TRUE);
+ }
+
+ /* If client became founder by providing correct founder auth data
+ notify the mode change to the channel. */
+ if (founder) {
+ SILC_PUT32_MSB(chl->mode, mode);
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+ SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
+ clidp->data, clidp->len,
+ mode, 4, clidp->data, clidp->len);
+
+ /* Set CUMODE notify type to network */
+ if (!server->standalone)
+ silc_server_send_notify_cumode(server, server->router->connection,
+ server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, channel,
+ chl->mode, client->id, SILC_ID_CLIENT,
+ client->id);
+ }
+
+ silc_buffer_free(reply);
+ silc_buffer_free(clidp);
+ silc_buffer_free(chidp);
+ silc_buffer_free(keyp);
+ silc_buffer_free(user_list);
+ silc_buffer_free(mode_list);
+
+ out:
+ silc_free(passphrase);
+}
+
+/* Server side of command JOIN. Joins client into requested channel. If
+ the channel does not exist it will be created. */
+
+SILC_SERVER_CMD_FUNC(join)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ unsigned char *auth;
+ uint32 tmp_len, auth_len;
+ char *tmp, *channel_name = NULL, *cipher, *hmac;
+ SilcChannelEntry channel;
+ uint32 umode = 0;
+ bool created = FALSE, create_key = TRUE;
+ SilcClientID *client_id;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 2, 6);
+
+ /* Get channel name */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ channel_name = tmp;
+
+ if (tmp_len > 256)
+ channel_name[255] = '\0';
+
+ if (silc_server_name_bad_chars(channel_name, tmp_len) == TRUE) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_BAD_CHANNEL);
+ goto out;
+ }
+
+ /* Get Client ID of the client who is joining to the channel */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Get cipher, hmac name and auth payload */
+ cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
+ hmac = silc_argument_get_arg_type(cmd->args, 5, NULL);
+ auth = silc_argument_get_arg_type(cmd->args, 6, &auth_len);
+
+ /* See if the channel exists */
+ channel = silc_idlist_find_channel_by_name(server->local_list,
+ channel_name, NULL);
+
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
+ SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
+ client_id = silc_id_dup(entry->id, SILC_ID_CLIENT);
+
+ if (!channel || channel->disabled) {
+ /* Channel not found */
+
+ /* If we are standalone server we don't have a router, we just create
+ the channel by ourselves. */
+ if (server->standalone) {
+ channel = silc_server_create_new_channel(server, server->id, cipher,
+ hmac, channel_name, TRUE);
+ if (!channel) {
+ silc_server_command_send_status_reply(
+ cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+ goto out;
+ }
+
+ umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+ created = TRUE;
+ create_key = FALSE;
+
+ } else {
+
+ /* The channel does not exist on our server. If we are normal server
+ we will send JOIN command to our router which will handle the
+ joining procedure (either creates the channel if it doesn't exist
+ or joins the client to it). */
+ if (server->server_type != SILC_ROUTER) {
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
+
+ /* If this is pending command callback then we've resolved
+ it and it didn't work, return since we've notified the
+ client already in the command reply callback. */
+ if (cmd->pending)
+ goto out;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ /* Send JOIN command to our router */
+ silc_server_packet_send(server, (SilcSocketConnection)
+ server->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_JOIN,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_join,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+ goto out;
+ }
+
+ /* We are router and the channel does not seem exist so we will check
+ our global list as well for the channel. */
+ channel = silc_idlist_find_channel_by_name(server->global_list,
+ channel_name, NULL);
+ if (!channel) {
+ /* Channel really does not exist, create it */
+ channel = silc_server_create_new_channel(server, server->id, cipher,
+ hmac, channel_name, TRUE);
+ if (!channel) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+ goto out;
+ }
+
+ umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+ created = TRUE;
+ create_key = FALSE;
+ }
+ }
+ }
+ } else {
+ if (!channel) {
+ /* Channel not found */
+
+ /* If the command came from router and we are normal server then
+ something went wrong with the joining as the channel was not found.
+ We can't do anything else but ignore this. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER ||
+ server->server_type != SILC_ROUTER)
+ goto out;
+
+ /* We are router and the channel does not seem exist so we will check
+ our global list as well for the channel. */
+ channel = silc_idlist_find_channel_by_name(server->global_list,
+ channel_name, NULL);
+ if (!channel) {
+ /* Channel really does not exist, create it */
+ channel = silc_server_create_new_channel(server, server->id, cipher,
+ hmac, channel_name, TRUE);
+ if (!channel) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+ goto out;
+ }
+
+ umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+ created = TRUE;
+ create_key = FALSE;
+ }
+ }
+ }
+
+ /* Check whether the channel was created by our router */
+ if (cmd->pending && context2) {
+ SilcServerCommandReplyContext reply =
+ (SilcServerCommandReplyContext)context2;
+
+ if (silc_command_get(reply->payload) == SILC_COMMAND_JOIN) {
+ tmp = silc_argument_get_arg_type(reply->args, 6, NULL);
+ SILC_GET32_MSB(created, tmp);
+ if (silc_argument_get_arg_type(reply->args, 7, NULL))
+ create_key = FALSE; /* Router returned the key already */
+ }
+
+ if (silc_command_get(reply->payload) == SILC_COMMAND_WHOIS &&
+ !silc_hash_table_count(channel->user_list))
+ created = TRUE;
+ }
+
+ /* If the channel does not have global users and is also empty the client
+ will be the channel founder and operator. */
+ if (!channel->global_users && !silc_hash_table_count(channel->user_list))
+ umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+
+ /* Join to the channel */
+ silc_server_command_join_channel(server, cmd, channel, client_id,
+ created, create_key, umode,
+ auth, auth_len);
+
+ silc_free(client_id);
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+/* Server side of command MOTD. Sends server's current "message of the
+ day" to the client. */
+
+SILC_SERVER_CMD_FUNC(motd)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcBuffer packet, idp;
+ char *motd, *dest_server;
+ uint32 motd_len;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_MOTD, cmd, 1, 1);
+
+ /* Get server name */
+ dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ if (!dest_server) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
+ SILC_STATUS_ERR_NO_SUCH_SERVER);
+ goto out;
+ }
+
+ if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
+ /* Send our MOTD */
+
+ idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
+
- motd = silc_file_readfile(server->config->motd->motd_file, &motd_len);
++ if (server->config && server->config->server_info &&
++ server->config->server_info->motd_file) {
+ /* Send motd */
++ motd = silc_file_readfile(server->config->server_info->motd_file, &motd_len);
+ if (!motd)
+ goto out;
+
+ motd[motd_len] = 0;
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
+ SILC_STATUS_OK, ident, 2,
+ 2, idp, idp->len,
+ 3, motd, motd_len);
+ } else {
+ /* No motd */
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
+ SILC_STATUS_OK, ident, 1,
+ 2, idp, idp->len);
+ }
+
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+ } else {
+ SilcServerEntry entry;
+
+ /* Check whether we have this server cached */
+ entry = silc_idlist_find_server_by_name(server->global_list,
+ dest_server, TRUE, NULL);
+ if (!entry) {
+ entry = silc_idlist_find_server_by_name(server->local_list,
+ dest_server, TRUE, NULL);
+ }
+
+ if (server->server_type != SILC_SERVER && !cmd->pending &&
+ entry && !entry->motd) {
+ /* Send to the server */
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ silc_server_packet_send(server, entry->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_MOTD,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_motd,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+ goto out;
+ }
+
+ if (!entry && !cmd->pending && !server->standalone) {
+ /* Send to the primary router */
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ silc_server_packet_send(server, server->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_MOTD,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_motd,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+ goto out;
+ }
+
+ if (!entry) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+ SILC_STATUS_ERR_NO_SUCH_SERVER);
+ goto out;
+ }
+
+ idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
+ SILC_STATUS_OK, ident, 2,
+ 2, idp, idp->len,
+ 3, entry->motd,
+ entry->motd ?
+ strlen(entry->motd) : 0);
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+ }
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+/* Server side of command UMODE. Client can use this command to set/unset
+ user mode. Client actually cannot set itself to be as server/router
+ operator so this can be used only to unset the modes. */
+
+SILC_SERVER_CMD_FUNC(umode)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ SilcBuffer packet;
+ unsigned char *tmp_mask;
+ uint32 mask;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+
+ if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ goto out;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_UMODE, cmd, 2, 2);
+
+ /* Get the client's mode mask */
+ tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ if (!tmp_mask) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ SILC_GET32_MSB(mask, tmp_mask);
+
+ /*
+ * Change the mode
+ */
+
+ if (mask & SILC_UMODE_SERVER_OPERATOR) {
+ if (!(client->mode & SILC_UMODE_SERVER_OPERATOR)) {
+ /* Cannot operator mode */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
+ SILC_STATUS_ERR_PERM_DENIED);
+ goto out;
+ }
+ } else {
+ /* Remove the server operator rights */
+ if (client->mode & SILC_UMODE_SERVER_OPERATOR) {
+ client->mode &= ~SILC_UMODE_SERVER_OPERATOR;
+ if (client->connection)
+ server->stat.my_server_ops--;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.server_ops--;
+ }
+ }
+
+ if (mask & SILC_UMODE_ROUTER_OPERATOR) {
+ if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+ /* Cannot operator mode */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
+ SILC_STATUS_ERR_PERM_DENIED);
+ goto out;
+ }
+ } else {
+ /* Remove the router operator rights */
+ if (client->mode & SILC_UMODE_ROUTER_OPERATOR) {
+ client->mode &= ~SILC_UMODE_ROUTER_OPERATOR;
+ if (client->connection)
+ server->stat.my_router_ops--;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.router_ops--;
+ }
+ }
+
+ if (mask & SILC_UMODE_GONE) {
+ client->mode |= SILC_UMODE_GONE;
+ } else {
+ if (client->mode & SILC_UMODE_GONE)
+ /* Remove the gone status */
+ client->mode &= ~SILC_UMODE_GONE;
+ }
+
+ /* Send UMODE change to primary router */
+ if (!server->standalone)
+ silc_server_send_notify_umode(server, server->router->connection, TRUE,
+ client->id, client->mode);
+
+ /* Send command reply to sender */
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_UMODE,
+ SILC_STATUS_OK, ident, 1,
+ 2, tmp_mask, 4);
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+/* Checks that client has rights to add or remove channel modes. If any
+ of the checks fails FALSE is returned. */
+
+int silc_server_check_cmode_rights(SilcChannelEntry channel,
+ SilcChannelClientEntry client,
+ uint32 mode)
+{
+ int is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
+ int is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
+
+ /* Check whether has rights to change anything */
+ if (!is_op && !is_fo)
+ return FALSE;
+
+ /* Check whether has rights to change everything */
+ if (is_op && is_fo)
+ return TRUE;
+
+ /* We know that client is channel operator, check that they are not
+ changing anything that requires channel founder rights. Rest of the
+ modes are available automatically for channel operator. */
+
+ if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
+ if (is_op && !is_fo)
+ return FALSE;
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
+ if (is_op && !is_fo)
+ return FALSE;
+ }
+ }
+
+ if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE))
+ if (is_op && !is_fo)
+ return FALSE;
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+ if (is_op && !is_fo)
+ return FALSE;
+ }
+ }
+
+ if (mode & SILC_CHANNEL_MODE_CIPHER) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER))
+ if (is_op && !is_fo)
+ return FALSE;
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
+ if (is_op && !is_fo)
+ return FALSE;
+ }
+ }
+
+ if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH))
+ if (is_op && !is_fo)
+ return FALSE;
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+ if (is_op && !is_fo)
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/* Server side command of CMODE. Changes channel mode */
+
+SILC_SERVER_CMD_FUNC(cmode)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ SilcIDListData idata = (SilcIDListData)client;
+ SilcChannelID *channel_id;
+ SilcChannelEntry channel;
+ SilcChannelClientEntry chl;
+ SilcBuffer packet, cidp;
+ unsigned char *tmp, *tmp_id, *tmp_mask;
+ char *cipher = NULL, *hmac = NULL, *passphrase = NULL;
+ uint32 mode_mask, tmp_len, tmp_len2;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CMODE, cmd, 2, 7);
+
+ /* Get Channel ID */
+ tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
+ if (!tmp_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
+ channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2);
+ if (!channel_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
+
+ /* Get the channel mode mask */
+ tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (!tmp_mask) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ SILC_GET32_MSB(mode_mask, tmp_mask);
+
+ /* Get channel entry */
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ goto out;
+ }
+ }
+
+ /* Check whether this client is on the channel */
+ if (!silc_server_client_on_channel(client, channel)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NOT_ON_CHANNEL);
+ goto out;
+ }
+
+ /* Get entry to the channel user list */
+ silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl);
+
+ /* Check that client has rights to change any requested channel modes */
+ if (!silc_server_check_cmode_rights(channel, chl, mode_mask)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+ goto out;
+ }
+
+ /*
+ * Check the modes. Modes that requires nothing special operation are
+ * not checked here.
+ */
+
+ if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) {
+ /* Channel uses private keys to protect traffic. Client(s) has set the
+ key locally they want to use, server does not know that key. */
+ /* Nothing interesting to do here */
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
+ /* The mode is removed and we need to generate and distribute
+ new channel key. Clients are not using private channel keys
+ anymore after this. */
+
+ /* Re-generate channel key */
+ if (!silc_server_create_channel_key(server, channel, 0))
+ goto out;
+
+ /* Send the channel key. This sends it to our local clients and if
+ we are normal server to our router as well. */
+ silc_server_send_channel_key(server, NULL, channel,
+ server->server_type == SILC_ROUTER ?
+ FALSE : !server->standalone);
+
+ cipher = channel->channel_key->cipher->name;
+ hmac = (char *)silc_hmac_get_name(channel->hmac);
+ }
+ }
+
+ if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
+ /* User limit is set on channel */
+ uint32 user_limit;
+
+ /* Get user limit */
+ tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
+ if (!tmp) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ } else {
+ SILC_GET32_MSB(user_limit, tmp);
+ channel->user_limit = user_limit;
+ }
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
+ /* User limit mode is unset. Remove user limit */
+ channel->user_limit = 0;
+ }
+
+ if (mode_mask & SILC_CHANNEL_MODE_PASSPHRASE) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
+ /* Passphrase has been set to channel */
+
+ /* Get the passphrase */
+ tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Save the passphrase */
+ passphrase = channel->passphrase = strdup(tmp);
+ }
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+ /* Passphrase mode is unset. remove the passphrase */
+ if (channel->passphrase) {
+ silc_free(channel->passphrase);
+ channel->passphrase = NULL;
+ }
+ }
+ }
+
+ if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
+ /* Cipher to use protect the traffic */
+ SilcCipher newkey, oldkey;
+
+ /* Get cipher */
+ cipher = silc_argument_get_arg_type(cmd->args, 5, NULL);
+ if (!cipher) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Delete old cipher and allocate the new one */
+ if (!silc_cipher_alloc(cipher, &newkey)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+ goto out;
+ }
+
+ oldkey = channel->channel_key;
+ channel->channel_key = newkey;
+
+ /* Re-generate channel key */
+ if (!silc_server_create_channel_key(server, channel, 0)) {
+ /* We don't have new key, revert to old one */
+ channel->channel_key = oldkey;
+ goto out;
+ }
+
+ /* Remove old channel key for good */
+ silc_cipher_free(oldkey);
+
+ /* Send the channel key. This sends it to our local clients and if
+ we are normal server to our router as well. */
+ silc_server_send_channel_key(server, NULL, channel,
+ server->server_type == SILC_ROUTER ?
+ FALSE : !server->standalone);
+ }
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
+ /* Cipher mode is unset. Remove the cipher and revert back to
+ default cipher */
+ SilcCipher newkey, oldkey;
+ cipher = channel->cipher;
+
+ /* Delete old cipher and allocate default one */
+ if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER, &newkey)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+ goto out;
+ }
+
+ oldkey = channel->channel_key;
+ channel->channel_key = newkey;
+
+ /* Re-generate channel key */
+ if (!silc_server_create_channel_key(server, channel, 0)) {
+ /* We don't have new key, revert to old one */
+ channel->channel_key = oldkey;
+ goto out;
+ }
+
+ /* Remove old channel key for good */
+ silc_cipher_free(oldkey);
+
+ /* Send the channel key. This sends it to our local clients and if
+ we are normal server to our router as well. */
+ silc_server_send_channel_key(server, NULL, channel,
+ server->server_type == SILC_ROUTER ?
+ FALSE : !server->standalone);
+ }
+ }
+
+ if (mode_mask & SILC_CHANNEL_MODE_HMAC) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_HMAC)) {
+ /* HMAC to use protect the traffic */
+ unsigned char hash[32];
+ SilcHmac newhmac;
+
+ /* Get hmac */
+ hmac = silc_argument_get_arg_type(cmd->args, 6, NULL);
+ if (!hmac) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Delete old hmac and allocate the new one */
+ if (!silc_hmac_alloc(hmac, NULL, &newhmac)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+ goto out;
+ }
+
+ silc_hmac_free(channel->hmac);
+ channel->hmac = newhmac;
+
+ /* Set the HMAC key out of current channel key. The client must do
+ this locally. */
+ silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key,
+ channel->key_len / 8, hash);
+ silc_hmac_set_key(channel->hmac, hash,
+ silc_hash_len(silc_hmac_get_hash(channel->hmac)));
+ memset(hash, 0, sizeof(hash));
+ }
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_HMAC) {
+ /* Hmac mode is unset. Remove the hmac and revert back to
+ default hmac */
+ SilcHmac newhmac;
+ unsigned char hash[32];
+ hmac = channel->hmac_name;
+
+ /* Delete old hmac and allocate default one */
+ silc_hmac_free(channel->hmac);
+ if (!silc_hmac_alloc(hmac ? hmac : SILC_DEFAULT_HMAC, NULL, &newhmac)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+ goto out;
+ }
+
+ silc_hmac_free(channel->hmac);
+ channel->hmac = newhmac;
+
+ /* Set the HMAC key out of current channel key. The client must do
+ this locally. */
+ silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key,
+ channel->key_len / 8,
+ hash);
+ silc_hmac_set_key(channel->hmac, hash,
+ silc_hash_len(silc_hmac_get_hash(channel->hmac)));
+ memset(hash, 0, sizeof(hash));
+ }
+ }
+
+ if (mode_mask & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+ if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
+ /* Set the founder authentication */
+ SilcAuthPayload auth;
+
+ tmp = silc_argument_get_arg_type(cmd->args, 7, &tmp_len);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ auth = silc_auth_payload_parse(tmp, tmp_len);
+ if (!auth) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Save the public key */
+ tmp = silc_pkcs_public_key_encode(idata->public_key, &tmp_len);
+ silc_pkcs_public_key_decode(tmp, tmp_len, &channel->founder_key);
+ silc_free(tmp);
+
+ channel->founder_method = silc_auth_get_method(auth);
+
+ if (channel->founder_method == SILC_AUTH_PASSWORD) {
+ tmp = silc_auth_get_data(auth, &tmp_len);
+ channel->founder_passwd =
+ silc_calloc(tmp_len + 1, sizeof(*channel->founder_passwd));
+ memcpy(channel->founder_passwd, tmp, tmp_len);
+ channel->founder_passwd_len = tmp_len;
+ } else {
+ /* Verify the payload before setting the mode */
+ if (!silc_auth_verify(auth, channel->founder_method,
+ channel->founder_key, 0, idata->hash,
+ client->id, SILC_ID_CLIENT)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_AUTH_FAILED);
+ goto out;
+ }
+ }
+
+ silc_auth_payload_free(auth);
+ }
+ }
+ } else {
+ if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+ if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+ if (channel->founder_key)
+ silc_pkcs_public_key_free(channel->founder_key);
+ if (channel->founder_passwd) {
+ silc_free(channel->founder_passwd);
+ channel->founder_passwd = NULL;
+ }
+ }
+ }
+ }
+
+ /* Finally, set the mode */
+ channel->mode = mode_mask;
+
+ /* Send CMODE_CHANGE notify. */
+ cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+ SILC_NOTIFY_TYPE_CMODE_CHANGE, 5,
+ cidp->data, cidp->len,
+ tmp_mask, 4,
+ cipher, cipher ? strlen(cipher) : 0,
+ hmac, hmac ? strlen(hmac) : 0,
+ passphrase, passphrase ?
+ strlen(passphrase) : 0);
+
+ /* Set CMODE notify type to network */
+ if (!server->standalone)
+ silc_server_send_notify_cmode(server, server->router->connection,
+ server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, channel,
+ mode_mask, client->id, SILC_ID_CLIENT,
+ cipher, hmac, passphrase);
+
+ /* Send command reply to sender */
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
+ SILC_STATUS_OK, ident, 2,
+ 2, tmp_id, tmp_len2,
+ 3, tmp_mask, 4);
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+ silc_free(channel_id);
+ silc_buffer_free(cidp);
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+/* Server side of CUMODE command. Changes client's mode on a channel. */
+
+SILC_SERVER_CMD_FUNC(cumode)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ SilcIDListData idata = (SilcIDListData)client;
+ SilcChannelID *channel_id;
+ SilcClientID *client_id;
+ SilcChannelEntry channel;
+ SilcClientEntry target_client;
+ SilcChannelClientEntry chl;
+ SilcBuffer packet, idp;
+ unsigned char *tmp_id, *tmp_ch_id, *tmp_mask;
+ uint32 target_mask, sender_mask = 0, tmp_len, tmp_ch_len;
+ int notify = FALSE;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CUMODE, cmd, 3, 4);
+
+ /* Get Channel ID */
+ tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
+ if (!tmp_ch_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
+ channel_id = silc_id_payload_parse_id(tmp_ch_id, tmp_ch_len);
+ if (!channel_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
+
+ /* Get channel entry */
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ goto out;
+ }
+ }
+
+ /* Check whether sender is on the channel */
+ if (!silc_server_client_on_channel(client, channel)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NOT_ON_CHANNEL);
+ goto out;
+ }
+
+ /* Check that client has rights to change other's rights */
+ silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl);
+ sender_mask = chl->mode;
+
+ /* Get the target client's channel mode mask */
+ tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ if (!tmp_mask) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ SILC_GET32_MSB(target_mask, tmp_mask);
+
+ /* Get target Client ID */
+ tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+ if (!tmp_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NO_CLIENT_ID);
+ goto out;
+ }
+ client_id = silc_id_payload_parse_id(tmp_id, tmp_len);
+ if (!client_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NO_CLIENT_ID);
+ goto out;
+ }
+
+ /* Get target client's entry */
+ target_client = silc_idlist_find_client_by_id(server->local_list,
+ client_id, TRUE, NULL);
+ if (!target_client) {
+ target_client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, TRUE, NULL);
+ }
+
+ if (target_client != client &&
+ !(sender_mask & SILC_CHANNEL_UMODE_CHANFO) &&
+ !(sender_mask & SILC_CHANNEL_UMODE_CHANOP)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+ goto out;
+ }
+
+ /* Check whether target client is on the channel */
+ if (target_client != client) {
+ if (!silc_server_client_on_channel(target_client, channel)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
+ goto out;
+ }
+
+ /* Get entry to the channel user list */
+ silc_hash_table_find(channel->user_list, target_client, NULL,
+ (void *)&chl);
+ }
+
+ /*
+ * Change the mode
+ */
+
+ /* If the target client is founder, no one else can change their mode
+ but themselves. */
+ if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && client != target_client) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+ goto out;
+ }
+
+ if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
+ if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+ /* The client tries to claim the founder rights. */
+ unsigned char *tmp_auth;
+ uint32 tmp_auth_len, auth_len;
+ void *auth;
+
+ if (target_client != client) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NOT_YOU);
+ goto out;
+ }
+
+ if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
+ !channel->founder_key || !idata->public_key ||
+ !silc_pkcs_public_key_compare(channel->founder_key,
+ idata->public_key)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NOT_YOU);
+ goto out;
+ }
+
+ tmp_auth = silc_argument_get_arg_type(cmd->args, 4, &tmp_auth_len);
+ if (!tmp_auth) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ auth = (channel->founder_method == SILC_AUTH_PASSWORD ?
+ (void *)channel->founder_passwd : (void *)channel->founder_key);
+ auth_len = (channel->founder_method == SILC_AUTH_PASSWORD ?
+ channel->founder_passwd_len : 0);
+
+ if (!silc_auth_verify_data(tmp_auth, tmp_auth_len,
+ channel->founder_method, auth, auth_len,
+ idata->hash, client->id, SILC_ID_CLIENT)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_AUTH_FAILED);
+ goto out;
+ }
+
+ sender_mask = chl->mode |= SILC_CHANNEL_UMODE_CHANFO;
+ notify = TRUE;
+ }
+ } else {
+ if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+ if (target_client == client) {
+ /* Remove channel founder rights from itself */
+ chl->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+ notify = TRUE;
+ } else {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NOT_YOU);
+ goto out;
+ }
+ }
+ }
+
+ if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
+ /* Promote to operator */
+ if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
+ if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
+ !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+ goto out;
+ }
+
+ chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
+ notify = TRUE;
+ }
+ } else {
+ if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
+ if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
+ !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+ goto out;
+ }
+
+ /* Demote to normal user */
+ chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
+ notify = TRUE;
+ }
+ }
+
+ idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+
+ /* Send notify to channel, notify only if mode was actually changed. */
+ if (notify) {
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+ SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
+ idp->data, idp->len,
+ tmp_mask, 4,
+ tmp_id, tmp_len);
+
+ /* Set CUMODE notify type to network */
+ if (!server->standalone)
+ silc_server_send_notify_cumode(server, server->router->connection,
+ server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, channel,
+ target_mask, client->id,
+ SILC_ID_CLIENT,
+ target_client->id);
+ }
+
+ /* Send command reply to sender */
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CUMODE,
+ SILC_STATUS_OK, ident, 3,
+ 2, tmp_mask, 4,
+ 3, tmp_ch_id, tmp_ch_len,
+ 4, tmp_id, tmp_len);
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+ silc_free(channel_id);
+ silc_free(client_id);
+ silc_buffer_free(idp);
+
+ out:
+ silc_server_command_free(cmd);
}
-SILC_SERVER_CMD_FUNC(topic)
+/* Server side of KICK command. Kicks client out of channel. */
+
+SILC_SERVER_CMD_FUNC(kick)
{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ SilcClientEntry target_client;
+ SilcChannelID *channel_id;
+ SilcClientID *client_id;
+ SilcChannelEntry channel;
+ SilcChannelClientEntry chl;
+ SilcBuffer idp;
+ uint32 tmp_len, target_idp_len;
+ unsigned char *tmp, *comment, *target_idp;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 3);
+
+ /* Get Channel ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
+
+ /* Get channel entry */
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ goto out;
+ }
+ }
+
+ /* Check whether sender is on the channel */
+ if (!silc_server_client_on_channel(client, channel)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+ SILC_STATUS_ERR_NOT_ON_CHANNEL);
+ goto out;
+ }
+
+ /* Check that the kicker is channel operator or channel founder */
+ silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl);
+ if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+ goto out;
+ }
+
+ /* Get target Client ID */
+ target_idp = silc_argument_get_arg_type(cmd->args, 2, &target_idp_len);
+ if (!target_idp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+ SILC_STATUS_ERR_NO_CLIENT_ID);
+ goto out;
+ }
+ client_id = silc_id_payload_parse_id(target_idp, target_idp_len);
+ if (!client_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+ SILC_STATUS_ERR_NO_CLIENT_ID);
+ goto out;
+ }
+
+ /* Get target client's entry */
+ target_client = silc_idlist_find_client_by_id(server->local_list,
+ client_id, TRUE, NULL);
+ if (!target_client) {
+ target_client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, TRUE, NULL);
+ }
+
+ /* Check that the target client is not channel founder. Channel founder
+ cannot be kicked from the channel. */
+ silc_hash_table_find(channel->user_list, target_client, NULL, (void *)&chl);
+ if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+ SILC_STATUS_ERR_NO_CHANNEL_FOPRIV);
+ goto out;
+ }
+
+ /* Check whether target client is on the channel */
+ if (!silc_server_client_on_channel(target_client, channel)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+ SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
+ goto out;
+ }
+
+ /* Get comment */
+ tmp_len = 0;
+ comment = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+ if (tmp_len > 128)
+ comment = NULL;
+
+ /* Send command reply to sender */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+ SILC_STATUS_OK);
+
+ /* Send KICKED notify to local clients on the channel */
+ idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+ SILC_NOTIFY_TYPE_KICKED, 3,
+ target_idp, target_idp_len,
+ comment, comment ? strlen(comment) : 0,
+ idp->data, idp->len);
+ silc_buffer_free(idp);
+
+ /* Remove the client from the channel. If the channel does not exist
+ after removing the client then the client kicked itself off the channel
+ and we don't have to send anything after that. */
+ if (!silc_server_remove_from_one_channel(server, NULL, channel,
+ target_client, FALSE))
+ goto out;
+
+ /* Send KICKED notify to primary route */
+ if (!server->standalone)
+ silc_server_send_notify_kicked(server, server->router->connection,
+ server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, channel,
+ target_client->id, client->id, comment);
+
+ if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
+ /* Re-generate channel key */
+ if (!silc_server_create_channel_key(server, channel, 0))
+ goto out;
+
+ /* Send the channel key to the channel. The key of course is not sent
+ to the client who was kicked off the channel. */
+ silc_server_send_channel_key(server, target_client->connection, channel,
+ server->server_type == SILC_ROUTER ?
+ FALSE : !server->standalone);
+ }
+
+ out:
+ silc_server_command_free(cmd);
}
-SILC_SERVER_CMD_FUNC(invite)
+/* Server side of OPER command. Client uses this comand to obtain server
+ operator privileges to this server/router. */
+
+SILC_SERVER_CMD_FUNC(oper)
{
- SilcServerConfigSectionAdminConnection *admin;
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ unsigned char *username, *auth;
+ uint32 tmp_len;
++ SilcServerConfigSectionAdmin *admin;
+ SilcIDListData idata = (SilcIDListData)client;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_OPER, cmd, 1, 2);
+
+ if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ goto out;
+
+ /* Get the username */
+ username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!username) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Get the admin configuration */
+ admin = silc_server_config_find_admin(server->config, cmd->sock->ip,
+ username, client->nickname);
+ if (!admin) {
+ admin = silc_server_config_find_admin(server->config, cmd->sock->hostname,
+ username, client->nickname);
+ if (!admin) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+ SILC_STATUS_ERR_AUTH_FAILED);
+ goto out;
+ }
+ }
+
+ /* Get the authentication payload */
+ auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (!auth) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Verify the authentication data */
+ if (!silc_auth_verify_data(auth, tmp_len, admin->auth_meth,
+ admin->auth_data, admin->auth_data_len,
+ idata->hash, client->id, SILC_ID_CLIENT)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+ SILC_STATUS_ERR_AUTH_FAILED);
+ goto out;
+ }
+
+ /* Client is now server operator */
+ client->mode |= SILC_UMODE_SERVER_OPERATOR;
+
+ /* Update statistics */
+ if (client->connection)
+ server->stat.my_server_ops++;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.server_ops++;
+
+ /* Send UMODE change to primary router */
+ if (!server->standalone)
+ silc_server_send_notify_umode(server, server->router->connection, TRUE,
+ client->id, client->mode);
+
+ /* Send reply to the sender */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+ SILC_STATUS_OK);
+
+ out:
+ silc_server_command_free(cmd);
}
-/* Quits connection to client. This gets called if client won't
- close the connection even when it has issued QUIT command. */
+/* Server side of SILCOPER command. Client uses this comand to obtain router
+ operator privileges to this router. */
+
+SILC_SERVER_CMD_FUNC(silcoper)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ unsigned char *username, *auth;
+ uint32 tmp_len;
- SilcServerConfigSectionAdminConnection *admin;
++ SilcServerConfigSectionAdmin *admin;
+ SilcIDListData idata = (SilcIDListData)client;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SILCOPER, cmd, 1, 2);
+
+ if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ goto out;
+
+ if (server->server_type != SILC_ROUTER) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+ SILC_STATUS_ERR_AUTH_FAILED);
+ goto out;
+ }
+
+ /* Get the username */
+ username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!username) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Get the admin configuration */
+ admin = silc_server_config_find_admin(server->config, cmd->sock->ip,
+ username, client->nickname);
+ if (!admin) {
+ admin = silc_server_config_find_admin(server->config, cmd->sock->hostname,
+ username, client->nickname);
+ if (!admin) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+ SILC_STATUS_ERR_AUTH_FAILED);
+ goto out;
+ }
+ }
+
+ /* Get the authentication payload */
+ auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (!auth) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Verify the authentication data */
+ if (!silc_auth_verify_data(auth, tmp_len, admin->auth_meth,
+ admin->auth_data, admin->auth_data_len,
+ idata->hash, client->id, SILC_ID_CLIENT)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+ SILC_STATUS_ERR_AUTH_FAILED);
+ goto out;
+ }
+
+ /* Client is now router operator */
+ client->mode |= SILC_UMODE_ROUTER_OPERATOR;
+
+ /* Update statistics */
+ if (client->connection)
+ server->stat.my_router_ops++;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.router_ops++;
-SILC_TASK_CALLBACK(silc_server_command_quit_cb)
-{
- SilcServer server = (SilcServer)context;
- SilcSocketConnection sock = server->sockets[fd];
+ /* Send UMODE change to primary router */
+ if (!server->standalone)
+ silc_server_send_notify_umode(server, server->router->connection, TRUE,
+ client->id, client->mode);
- /* Free all client specific data, such as client entry and entires
- on channels this client may be on. */
- silc_server_free_sock_user_data(server, sock);
+ /* Send reply to the sender */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+ SILC_STATUS_OK);
- /* Close the connection on our side */
- silc_server_close_connection(server, sock);
+ out:
+ silc_server_command_free(cmd);
}
-/* Quits SILC session. This is the normal way to disconnect client. */
-
-SILC_SERVER_CMD_FUNC(quit)
+/* Server side command of CONNECT. Connects us to the specified remote
+ server or router. */
+
+SILC_SERVER_CMD_FUNC(connect)
{
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
--- /dev/null
- SilcServerConfigSectionClientConnection *client = NULL;
+/*
+
+ packet_receive.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2001 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; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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.
+
+*/
+/*
+ * Server packet routines to handle received packets.
+ */
+/* $Id$ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+
+extern char *server_version;
+
+/* Received notify packet. Server can receive notify packets from router.
+ Server then relays the notify messages to clients if needed. */
+
+void silc_server_notify(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcNotifyPayload payload;
+ SilcNotifyType type;
+ SilcArgumentPayload args;
+ SilcChannelID *channel_id = NULL, *channel_id2;
+ SilcClientID *client_id, *client_id2;
+ SilcServerID *server_id;
+ SilcChannelEntry channel;
+ SilcClientEntry client;
+ SilcServerEntry server_entry;
+ SilcChannelClientEntry chl;
+ SilcIDCacheEntry cache;
+ SilcHashTableList htl;
+ uint32 mode;
+ unsigned char *tmp;
+ uint32 tmp_len;
+ bool local;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+ packet->src_id_type != SILC_ID_SERVER)
+ return;
+
+ if (!packet->dst_id)
+ return;
+
+ /* If the packet is destined directly to a client then relay the packet
+ before processing it. */
+ if (packet->dst_id_type == SILC_ID_CLIENT) {
+ SilcIDListData idata;
+ SilcSocketConnection dst_sock;
+
+ /* Get the route to the client */
+ dst_sock = silc_server_get_client_route(server, packet->dst_id,
+ packet->dst_id_len, NULL, &idata);
+ if (dst_sock)
+ /* Relay the packet */
+ silc_server_relay_packet(server, dst_sock, idata->send_key,
+ idata->hmac_receive, idata->psn_send++,
+ packet, TRUE);
+ }
+
+ /* Parse the Notify Payload */
+ payload = silc_notify_payload_parse(packet->buffer->data,
+ packet->buffer->len);
+ if (!payload)
+ return;
+
+ /* If we are router and this packet is not already broadcast packet
+ we will broadcast it. The sending socket really cannot be router or
+ the router is buggy. If this packet is coming from router then it must
+ have the broadcast flag set already and we won't do anything. */
+ if (!server->standalone && server->server_type == SILC_ROUTER &&
+ sock->type == SILC_SOCKET_TYPE_SERVER &&
+ !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
+ SILC_LOG_DEBUG(("Broadcasting received Notify packet"));
+ if (packet->dst_id_type == SILC_ID_CHANNEL) {
+ /* Packet is destined to channel */
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ packet->dst_id_type);
+ if (!channel_id)
+ goto out;
+
+ silc_server_packet_send_dest(server, server->router->connection,
+ packet->type,
+ packet->flags | SILC_PACKET_FLAG_BROADCAST,
+ channel_id, SILC_ID_CHANNEL,
+ packet->buffer->data, packet->buffer->len,
+ FALSE);
+ silc_server_backup_send_dest(server, (SilcServerEntry)sock->user_data,
+ packet->type, packet->flags,
+ channel_id, SILC_ID_CHANNEL,
+ packet->buffer->data, packet->buffer->len,
+ FALSE, TRUE);
+ } else {
+ /* Packet is destined to client or server */
+ silc_server_packet_send(server, server->router->connection,
+ packet->type,
+ packet->flags | SILC_PACKET_FLAG_BROADCAST,
+ packet->buffer->data, packet->buffer->len,
+ FALSE);
+ silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
+ packet->type, packet->flags,
+ packet->buffer->data, packet->buffer->len,
+ FALSE, TRUE);
+ }
+ }
+
+ type = silc_notify_get_type(payload);
+ args = silc_notify_get_args(payload);
+ if (!args)
+ goto out;
+
+ switch(type) {
+ case SILC_NOTIFY_TYPE_JOIN:
+ /*
+ * Distribute the notify to local clients on the channel
+ */
+ SILC_LOG_DEBUG(("JOIN notify"));
+
+ /* Get Channel ID */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id)
+ goto out;
+
+ /* Get channel entry */
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_free(channel_id);
+ goto out;
+ }
+ }
+ silc_free(channel_id);
+
+ /* Get client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
+
+ /* If the the client is not in local list we check global list (ie. the
+ channel will be global channel) and if it does not exist then create
+ entry for the client. */
+ client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, server->server_type,
+ NULL);
+ if (!client) {
+ client = silc_idlist_find_client_by_id(server->local_list,
+ client_id, server->server_type,
+ NULL);
+ if (!client) {
+ /* If router did not find the client the it is bogus */
+ if (server->server_type != SILC_SERVER)
+ goto out;
+
+ client =
+ silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
+ silc_id_dup(client_id, SILC_ID_CLIENT),
+ sock->user_data, NULL, 0);
+ if (!client) {
+ SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
+ silc_free(client_id);
+ goto out;
+ }
+
+ client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+ }
+ }
+
+ /* Do not process the notify if the client is not registered */
+ if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
+ break;
+
+ /* Do not add client to channel if it is there already */
+ if (silc_server_client_on_channel(client, channel)) {
+ SILC_LOG_DEBUG(("Client already on channel"));
+ break;
+ }
+
+ /* Send to channel */
+ silc_server_packet_send_to_channel(server, sock, channel, packet->type,
+ FALSE, packet->buffer->data,
+ packet->buffer->len, FALSE);
+
+ if (server->server_type != SILC_ROUTER &&
+ sock->type == SILC_SOCKET_TYPE_ROUTER)
+ /* The channel is global now */
+ channel->global_users = TRUE;
+
+ SILC_LOG_DEBUG(("Joining to channel %s", channel->channel_name));
+
+ /* JOIN the global client to the channel (local clients (if router
+ created the channel) is joined in the pending JOIN command). */
+ chl = silc_calloc(1, sizeof(*chl));
+ chl->client = client;
+ chl->channel = channel;
+
+ /* If this is the first one on the channel then it is the founder of
+ the channel. */
+ if (!silc_hash_table_count(channel->user_list))
+ chl->mode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+
+ silc_hash_table_add(channel->user_list, client, chl);
+ silc_hash_table_add(client->channels, channel, chl);
+ silc_free(client_id);
+
+ break;
+
+ case SILC_NOTIFY_TYPE_LEAVE:
+ /*
+ * Distribute the notify to local clients on the channel
+ */
+ SILC_LOG_DEBUG(("LEAVE notify"));
+
+ if (!channel_id) {
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ packet->dst_id_type);
+ if (!channel_id)
+ goto out;
+ }
+
+ /* Get channel entry */
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_free(channel_id);
+ goto out;
+ }
+ }
+
+ /* Get client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp) {
+ silc_free(channel_id);
+ goto out;
+ }
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id) {
+ silc_free(channel_id);
+ goto out;
+ }
+
+ /* Get client entry */
+ client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, TRUE, NULL);
+ if (!client) {
+ client = silc_idlist_find_client_by_id(server->local_list,
+ client_id, TRUE, NULL);
+ if (!client) {
+ silc_free(client_id);
+ silc_free(channel_id);
+ goto out;
+ }
+ }
+ silc_free(client_id);
+
+ /* Check if on channel */
+ if (!silc_server_client_on_channel(client, channel))
+ break;
+
+ /* Send the leave notify to channel */
+ silc_server_packet_send_to_channel(server, sock, channel, packet->type,
+ FALSE, packet->buffer->data,
+ packet->buffer->len, FALSE);
+
+ /* Remove the user from channel */
+ silc_server_remove_from_one_channel(server, sock, channel, client, FALSE);
+ break;
+
+ case SILC_NOTIFY_TYPE_SIGNOFF:
+ /*
+ * Distribute the notify to local clients on the channel
+ */
+ SILC_LOG_DEBUG(("SIGNOFF notify"));
+
+ /* Get client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
+
+ /* Get client entry */
+ client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, TRUE, &cache);
+ if (!client) {
+ client = silc_idlist_find_client_by_id(server->local_list,
+ client_id, TRUE, &cache);
+ if (!client) {
+ silc_free(client_id);
+ goto out;
+ }
+ }
+ silc_free(client_id);
+
+ /* Get signoff message */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (tmp_len > 128)
+ tmp = NULL;
+
+ /* Update statistics */
+ server->stat.clients--;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.cell_clients--;
+ SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
+ SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
+
+ /* Remove the client from all channels. */
+ silc_server_remove_from_channels(server, NULL, client, TRUE, tmp, FALSE);
+
+ client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
+ cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
+ break;
+
+ case SILC_NOTIFY_TYPE_TOPIC_SET:
+ /*
+ * Distribute the notify to local clients on the channel
+ */
+
+ SILC_LOG_DEBUG(("TOPIC SET notify"));
+
+ if (!channel_id) {
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ packet->dst_id_type);
+ if (!channel_id)
+ goto out;
+ }
+
+ /* Get channel entry */
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_free(channel_id);
+ goto out;
+ }
+ }
+
+ /* Get the topic */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp) {
+ silc_free(channel_id);
+ goto out;
+ }
+
+ silc_free(channel->topic);
+ channel->topic = strdup(tmp);
+
+ /* Send the same notify to the channel */
+ silc_server_packet_send_to_channel(server, sock, channel, packet->type,
+ FALSE, packet->buffer->data,
+ packet->buffer->len, FALSE);
+ silc_free(channel_id);
+ break;
+
+ case SILC_NOTIFY_TYPE_NICK_CHANGE:
+ {
+ /*
+ * Distribute the notify to local clients on the channel
+ */
+ unsigned char *id, *id2;
+
+ SILC_LOG_DEBUG(("NICK CHANGE notify"));
+
+ /* Get old client ID */
+ id = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!id)
+ goto out;
+ client_id = silc_id_payload_parse_id(id, tmp_len);
+ if (!client_id)
+ goto out;
+
+ /* Get new client ID */
+ id2 = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!id2)
+ goto out;
+ client_id2 = silc_id_payload_parse_id(id2, tmp_len);
+ if (!client_id2)
+ goto out;
+
+ SILC_LOG_DEBUG(("Old Client ID id(%s)",
+ silc_id_render(client_id, SILC_ID_CLIENT)));
+ SILC_LOG_DEBUG(("New Client ID id(%s)",
+ silc_id_render(client_id2, SILC_ID_CLIENT)));
+
+ /* Replace the Client ID */
+ client = silc_idlist_replace_client_id(server->global_list, client_id,
+ client_id2);
+ if (!client)
+ client = silc_idlist_replace_client_id(server->local_list, client_id,
+ client_id2);
+
+ if (client) {
+ /* The nickname is not valid anymore, set it NULL. This causes that
+ the nickname will be queried if someone wants to know it. */
+ if (client->nickname)
+ silc_free(client->nickname);
+ client->nickname = NULL;
+
+ /* Send the NICK_CHANGE notify type to local clients on the channels
+ this client is joined to. */
+ silc_server_send_notify_on_channels(server, NULL, client,
+ SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
+ id, tmp_len,
+ id2, tmp_len);
+ }
+
+ silc_free(client_id);
+ if (!client)
+ silc_free(client_id2);
+ break;
+ }
+
+ case SILC_NOTIFY_TYPE_CMODE_CHANGE:
+ /*
+ * Distribute the notify to local clients on the channel
+ */
+
+ SILC_LOG_DEBUG(("CMODE CHANGE notify"));
+
+ if (!channel_id) {
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ packet->dst_id_type);
+ if (!channel_id)
+ goto out;
+ }
+
+ /* Get channel entry */
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_free(channel_id);
+ goto out;
+ }
+ }
+
+ /* Get the mode */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp) {
+ silc_free(channel_id);
+ goto out;
+ }
+
+ SILC_GET32_MSB(mode, tmp);
+
+ /* Check if mode changed */
+ if (channel->mode == mode)
+ break;
+
+ /* Send the same notify to the channel */
+ silc_server_packet_send_to_channel(server, sock, channel, packet->type,
+ FALSE, packet->buffer->data,
+ packet->buffer->len, FALSE);
+
+ /* If the channel had private keys set and the mode was removed then
+ we must re-generate and re-distribute a new channel key */
+ if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
+ !(mode & SILC_CHANNEL_MODE_PRIVKEY)) {
+ /* Re-generate channel key */
+ if (!silc_server_create_channel_key(server, channel, 0))
+ goto out;
+
+ /* Send the channel key. This sends it to our local clients and if
+ we are normal server to our router as well. */
+ silc_server_send_channel_key(server, NULL, channel,
+ server->server_type == SILC_ROUTER ?
+ FALSE : !server->standalone);
+ }
+
+ /* Change mode */
+ channel->mode = mode;
+ silc_free(channel_id);
+
+ /* Get the hmac */
+ tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
+ if (tmp) {
+ unsigned char hash[32];
+
+ if (channel->hmac)
+ silc_hmac_free(channel->hmac);
+ if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
+ goto out;
+
+ /* Set the HMAC key out of current channel key. The client must do
+ this locally. */
+ silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key,
+ channel->key_len / 8,
+ hash);
+ silc_hmac_set_key(channel->hmac, hash,
+ silc_hash_len(silc_hmac_get_hash(channel->hmac)));
+ memset(hash, 0, sizeof(hash));
+ }
+
+ /* Get the passphrase */
+ tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
+ if (tmp) {
+ silc_free(channel->passphrase);
+ channel->passphrase = strdup(tmp);
+ }
+
+ break;
+
+ case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
+ {
+ /*
+ * Distribute the notify to local clients on the channel
+ */
+ SilcChannelClientEntry chl2 = NULL;
+ bool notify_sent = FALSE;
+
+ SILC_LOG_DEBUG(("CUMODE CHANGE notify"));
+
+ if (!channel_id) {
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ packet->dst_id_type);
+ if (!channel_id)
+ goto out;
+ }
+
+ /* Get channel entry */
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_free(channel_id);
+ goto out;
+ }
+ }
+
+ /* Get the mode */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp) {
+ silc_free(channel_id);
+ goto out;
+ }
+
+ SILC_GET32_MSB(mode, tmp);
+
+ /* Get target client */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (!tmp)
+ goto out;
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
+
+ /* Get client entry */
+ client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, TRUE, NULL);
+ if (!client) {
+ client = silc_idlist_find_client_by_id(server->local_list,
+ client_id, TRUE, NULL);
+ if (!client) {
+ silc_free(client_id);
+ goto out;
+ }
+ }
+ silc_free(client_id);
+
+ /* Get entry to the channel user list */
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+ /* If the mode is channel founder and we already find a client
+ to have that mode on the channel we will enforce the sender
+ to change the channel founder mode away. There can be only one
+ channel founder on the channel. */
+ if (server->server_type == SILC_ROUTER &&
+ mode & SILC_CHANNEL_UMODE_CHANFO &&
+ chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+ SilcBuffer idp;
+ unsigned char cumode[4];
+
+ if (chl->client == client && chl->mode == mode) {
+ notify_sent = TRUE;
+ break;
+ }
+
+ mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+ silc_server_send_notify_cumode(server, sock, FALSE, channel, mode,
+ client->id, SILC_ID_CLIENT,
+ client->id);
+
+ idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ SILC_PUT32_MSB(mode, cumode);
+ silc_server_send_notify_to_channel(server, sock, channel, FALSE,
+ SILC_NOTIFY_TYPE_CUMODE_CHANGE,
+ 3, idp->data, idp->len,
+ cumode, 4,
+ idp->data, idp->len);
+ silc_buffer_free(idp);
+ notify_sent = TRUE;
+
+ /* Force the mode change if we alredy set the mode */
+ if (chl2) {
+ chl2->mode = mode;
+ silc_free(channel_id);
+ silc_hash_table_list_reset(&htl);
+ goto out;
+ }
+ }
+
+ if (chl->client == client) {
+ if (chl->mode == mode) {
+ notify_sent = TRUE;
+ break;
+ }
+
+ SILC_LOG_DEBUG(("Changing the channel user mode"));
+
+ /* Change the mode */
+ chl->mode = mode;
+ if (!(mode & SILC_CHANNEL_UMODE_CHANFO))
+ break;
+
+ chl2 = chl;
+ }
+ }
+ silc_hash_table_list_reset(&htl);
+
+ /* Send the same notify to the channel */
+ if (!notify_sent)
+ silc_server_packet_send_to_channel(server, sock, channel,
+ packet->type,
+ FALSE, packet->buffer->data,
+ packet->buffer->len, FALSE);
+
+ silc_free(channel_id);
+ break;
+ }
+
+ case SILC_NOTIFY_TYPE_INVITE:
+
+ if (packet->dst_id_type == SILC_ID_CLIENT)
+ goto out;
+
+ SILC_LOG_DEBUG(("INVITE notify"));
+
+ /* Get Channel ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id)
+ goto out;
+
+ /* Get channel entry */
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_free(channel_id);
+ goto out;
+ }
+ }
+ silc_free(channel_id);
+
+ /* Get the added invite */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (tmp) {
+ if (!channel->invite_list)
+ channel->invite_list = silc_calloc(tmp_len + 2,
+ sizeof(*channel->invite_list));
+ else
+ channel->invite_list = silc_realloc(channel->invite_list,
+ sizeof(*channel->invite_list) *
+ (tmp_len +
+ strlen(channel->invite_list) +
+ 2));
+ if (tmp[tmp_len - 1] == ',')
+ tmp[tmp_len - 1] = '\0';
+
+ strncat(channel->invite_list, tmp, tmp_len);
+ strncat(channel->invite_list, ",", 1);
+ }
+
+ /* Get the deleted invite */
+ tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
+ if (tmp && channel->invite_list) {
+ char *start, *end, *n;
+
+ if (!strncmp(channel->invite_list, tmp,
+ strlen(channel->invite_list) - 1)) {
+ silc_free(channel->invite_list);
+ channel->invite_list = NULL;
+ } else {
+ start = strstr(channel->invite_list, tmp);
+ if (start && strlen(start) >= tmp_len) {
+ end = start + tmp_len;
+ n = silc_calloc(strlen(channel->invite_list) - tmp_len, sizeof(*n));
+ strncat(n, channel->invite_list, start - channel->invite_list);
+ strncat(n, end + 1, ((channel->invite_list +
+ strlen(channel->invite_list)) - end) - 1);
+ silc_free(channel->invite_list);
+ channel->invite_list = n;
+ }
+ }
+ }
+
+ break;
+
+ case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
+ /*
+ * Distribute to the local clients on the channel and change the
+ * channel ID.
+ */
+
+ SILC_LOG_DEBUG(("CHANNEL CHANGE"));
+
+ if (sock->type != SILC_SOCKET_TYPE_ROUTER)
+ break;
+
+ /* Get the old Channel ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id)
+ goto out;
+
+ /* Get the channel entry */
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_free(channel_id);
+ goto out;
+ }
+ }
+
+ /* Send the notify to the channel */
+ silc_server_packet_send_to_channel(server, sock, channel, packet->type,
+ FALSE, packet->buffer->data,
+ packet->buffer->len, FALSE);
+
+ /* Get the new Channel ID */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
+ channel_id2 = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id2)
+ goto out;
+
+ SILC_LOG_DEBUG(("Old Channel ID id(%s)",
+ silc_id_render(channel_id, SILC_ID_CHANNEL)));
+ SILC_LOG_DEBUG(("New Channel ID id(%s)",
+ silc_id_render(channel_id2, SILC_ID_CHANNEL)));
+
+ /* Replace the Channel ID */
+ if (!silc_idlist_replace_channel_id(server->local_list, channel_id,
+ channel_id2))
+ if (!silc_idlist_replace_channel_id(server->global_list, channel_id,
+ channel_id2)) {
+ silc_free(channel_id2);
+ channel_id2 = NULL;
+ }
+
+ if (channel_id2) {
+ SilcBuffer users = NULL, users_modes = NULL;
+
+ /* Re-announce this channel which ID was changed. */
+ silc_server_send_new_channel(server, sock, FALSE, channel->channel_name,
+ channel->id,
+ silc_id_get_len(channel->id,
+ SILC_ID_CHANNEL),
+ channel->mode);
+
+ /* Re-announce our clients on the channel as the ID has changed now */
+ silc_server_announce_get_channel_users(server, channel, &users,
+ &users_modes);
+ if (users) {
+ silc_buffer_push(users, users->data - users->head);
+ silc_server_packet_send(server, sock,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ users->data, users->len, FALSE);
+ silc_buffer_free(users);
+ }
+ if (users_modes) {
+ silc_buffer_push(users_modes, users_modes->data - users_modes->head);
+ silc_server_packet_send_dest(server, sock,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ channel->id, SILC_ID_CHANNEL,
+ users_modes->data,
+ users_modes->len, FALSE);
+ silc_buffer_free(users_modes);
+ }
+
+ /* Re-announce channel's topic */
+ if (channel->topic) {
+ silc_server_send_notify_topic_set(server, sock,
+ server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, channel,
+ channel->id, SILC_ID_CHANNEL,
+ channel->topic);
+ }
+ }
+
+ silc_free(channel_id);
+
+ break;
+
+ case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
+ /*
+ * Remove the server entry and all clients that this server owns.
+ */
+
+ SILC_LOG_DEBUG(("SERVER SIGNOFF notify"));
+
+ /* Get Server ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ server_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!server_id)
+ goto out;
+
+ /* Get server entry */
+ server_entry = silc_idlist_find_server_by_id(server->global_list,
+ server_id, TRUE, NULL);
+ local = TRUE;
+ if (!server_entry) {
+ server_entry = silc_idlist_find_server_by_id(server->local_list,
+ server_id, TRUE, NULL);
+ local = TRUE;
+ if (!server_entry) {
+ /* If we are normal server then we might not have the server. Check
+ whether router was kind enough to send the list of all clients
+ that actually was to be removed. Remove them if the list is
+ available. */
+ if (server->server_type != SILC_ROUTER &&
+ silc_argument_get_arg_num(args) > 1) {
+ int i;
+
+ for (i = 1; i < silc_argument_get_arg_num(args); i++) {
+ /* Get Client ID */
+ tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
+ if (!tmp)
+ continue;
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ continue;
+
+ /* Get client entry */
+ client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, TRUE, &cache);
+ local = TRUE;
+ if (!client) {
+ client = silc_idlist_find_client_by_id(server->local_list,
+ client_id, TRUE, &cache);
+ local = FALSE;
+ if (!client) {
+ silc_free(client_id);
+ continue;
+ }
+ }
+ silc_free(client_id);
+
+ /* Update statistics */
+ server->stat.clients--;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.cell_clients--;
+ SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
+ SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
+
+ /* Remove the client from all channels. */
+ silc_server_remove_from_channels(server, NULL, client,
+ TRUE, NULL, FALSE);
+
+ /* Remove the client */
+ silc_idlist_del_client(local ? server->local_list :
+ server->global_list, client);
+ }
+ }
+
+ silc_free(server_id);
+ goto out;
+ }
+ }
+ silc_free(server_id);
+
+ /* Free all client entries that this server owns as they will
+ become invalid now as well. */
+ silc_server_remove_clients_by_server(server, server_entry, TRUE);
+
+ /* Remove the server entry */
+ silc_idlist_del_server(local ? server->local_list :
+ server->global_list, server_entry);
+
+ /* XXX update statistics */
+
+ break;
+
+ case SILC_NOTIFY_TYPE_KICKED:
+ /*
+ * Distribute the notify to local clients on the channel
+ */
+
+ SILC_LOG_DEBUG(("KICKED notify"));
+
+ if (!channel_id) {
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ packet->dst_id_type);
+ if (!channel_id)
+ goto out;
+ }
+
+ /* Get channel entry */
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_free(channel_id);
+ goto out;
+ }
+ }
+ silc_free(channel_id);
+
+ /* Get client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
+
+ /* If the the client is not in local list we check global list */
+ client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, TRUE, NULL);
+ if (!client) {
+ client = silc_idlist_find_client_by_id(server->local_list,
+ client_id, TRUE, NULL);
+ if (!client) {
+ silc_free(client_id);
+ goto out;
+ }
+ }
+
+ /* Send to channel */
+ silc_server_packet_send_to_channel(server, sock, channel, packet->type,
+ FALSE, packet->buffer->data,
+ packet->buffer->len, FALSE);
+
+ /* Remove the client from channel */
+ silc_server_remove_from_one_channel(server, sock, channel, client, FALSE);
+
+ break;
+
+ case SILC_NOTIFY_TYPE_KILLED:
+ {
+ /*
+ * Distribute the notify to local clients on channels
+ */
+ unsigned char *id;
+ uint32 id_len;
+
+ SILC_LOG_DEBUG(("KILLED notify"));
+
+ /* Get client ID */
+ id = silc_argument_get_arg_type(args, 1, &id_len);
+ if (!id)
+ goto out;
+ client_id = silc_id_payload_parse_id(id, id_len);
+ if (!client_id)
+ goto out;
+
+ /* If the the client is not in local list we check global list */
+ client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, TRUE, NULL);
+ if (!client) {
+ client = silc_idlist_find_client_by_id(server->local_list,
+ client_id, TRUE, NULL);
+ if (!client) {
+ silc_free(client_id);
+ goto out;
+ }
+ }
+ silc_free(client_id);
+
+ /* If the client is one of ours, then close the connection to the
+ client now. This removes the client from all channels as well. */
+ if (packet->dst_id_type == SILC_ID_CLIENT && client->connection) {
+ sock = client->connection;
+ silc_server_free_client_data(server, NULL, client, FALSE, NULL);
+ silc_server_close_connection(server, sock);
+ break;
+ }
+
+ /* Get comment */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (tmp_len > 128)
+ tmp = NULL;
+
+ /* Send the notify to local clients on the channels except to the
+ client who is killed. */
+ silc_server_send_notify_on_channels(server, client, client,
+ SILC_NOTIFY_TYPE_KILLED,
+ tmp ? 2 : 1,
+ id, id_len,
+ tmp, tmp_len);
+
+ /* Remove the client from all channels */
+ silc_server_remove_from_channels(server, NULL, client, FALSE, NULL,
+ FALSE);
+
+ break;
+ }
+
+ case SILC_NOTIFY_TYPE_UMODE_CHANGE:
+ /*
+ * Save the mode of the client.
+ */
+
+ SILC_LOG_DEBUG(("UMODE_CHANGE notify"));
+
+ /* Get client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
+
+ /* Get client entry */
+ client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, TRUE, NULL);
+ if (!client) {
+ client = silc_idlist_find_client_by_id(server->local_list,
+ client_id, TRUE, NULL);
+ if (!client) {
+ silc_free(client_id);
+ goto out;
+ }
+ }
+ silc_free(client_id);
+
+ /* Get the mode */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
+ SILC_GET32_MSB(mode, tmp);
+
+#define SILC_UMODE_STATS_UPDATE(oper, mod) \
+do { \
+ if (client->mode & (mod)) { \
+ if (!(mode & (mod))) { \
+ if (client->connection) \
+ server->stat.my_ ## oper ## _ops--; \
+ if (server->server_type == SILC_ROUTER) \
+ server->stat. oper ## _ops--; \
+ } \
+ } else { \
+ if (mode & (mod)) { \
+ if (client->connection) \
+ server->stat.my_ ## oper ## _ops++; \
+ if (server->server_type == SILC_ROUTER) \
+ server->stat. oper ## _ops++; \
+ } \
+ } \
+} while(0)
+
+ /* Update statistics */
+ SILC_UMODE_STATS_UPDATE(server, SILC_UMODE_SERVER_OPERATOR);
+ SILC_UMODE_STATS_UPDATE(router, SILC_UMODE_ROUTER_OPERATOR);
+
+ /* Save the mode */
+ client->mode = mode;
+
+ break;
+
+ case SILC_NOTIFY_TYPE_BAN:
+ /*
+ * Save the ban
+ */
+
+ SILC_LOG_DEBUG(("BAN notify"));
+
+ /* Get Channel ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id)
+ goto out;
+
+ /* Get channel entry */
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_free(channel_id);
+ goto out;
+ }
+ }
+ silc_free(channel_id);
+
+ /* Get the new ban and add it to the ban list */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (tmp) {
+ if (!channel->ban_list)
+ channel->ban_list = silc_calloc(tmp_len + 2,
+ sizeof(*channel->ban_list));
+ else
+ channel->ban_list = silc_realloc(channel->ban_list,
+ sizeof(*channel->ban_list) *
+ (tmp_len +
+ strlen(channel->ban_list) + 2));
+ strncat(channel->ban_list, tmp, tmp_len);
+ strncat(channel->ban_list, ",", 1);
+ }
+
+ /* Get the ban to be removed and remove it from the list */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (tmp && channel->ban_list) {
+ char *start, *end, *n;
+
+ if (!strncmp(channel->ban_list, tmp, strlen(channel->ban_list) - 1)) {
+ silc_free(channel->ban_list);
+ channel->ban_list = NULL;
+ } else {
+ start = strstr(channel->ban_list, tmp);
+ if (start && strlen(start) >= tmp_len) {
+ end = start + tmp_len;
+ n = silc_calloc(strlen(channel->ban_list) - tmp_len, sizeof(*n));
+ strncat(n, channel->ban_list, start - channel->ban_list);
+ strncat(n, end + 1, ((channel->ban_list +
+ strlen(channel->ban_list)) - end) - 1);
+ silc_free(channel->ban_list);
+ channel->ban_list = n;
+ }
+ }
+ }
+ break;
+
+ /* Ignore rest of the notify types for now */
+ case SILC_NOTIFY_TYPE_NONE:
+ case SILC_NOTIFY_TYPE_MOTD:
+ break;
+ default:
+ break;
+ }
+
+ out:
+ silc_notify_payload_free(payload);
+}
+
+void silc_server_notify_list(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcPacketContext *new;
+ SilcBuffer buffer;
+ uint16 len;
+
+ SILC_LOG_DEBUG(("Processing Notify List"));
+
+ if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+ packet->src_id_type != SILC_ID_SERVER)
+ return;
+
+ /* Make copy of the original packet context, except for the actual
+ data buffer, which we will here now fetch from the original buffer. */
+ new = silc_packet_context_alloc();
+ new->type = SILC_PACKET_NOTIFY;
+ new->flags = packet->flags;
+ new->src_id = packet->src_id;
+ new->src_id_len = packet->src_id_len;
+ new->src_id_type = packet->src_id_type;
+ new->dst_id = packet->dst_id;
+ new->dst_id_len = packet->dst_id_len;
+ new->dst_id_type = packet->dst_id_type;
+
+ buffer = silc_buffer_alloc(1024);
+ new->buffer = buffer;
+
+ while (packet->buffer->len) {
+ SILC_GET16_MSB(len, packet->buffer->data + 2);
+ if (len > packet->buffer->len)
+ break;
+
+ if (len > buffer->truelen) {
+ silc_buffer_free(buffer);
+ buffer = silc_buffer_alloc(1024 + len);
+ }
+
+ silc_buffer_pull_tail(buffer, len);
+ silc_buffer_put(buffer, packet->buffer->data, len);
+
+ /* Process the Notify */
+ silc_server_notify(server, sock, new);
+
+ silc_buffer_push_tail(buffer, len);
+ silc_buffer_pull(packet->buffer, len);
+ }
+
+ silc_buffer_free(buffer);
+ silc_free(new);
+}
+
+/* Received private message. This resolves the destination of the message
+ and sends the packet. This is used by both server and router. If the
+ destination is our locally connected client this sends the packet to
+ the client. This may also send the message for further routing if
+ the destination is not in our server (or router). */
+
+void silc_server_private_message(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcSocketConnection dst_sock;
+ SilcIDListData idata;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (packet->src_id_type != SILC_ID_CLIENT ||
+ packet->dst_id_type != SILC_ID_CLIENT || !packet->dst_id)
+ return;
+
+ /* Get the route to the client */
+ dst_sock = silc_server_get_client_route(server, packet->dst_id,
+ packet->dst_id_len, NULL, &idata);
+ if (!dst_sock) {
+ /* Send IDENTIFY command reply with error status to indicate that
+ such destination ID does not exist or is invalid */
+ SilcBuffer idp = silc_id_payload_encode_data(packet->dst_id,
+ packet->dst_id_len,
+ packet->dst_id_type);
+ if (!idp)
+ return;
+
+ if (packet->src_id_type == SILC_ID_CLIENT) {
+ SilcClientID *client_id = silc_id_str2id(packet->src_id,
+ packet->src_id_len,
+ packet->src_id_type);
+ silc_server_send_dest_command_reply(server, sock,
+ client_id, SILC_ID_CLIENT,
+ SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+ 0, 1, 2, idp->data, idp->len);
+ silc_free(client_id);
+ } else {
+ silc_server_send_command_reply(server, sock, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+ 0, 1, 2, idp->data, idp->len);
+ }
+
+ silc_buffer_free(idp);
+ return;
+ }
+
+ /* Send the private message */
+ silc_server_send_private_message(server, dst_sock, idata->send_key,
+ idata->hmac_send, idata->psn_send++,
+ packet);
+}
+
+/* Received private message key packet.. This packet is never for us. It is to
+ the client in the packet's destination ID. Sending of this sort of packet
+ equals sending private message, ie. it is sent point to point from
+ one client to another. */
+
+void silc_server_private_message_key(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcSocketConnection dst_sock;
+ SilcIDListData idata;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (packet->src_id_type != SILC_ID_CLIENT ||
+ packet->dst_id_type != SILC_ID_CLIENT)
+ return;
+
+ if (!packet->dst_id)
+ return;
+
+ /* Get the route to the client */
+ dst_sock = silc_server_get_client_route(server, packet->dst_id,
+ packet->dst_id_len, NULL, &idata);
+ if (!dst_sock)
+ return;
+
+ /* Relay the packet */
+ silc_server_relay_packet(server, dst_sock, idata->send_key,
+ idata->hmac_send, idata->psn_send++, packet, FALSE);
+}
+
+/* Processes incoming command reply packet. The command reply packet may
+ be destined to one of our clients or it may directly for us. We will
+ call the command reply routine after processing the packet. */
+
+void silc_server_command_reply(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcClientEntry client = NULL;
+ SilcSocketConnection dst_sock;
+ SilcIDListData idata;
+ SilcClientID *id = NULL;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Source must be server or router */
+ if (packet->src_id_type != SILC_ID_SERVER &&
+ sock->type != SILC_SOCKET_TYPE_ROUTER)
+ return;
+
+ if (packet->dst_id_type == SILC_ID_CHANNEL)
+ return;
+
+ if (packet->dst_id_type == SILC_ID_CLIENT) {
+ /* Destination must be one of ours */
+ id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CLIENT);
+ if (!id)
+ return;
+ client = silc_idlist_find_client_by_id(server->local_list, id, TRUE, NULL);
+ if (!client) {
+ SILC_LOG_ERROR(("Cannot process command reply to unknown client"));
+ silc_free(id);
+ return;
+ }
+ }
+
+ if (packet->dst_id_type == SILC_ID_SERVER) {
+ /* For now this must be for us */
+ if (memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
+ SILC_LOG_ERROR(("Cannot process command reply to unknown server"));
+ return;
+ }
+ }
+
+ /* Execute command reply locally for the command */
+ silc_server_command_reply_process(server, sock, buffer);
+
+ if (packet->dst_id_type == SILC_ID_CLIENT && client && id) {
+ /* Relay the packet to the client */
+
+ dst_sock = (SilcSocketConnection)client->connection;
+ silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ + packet->dst_id_len + packet->padlen);
+
+ silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
+ silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+
+ idata = (SilcIDListData)client;
+
+ /* Encrypt packet */
+ silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
+ dst_sock->outbuf, buffer->len);
+
+ /* Send the packet */
+ silc_server_packet_send_real(server, dst_sock, TRUE);
+
+ silc_free(id);
+ }
+}
+
+/* Process received channel message. The message can be originated from
+ client or server. */
+
+void silc_server_channel_message(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcChannelEntry channel = NULL;
+ SilcChannelID *id = NULL;
+ void *sender = NULL;
+ void *sender_entry = NULL;
+ bool local = TRUE;
+
+ SILC_LOG_DEBUG(("Processing channel message"));
+
+ /* Sanity checks */
+ if (packet->dst_id_type != SILC_ID_CHANNEL) {
+ SILC_LOG_DEBUG(("Received bad message for channel, dropped"));
+ goto out;
+ }
+
+ /* Find channel entry */
+ id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL);
+ if (!id)
+ goto out;
+ channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
+ if (!channel) {
+ SILC_LOG_DEBUG(("Could not find channel"));
+ goto out;
+ }
+ }
+
+ /* See that this client is on the channel. If the original sender is
+ not client (as it can be server as well) we don't do the check. */
+ sender = silc_id_str2id(packet->src_id, packet->src_id_len,
+ packet->src_id_type);
+ if (!sender)
+ goto out;
+ if (packet->src_id_type == SILC_ID_CLIENT) {
+ sender_entry = silc_idlist_find_client_by_id(server->local_list,
+ sender, TRUE, NULL);
+ if (!sender_entry) {
+ local = FALSE;
+ sender_entry = silc_idlist_find_client_by_id(server->global_list,
+ sender, TRUE, NULL);
+ }
+ if (!sender_entry || !silc_server_client_on_channel(sender_entry,
+ channel)) {
+ SILC_LOG_DEBUG(("Client not on channel"));
+ goto out;
+ }
+
+ /* If the packet is coming from router, but the client entry is
+ local entry to us then some router is rerouting this to us and it is
+ not allowed. */
+ if (server->server_type == SILC_ROUTER &&
+ sock->type == SILC_SOCKET_TYPE_ROUTER && local) {
+ SILC_LOG_DEBUG(("Channel message rerouted to the sender, drop it"));
+ goto out;
+ }
+ }
+
+ /* Distribute the packet to our local clients. This will send the
+ packet for further routing as well, if needed. */
+ silc_server_packet_relay_to_channel(server, sock, channel, sender,
+ packet->src_id_type, sender_entry,
+ packet->buffer->data,
+ packet->buffer->len, FALSE);
+
+ out:
+ if (sender)
+ silc_free(sender);
+ if (id)
+ silc_free(id);
+}
+
+/* Received channel key packet. We distribute the key to all of our locally
+ connected clients on the channel. */
+
+void silc_server_channel_key(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcChannelEntry channel;
+
+ if (packet->src_id_type != SILC_ID_SERVER ||
+ (server->server_type == SILC_ROUTER &&
+ sock->type == SILC_SOCKET_TYPE_ROUTER))
+ return;
+
+ /* Save the channel key */
+ channel = silc_server_save_channel_key(server, buffer, NULL);
+ if (!channel)
+ return;
+
+ /* Distribute the key to everybody who is on the channel. If we are router
+ we will also send it to locally connected servers. */
+ silc_server_send_channel_key(server, sock, channel, FALSE);
+
+ if (server->server_type != SILC_BACKUP_ROUTER) {
+ /* Distribute to local cell backup routers. */
+ silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
+ SILC_PACKET_CHANNEL_KEY, 0,
+ buffer->data, buffer->len, FALSE, TRUE);
+ }
+}
+
+/* Received New Client packet and processes it. Creates Client ID for the
+ client. Client becomes registered after calling this functions. */
+
+SilcClientEntry silc_server_new_client(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcClientEntry client;
+ SilcClientID *client_id;
+ SilcBuffer reply;
+ SilcIDListData idata;
+ char *username = NULL, *realname = NULL, *id_string;
+ uint16 username_len;
+ uint32 id_len;
+ int ret;
+ char *hostname, *nickname;
+ int nickfail = 0;
+
+ SILC_LOG_DEBUG(("Creating new client"));
+
+ if (sock->type != SILC_SOCKET_TYPE_CLIENT)
+ return NULL;
+
+ /* Take client entry */
+ client = (SilcClientEntry)sock->user_data;
+ idata = (SilcIDListData)client;
+
+ /* Remove the old cache entry. */
+ if (!silc_idcache_del_by_context(server->local_list->clients, client)) {
+ SILC_LOG_ERROR(("Lost client's cache entry - bad thing"));
+ silc_server_disconnect_remote(server, sock, "Server closed connection: "
+ "Unknown client");
+ return NULL;
+ }
+
+ /* Parse incoming packet */
+ ret = silc_buffer_unformat(buffer,
+ SILC_STR_UI16_NSTRING_ALLOC(&username,
+ &username_len),
+ SILC_STR_UI16_STRING_ALLOC(&realname),
+ SILC_STR_END);
+ if (ret == -1) {
+ silc_free(username);
+ silc_free(realname);
+ silc_server_disconnect_remote(server, sock, "Server closed connection: "
+ "Incomplete client information");
+ return NULL;
+ }
+
+ if (!username) {
+ silc_free(username);
+ silc_free(realname);
+ silc_server_disconnect_remote(server, sock, "Server closed connection: "
+ "Incomplete client information");
+ return NULL;
+ }
+
+ if (username_len > 128)
+ username[128] = '\0';
+
+ /* Check for bad characters for nickname, and modify the nickname if
+ it includes those. */
+ if (silc_server_name_bad_chars(username, username_len)) {
+ nickname = silc_server_name_modify_bad(username, username_len);
+ } else {
+ nickname = strdup(username);
+ }
+
+ /* Make sanity checks for the hostname of the client. If the hostname
+ is provided in the `username' check that it is the same than the
+ resolved hostname, or if not resolved the hostname that appears in
+ the client's public key. If the hostname is not present then put
+ it from the resolved name or from the public key. */
+ if (strchr(username, '@')) {
+ SilcPublicKeyIdentifier pident;
+ int tlen = strcspn(username, "@");
+ char *phostname = NULL;
+
+ hostname = silc_calloc((strlen(username) - tlen) + 1, sizeof(char));
+ memcpy(hostname, username + tlen + 1, strlen(username) - tlen - 1);
+
+ if (strcmp(sock->hostname, sock->ip) &&
+ strcmp(sock->hostname, hostname)) {
+ silc_free(username);
+ silc_free(hostname);
+ silc_free(realname);
+ silc_server_disconnect_remote(server, sock,
+ "Server closed connection: "
+ "Incomplete client information");
+ return NULL;
+ }
+
+ pident = silc_pkcs_decode_identifier(client->data.public_key->identifier);
+ if (pident) {
+ phostname = strdup(pident->host);
+ silc_pkcs_free_identifier(pident);
+ }
+
+ if (!strcmp(sock->hostname, sock->ip) &&
+ phostname && strcmp(phostname, hostname)) {
+ silc_free(username);
+ silc_free(hostname);
+ silc_free(phostname);
+ silc_free(realname);
+ silc_server_disconnect_remote(server, sock,
+ "Server closed connection: "
+ "Incomplete client information");
+ return NULL;
+ }
+
+ silc_free(phostname);
+ } else {
+ /* The hostname is not present, add it. */
+ char *newusername;
+ /* XXX For now we cannot take the host name from the public key since
+ they are not trusted or we cannot verify them as trusted. Just take
+ what the resolved name or address is. */
+#if 0
+ if (strcmp(sock->hostname, sock->ip)) {
+#endif
+ newusername = silc_calloc(strlen(username) +
+ strlen(sock->hostname) + 2,
+ sizeof(*newusername));
+ strncat(newusername, username, strlen(username));
+ strncat(newusername, "@", 1);
+ strncat(newusername, sock->hostname, strlen(sock->hostname));
+ silc_free(username);
+ username = newusername;
+#if 0
+ } else {
+ SilcPublicKeyIdentifier pident =
+ silc_pkcs_decode_identifier(client->data.public_key->identifier);
+
+ if (pident) {
+ newusername = silc_calloc(strlen(username) +
+ strlen(pident->host) + 2,
+ sizeof(*newusername));
+ strncat(newusername, username, strlen(username));
+ strncat(newusername, "@", 1);
+ strncat(newusername, pident->host, strlen(pident->host));
+ silc_free(username);
+ username = newusername;
+ silc_pkcs_free_identifier(pident);
+ }
+ }
+#endif
+ }
+
+ /* Create Client ID */
+ while (!silc_id_create_client_id(server, server->id, server->rng,
+ server->md5hash, nickname, &client_id)) {
+ nickfail++;
+ snprintf(&nickname[strlen(nickname) - 1], 1, "%d", nickfail);
+ }
+
+ /* Update client entry */
+ idata->status |= SILC_IDLIST_STATUS_REGISTERED;
+ client->nickname = nickname;
+ client->username = username;
+ client->userinfo = realname ? realname : strdup(" ");
+ client->id = client_id;
+ id_len = silc_id_get_len(client_id, SILC_ID_CLIENT);
+
+ /* Add the client again to the ID cache */
+ silc_idcache_add(server->local_list->clients, client->nickname,
+ client_id, client, 0, NULL);
+
+ /* Notify our router about new client on the SILC network */
+ if (!server->standalone)
+ silc_server_send_new_id(server, (SilcSocketConnection)
+ server->router->connection,
+ server->server_type == SILC_ROUTER ? TRUE : FALSE,
+ client->id, SILC_ID_CLIENT, id_len);
+
+ /* Send the new client ID to the client. */
+ id_string = silc_id_id2str(client->id, SILC_ID_CLIENT);
+ reply = silc_buffer_alloc(2 + 2 + id_len);
+ silc_buffer_pull_tail(reply, SILC_BUFFER_END(reply));
+ silc_buffer_format(reply,
+ SILC_STR_UI_SHORT(SILC_ID_CLIENT),
+ SILC_STR_UI_SHORT(id_len),
+ SILC_STR_UI_XNSTRING(id_string, id_len),
+ SILC_STR_END);
+ silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 0,
+ reply->data, reply->len, FALSE);
+ silc_free(id_string);
+ silc_buffer_free(reply);
+
+ /* Send some nice info to the client */
+ SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+ ("Welcome to the SILC Network %s",
+ username));
+ SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+ ("Your host is %s, running version %s",
+ server->config->server_info->server_name,
+ server_version));
+ if (server->server_type == SILC_ROUTER) {
+ SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+ ("There are %d clients on %d servers in SILC "
+ "Network", server->stat.clients,
+ server->stat.servers + 1));
+ SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+ ("There are %d clients on %d server in our cell",
+ server->stat.cell_clients,
+ server->stat.cell_servers + 1));
+ SILC_SERVER_SEND_NOTIFY(server, sock, 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));
+ SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+ ("There are %d server operators and %d router "
+ "operators online",
+ server->stat.server_ops,
+ server->stat.router_ops));
+ SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+ ("I have %d operators online",
+ server->stat.my_router_ops +
+ server->stat.my_server_ops));
+ } else {
+ SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+ ("I have %d clients and %d channels formed",
+ server->stat.my_clients,
+ server->stat.my_channels));
+ SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+ ("%d operators online",
+ server->stat.my_server_ops));
+ }
+ SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+ ("Your connection is secured with %s cipher, "
+ "key length %d bits",
+ idata->send_key->cipher->name,
+ idata->send_key->cipher->key_len));
+ SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+ ("Your current nickname is %s",
+ client->nickname));
+
+ /* Send motd */
+ silc_server_send_motd(server, sock);
+
+ return client;
+}
+
+/* Create new server. This processes received New Server packet and
+ saves the received Server ID. The server is our locally connected
+ server thus we save all the information and save it to local list.
+ This funtion can be used by both normal server and router server.
+ If normal server uses this it means that its router has connected
+ to the server. If router uses this it means that one of the cell's
+ servers is connected to the router. */
+
+SilcServerEntry silc_server_new_server(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcServerEntry new_server, server_entry;
+ SilcServerID *server_id;
+ SilcIDListData idata;
+ unsigned char *server_name, *id_string;
+ uint16 id_len, name_len;
+ int ret;
+ bool local = TRUE;
+
+ SILC_LOG_DEBUG(("Creating new server"));
+
+ if (sock->type != SILC_SOCKET_TYPE_SERVER &&
+ sock->type != SILC_SOCKET_TYPE_ROUTER)
+ return NULL;
+
+ /* Take server entry */
+ new_server = (SilcServerEntry)sock->user_data;
+ idata = (SilcIDListData)new_server;
+
+ /* Remove the old cache entry */
+ if (!silc_idcache_del_by_context(server->local_list->servers, new_server)) {
+ silc_idcache_del_by_context(server->global_list->servers, new_server);
+ local = FALSE;
+ }
+
+ /* Parse the incoming packet */
+ ret = silc_buffer_unformat(buffer,
+ SILC_STR_UI16_NSTRING_ALLOC(&id_string, &id_len),
+ SILC_STR_UI16_NSTRING_ALLOC(&server_name,
+ &name_len),
+ SILC_STR_END);
+ if (ret == -1) {
+ if (id_string)
+ silc_free(id_string);
+ if (server_name)
+ silc_free(server_name);
+ return NULL;
+ }
+
+ if (id_len > buffer->len) {
+ silc_free(id_string);
+ silc_free(server_name);
+ return NULL;
+ }
+
+ if (name_len > 256)
+ server_name[255] = '\0';
+
+ /* Get Server ID */
+ server_id = silc_id_str2id(id_string, id_len, SILC_ID_SERVER);
+ if (!server_id) {
+ silc_free(id_string);
+ silc_free(server_name);
+ return NULL;
+ }
+ silc_free(id_string);
+
+ /* Check that we do not have this ID already */
+ server_entry = silc_idlist_find_server_by_id(server->local_list,
+ server_id, TRUE, NULL);
+ if (server_entry) {
+ silc_idcache_del_by_context(server->local_list->servers, server_entry);
+ } else {
+ server_entry = silc_idlist_find_server_by_id(server->global_list,
+ server_id, TRUE, NULL);
+ if (server_entry)
+ silc_idcache_del_by_context(server->global_list->servers, server_entry);
+ }
+
+ /* Update server entry */
+ idata->status |= SILC_IDLIST_STATUS_REGISTERED;
+ new_server->server_name = server_name;
+ new_server->id = server_id;
+
+ SILC_LOG_DEBUG(("New server id(%s)",
+ silc_id_render(server_id, SILC_ID_SERVER)));
+
+ /* Add again the entry to the ID cache. */
+ silc_idcache_add(local ? server->local_list->servers :
+ server->global_list->servers, server_name, server_id,
+ new_server, 0, NULL);
+
+ /* Distribute the information about new server in the SILC network
+ to our router. If we are normal server we won't send anything
+ since this connection must be our router connection. */
+ if (server->server_type == SILC_ROUTER && !server->standalone &&
+ server->router->connection != sock)
+ silc_server_send_new_id(server, server->router->connection,
+ TRUE, new_server->id, SILC_ID_SERVER,
+ silc_id_get_len(server_id, SILC_ID_SERVER));
+
+ if (server->server_type == SILC_ROUTER)
+ server->stat.cell_servers++;
+
+ /* Check whether this router connection has been replaced by an
+ backup router. If it has been then we'll disable the server and will
+ ignore everything it will send until the backup router resuming
+ protocol has been completed. */
+ if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
+ silc_server_backup_replaced_get(server, server_id, NULL)) {
+ /* Send packet to the server indicating that it cannot use this
+ connection as it has been replaced by backup router. */
+ SilcBuffer packet = silc_buffer_alloc(2);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_REPLACED),
+ SILC_STR_UI_CHAR(0),
+ SILC_STR_END);
+ silc_server_packet_send(server, sock,
+ SILC_PACKET_RESUME_ROUTER, 0,
+ packet->data, packet->len, TRUE);
+ silc_buffer_free(packet);
+
+ /* Mark the router disabled. The data sent earlier will go but nothing
+ after this does not go to this connection. */
+ idata->status |= SILC_IDLIST_STATUS_DISABLED;
+ } else {
+ /* If it is router announce our stuff to it. */
+ if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
+ server->server_type == SILC_ROUTER) {
+ silc_server_announce_servers(server, FALSE, 0, sock);
+ silc_server_announce_clients(server, 0, sock);
+ silc_server_announce_channels(server, 0, sock);
+ }
+ }
+
+ return new_server;
+}
+
+/* Processes incoming New ID packet. New ID Payload is used to distribute
+ information about newly registered clients and servers. */
+
+static void silc_server_new_id_real(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet,
+ int broadcast)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcIDList id_list;
+ SilcServerEntry router, server_entry;
+ SilcSocketConnection router_sock;
+ SilcIDPayload idp;
+ SilcIdType id_type;
+ void *id;
+
+ SILC_LOG_DEBUG(("Processing new ID"));
+
+ if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+ server->server_type == SILC_SERVER ||
+ packet->src_id_type != SILC_ID_SERVER)
+ return;
+
+ idp = silc_id_payload_parse(buffer->data, buffer->len);
+ if (!idp)
+ return;
+
+ id_type = silc_id_payload_get_type(idp);
+
+ /* Normal server cannot have other normal server connections */
+ server_entry = (SilcServerEntry)sock->user_data;
+ if (id_type == SILC_ID_SERVER && sock->type == SILC_SOCKET_TYPE_SERVER &&
+ server_entry->server_type == SILC_SERVER)
+ goto out;
+
+ id = silc_id_payload_get_id(idp);
+ if (!id)
+ goto out;
+
+ /* If the packet is coming from server then use the sender as the
+ origin of the the packet. If it came from router then check the real
+ sender of the packet and use that as the origin. */
+ if (sock->type == SILC_SOCKET_TYPE_SERVER) {
+ id_list = server->local_list;
+ router_sock = sock;
+ router = sock->user_data;
+
+ /* If the sender is backup router and ID is server (and we are not
+ backup router) then switch the entry to global list. */
+ if (server_entry->server_type == SILC_BACKUP_ROUTER &&
+ id_type == SILC_ID_SERVER &&
+ server->id_entry->server_type != SILC_BACKUP_ROUTER) {
+ id_list = server->global_list;
+ router_sock = server->router ? server->router->connection : sock;
+ }
+ } else {
+ void *sender_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ packet->src_id_type);
+ router = silc_idlist_find_server_by_id(server->global_list,
+ sender_id, TRUE, NULL);
+ if (!router)
+ router = silc_idlist_find_server_by_id(server->local_list,
+ sender_id, TRUE, NULL);
+ silc_free(sender_id);
+ router_sock = sock;
+ id_list = server->global_list;
+ }
+
+ if (!router)
+ goto out;
+
+ switch(id_type) {
+ case SILC_ID_CLIENT:
+ {
+ SilcClientEntry entry;
+
+ /* Check that we do not have this client already */
+ entry = silc_idlist_find_client_by_id(server->global_list,
+ id, server->server_type,
+ NULL);
+ if (!entry)
+ entry = silc_idlist_find_client_by_id(server->local_list,
+ id, server->server_type,
+ NULL);
+ if (entry) {
+ SILC_LOG_DEBUG(("Ignoring client that we already have"));
+ goto out;
+ }
+
+ SILC_LOG_DEBUG(("New client id(%s) from [%s] %s",
+ silc_id_render(id, SILC_ID_CLIENT),
+ sock->type == SILC_SOCKET_TYPE_SERVER ?
+ "Server" : "Router", sock->hostname));
+
+ /* As a router we keep information of all global information in our
+ global list. Cell wide information however is kept in the local
+ list. */
+ entry = silc_idlist_add_client(id_list, NULL, NULL, NULL,
+ id, router, NULL, 0);
+ if (!entry) {
+ SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
+
+ /* Inform the sender that the ID is not usable */
+ silc_server_send_notify_signoff(server, sock, FALSE, id, NULL);
+ goto out;
+ }
+ entry->nickname = NULL;
+ entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+
+ if (sock->type == SILC_SOCKET_TYPE_SERVER)
+ server->stat.cell_clients++;
+ server->stat.clients++;
+ }
+ break;
+
+ case SILC_ID_SERVER:
+ {
+ SilcServerEntry entry;
+
+ /* If the ID is mine, ignore it. */
+ if (SILC_ID_SERVER_COMPARE(id, server->id)) {
+ SILC_LOG_DEBUG(("Ignoring my own ID as new ID"));
+ break;
+ }
+
+ /* If the ID is the sender's ID, ignore it (we have it already) */
+ if (SILC_ID_SERVER_COMPARE(id, router->id)) {
+ SILC_LOG_DEBUG(("Ignoring sender's own ID"));
+ break;
+ }
+
+ /* Check that we do not have this server already */
+ entry = silc_idlist_find_server_by_id(server->global_list,
+ id, server->server_type,
+ NULL);
+ if (!entry)
+ entry = silc_idlist_find_server_by_id(server->local_list,
+ id, server->server_type,
+ NULL);
+ if (entry) {
+ SILC_LOG_DEBUG(("Ignoring server that we already have"));
+ goto out;
+ }
+
+ SILC_LOG_DEBUG(("New server id(%s) from [%s] %s",
+ silc_id_render(id, SILC_ID_SERVER),
+ sock->type == SILC_SOCKET_TYPE_SERVER ?
+ "Server" : "Router", sock->hostname));
+
+ /* As a router we keep information of all global information in our
+ global list. Cell wide information however is kept in the local
+ list. */
+ entry = silc_idlist_add_server(id_list, NULL, 0, id, router,
+ router_sock);
+ if (!entry) {
+ SILC_LOG_ERROR(("Could not add new server to the ID Cache"));
+ goto out;
+ }
+ entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+
+ if (sock->type == SILC_SOCKET_TYPE_SERVER)
+ server->stat.cell_servers++;
+ server->stat.servers++;
+ }
+ break;
+
+ case SILC_ID_CHANNEL:
+ SILC_LOG_ERROR(("Channel cannot be registered with NEW_ID packet"));
+ goto out;
+ break;
+
+ default:
+ goto out;
+ break;
+ }
+
+ /* If the sender of this packet is server and we are router we need to
+ broadcast this packet to other routers in the network. */
+ if (broadcast && !server->standalone && server->server_type == SILC_ROUTER &&
+ sock->type == SILC_SOCKET_TYPE_SERVER &&
+ !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
+ SILC_LOG_DEBUG(("Broadcasting received New ID packet"));
+ silc_server_packet_send(server, server->router->connection,
+ packet->type,
+ packet->flags | SILC_PACKET_FLAG_BROADCAST,
+ buffer->data, buffer->len, FALSE);
+ silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
+ packet->type, packet->flags,
+ packet->buffer->data, packet->buffer->len,
+ FALSE, TRUE);
+ }
+
+ out:
+ silc_id_payload_free(idp);
+}
+
+
+/* Processes incoming New ID packet. New ID Payload is used to distribute
+ information about newly registered clients and servers. */
+
+void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ silc_server_new_id_real(server, sock, packet, TRUE);
+}
+
+/* Receoved New Id List packet, list of New ID payloads inside one
+ packet. Process the New ID payloads one by one. */
+
+void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcPacketContext *new_id;
+ SilcBuffer idp;
+ uint16 id_len;
+
+ SILC_LOG_DEBUG(("Processing New ID List"));
+
+ if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+ packet->src_id_type != SILC_ID_SERVER)
+ return;
+
+ /* If the sender of this packet is server and we are router we need to
+ broadcast this packet to other routers in the network. Broadcast
+ this list packet instead of multiple New ID packets. */
+ if (!server->standalone && server->server_type == SILC_ROUTER &&
+ sock->type == SILC_SOCKET_TYPE_SERVER &&
+ !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
+ SILC_LOG_DEBUG(("Broadcasting received New ID List packet"));
+ silc_server_packet_send(server, server->router->connection,
+ packet->type,
+ packet->flags | SILC_PACKET_FLAG_BROADCAST,
+ packet->buffer->data, packet->buffer->len, FALSE);
+ silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
+ packet->type, packet->flags,
+ packet->buffer->data, packet->buffer->len,
+ FALSE, TRUE);
+ }
+
+ /* Make copy of the original packet context, except for the actual
+ data buffer, which we will here now fetch from the original buffer. */
+ new_id = silc_packet_context_alloc();
+ new_id->type = SILC_PACKET_NEW_ID;
+ new_id->flags = packet->flags;
+ new_id->src_id = packet->src_id;
+ new_id->src_id_len = packet->src_id_len;
+ new_id->src_id_type = packet->src_id_type;
+ new_id->dst_id = packet->dst_id;
+ new_id->dst_id_len = packet->dst_id_len;
+ new_id->dst_id_type = packet->dst_id_type;
+
+ idp = silc_buffer_alloc(256);
+ new_id->buffer = idp;
+
+ while (packet->buffer->len) {
+ SILC_GET16_MSB(id_len, packet->buffer->data + 2);
+ if ((id_len > packet->buffer->len) ||
+ (id_len > idp->truelen))
+ break;
+
+ silc_buffer_pull_tail(idp, 4 + id_len);
+ silc_buffer_put(idp, packet->buffer->data, 4 + id_len);
+
+ /* Process the New ID */
+ silc_server_new_id_real(server, sock, new_id, FALSE);
+
+ silc_buffer_push_tail(idp, 4 + id_len);
+ silc_buffer_pull(packet->buffer, 4 + id_len);
+ }
+
+ silc_buffer_free(idp);
+ silc_free(new_id);
+}
+
+/* Received New Channel packet. Information about new channels in the
+ network are distributed using this packet. Save the information about
+ the new channel. This usually comes from router but also normal server
+ can send this to notify channels it has when it connects to us. */
+
+void silc_server_new_channel(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcChannelPayload payload;
+ SilcChannelID *channel_id;
+ char *channel_name;
+ uint32 name_len;
+ unsigned char *id;
+ uint32 id_len;
+ uint32 mode;
+ SilcServerEntry server_entry;
+ SilcChannelEntry channel;
+
+ SILC_LOG_DEBUG(("Processing New Channel"));
+
+ if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+ packet->src_id_type != SILC_ID_SERVER ||
+ server->server_type == SILC_SERVER)
+ return;
+
+ /* Parse the channel payload */
+ payload = silc_channel_payload_parse(packet->buffer->data,
+ packet->buffer->len);
+ if (!payload)
+ return;
+
+ /* Get the channel ID */
+ channel_id = silc_channel_get_id_parse(payload);
+ if (!channel_id) {
+ silc_channel_payload_free(payload);
+ return;
+ }
+
+ channel_name = silc_channel_get_name(payload, &name_len);
+ if (name_len > 256)
+ channel_name[255] = '\0';
+
+ id = silc_channel_get_id(payload, &id_len);
+
+ server_entry = (SilcServerEntry)sock->user_data;
+
+ if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ /* Add the channel to global list as it is coming from router. It
+ cannot be our own channel as it is coming from router. */
+
+ /* Check that we don't already have this channel */
+ channel = silc_idlist_find_channel_by_name(server->local_list,
+ channel_name, NULL);
+ if (!channel)
+ channel = silc_idlist_find_channel_by_name(server->global_list,
+ channel_name, NULL);
+ if (!channel) {
+ SILC_LOG_DEBUG(("New channel id(%s) from [Router] %s",
+ silc_id_render(channel_id, SILC_ID_CHANNEL),
+ sock->hostname));
+
+ silc_idlist_add_channel(server->global_list, strdup(channel_name),
+ 0, channel_id, sock->user_data, NULL, NULL, 0);
+ server->stat.channels++;
+ }
+ } else {
+ /* The channel is coming from our server, thus it is in our cell
+ we will add it to our local list. */
+ SilcBuffer chk;
+
+ SILC_LOG_DEBUG(("Channel id(%s) from [Server] %s",
+ silc_id_render(channel_id, SILC_ID_CHANNEL),
+ sock->hostname));
+
+ /* Check that we don't already have this channel */
+ channel = silc_idlist_find_channel_by_name(server->local_list,
+ channel_name, NULL);
+ if (!channel)
+ channel = silc_idlist_find_channel_by_name(server->global_list,
+ channel_name, NULL);
+
+ /* If the channel does not exist, then create it. This creates a new
+ key to the channel as well that we will send to the server. */
+ if (!channel) {
+ /* The protocol says that the Channel ID's IP address must be based
+ on the router's IP address. Check whether the ID is based in our
+ IP and if it is not then create a new ID and enforce the server
+ to switch the ID. */
+ if (server_entry->server_type != SILC_BACKUP_ROUTER &&
+ !SILC_ID_COMPARE(channel_id, server->id, server->id->ip.data_len)) {
+ SilcChannelID *tmp;
+ SILC_LOG_DEBUG(("Forcing the server to change Channel ID"));
+
+ if (silc_id_create_channel_id(server, server->id, server->rng, &tmp)) {
+ silc_server_send_notify_channel_change(server, sock, FALSE,
+ channel_id, tmp);
+ silc_free(channel_id);
+ channel_id = tmp;
+ }
+ }
+
+ /* Create the channel with the provided Channel ID */
+ channel = silc_server_create_new_channel_with_id(server, NULL, NULL,
+ channel_name,
+ channel_id, FALSE);
+ if (!channel) {
+ silc_channel_payload_free(payload);
+ silc_free(channel_id);
+ return;
+ }
+
+ /* Get the mode and set it to the channel */
+ channel->mode = silc_channel_get_mode(payload);
+
+ /* Send the new channel key to the server */
+ id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+ id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
+ chk = silc_channel_key_payload_encode(id_len, id,
+ strlen(channel->channel_key->
+ cipher->name),
+ channel->channel_key->cipher->name,
+ channel->key_len / 8,
+ channel->key);
+ silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
+ chk->data, chk->len, FALSE);
+ silc_buffer_free(chk);
+
+ } else {
+ /* The channel exist by that name, check whether the ID's match.
+ If they don't then we'll force the server to use the ID we have.
+ We also create a new key for the channel. */
+ SilcBuffer users = NULL, users_modes = NULL;
+
+ if (!SILC_ID_CHANNEL_COMPARE(channel_id, channel->id)) {
+ /* They don't match, send CHANNEL_CHANGE notify to the server to
+ force the ID change. */
+ SILC_LOG_DEBUG(("Forcing the server to change Channel ID"));
+ silc_server_send_notify_channel_change(server, sock, FALSE,
+ channel_id, channel->id);
+ }
+
+ /* If the mode is different from what we have then enforce the
+ mode change. */
+ mode = silc_channel_get_mode(payload);
+ if (channel->mode != mode) {
+ SILC_LOG_DEBUG(("Forcing the server to change channel mode"));
+ silc_server_send_notify_cmode(server, sock, FALSE, channel,
+ channel->mode, server->id,
+ SILC_ID_SERVER,
+ channel->cipher, channel->hmac_name,
+ channel->passphrase);
+ }
+
+ /* Create new key for the channel and send it to the server and
+ everybody else possibly on the channel. */
+
+ if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
+ if (!silc_server_create_channel_key(server, channel, 0))
+ return;
+
+ /* Send to the channel */
+ silc_server_send_channel_key(server, sock, channel, FALSE);
+ id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+ id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
+
+ /* Send to the server */
+ chk = silc_channel_key_payload_encode(id_len, id,
+ strlen(channel->channel_key->
+ cipher->name),
+ channel->channel_key->
+ cipher->name,
+ channel->key_len / 8,
+ channel->key);
+ silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
+ chk->data, chk->len, FALSE);
+ silc_buffer_free(chk);
+ silc_free(id);
+ }
+
+ silc_free(channel_id);
+
+ /* Since the channel is coming from server and we also know about it
+ then send the JOIN notify to the server so that it see's our
+ users on the channel "joining" the channel. */
+ silc_server_announce_get_channel_users(server, channel, &users,
+ &users_modes);
+ if (users) {
+ silc_buffer_push(users, users->data - users->head);
+ silc_server_packet_send(server, sock,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ users->data, users->len, FALSE);
+ silc_buffer_free(users);
+ }
+ if (users_modes) {
+ silc_buffer_push(users_modes, users_modes->data - users_modes->head);
+ silc_server_packet_send_dest(server, sock,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ channel->id, SILC_ID_CHANNEL,
+ users_modes->data,
+ users_modes->len, FALSE);
+ silc_buffer_free(users_modes);
+ }
+ }
+ }
+
+ silc_channel_payload_free(payload);
+}
+
+/* Received New Channel List packet, list of New Channel List payloads inside
+ one packet. Process the New Channel payloads one by one. */
+
+void silc_server_new_channel_list(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcPacketContext *new;
+ SilcBuffer buffer;
+ uint16 len1, len2;
+
+ SILC_LOG_DEBUG(("Processing New Channel List"));
+
+ if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+ packet->src_id_type != SILC_ID_SERVER ||
+ server->server_type == SILC_SERVER)
+ return;
+
+ /* If the sender of this packet is server and we are router we need to
+ broadcast this packet to other routers in the network. Broadcast
+ this list packet instead of multiple New Channel packets. */
+ if (!server->standalone && server->server_type == SILC_ROUTER &&
+ sock->type == SILC_SOCKET_TYPE_SERVER &&
+ !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
+ SILC_LOG_DEBUG(("Broadcasting received New Channel List packet"));
+ silc_server_packet_send(server, server->router->connection,
+ packet->type,
+ packet->flags | SILC_PACKET_FLAG_BROADCAST,
+ packet->buffer->data, packet->buffer->len, FALSE);
+ silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
+ packet->type, packet->flags,
+ packet->buffer->data, packet->buffer->len,
+ FALSE, TRUE);
+ }
+
+ /* Make copy of the original packet context, except for the actual
+ data buffer, which we will here now fetch from the original buffer. */
+ new = silc_packet_context_alloc();
+ new->type = SILC_PACKET_NEW_CHANNEL;
+ new->flags = packet->flags;
+ new->src_id = packet->src_id;
+ new->src_id_len = packet->src_id_len;
+ new->src_id_type = packet->src_id_type;
+ new->dst_id = packet->dst_id;
+ new->dst_id_len = packet->dst_id_len;
+ new->dst_id_type = packet->dst_id_type;
+
+ buffer = silc_buffer_alloc(512);
+ new->buffer = buffer;
+
+ while (packet->buffer->len) {
+ SILC_GET16_MSB(len1, packet->buffer->data);
+ if ((len1 > packet->buffer->len) ||
+ (len1 > buffer->truelen))
+ break;
+
+ SILC_GET16_MSB(len2, packet->buffer->data + 2 + len1);
+ if ((len2 > packet->buffer->len) ||
+ (len2 > buffer->truelen))
+ break;
+
+ silc_buffer_pull_tail(buffer, 8 + len1 + len2);
+ silc_buffer_put(buffer, packet->buffer->data, 8 + len1 + len2);
+
+ /* Process the New Channel */
+ silc_server_new_channel(server, sock, new);
+
+ silc_buffer_push_tail(buffer, 8 + len1 + len2);
+ silc_buffer_pull(packet->buffer, 8 + len1 + len2);
+ }
+
+ silc_buffer_free(buffer);
+ silc_free(new);
+}
+
+/* Received key agreement packet. This packet is never for us. It is to
+ the client in the packet's destination ID. Sending of this sort of packet
+ equals sending private message, ie. it is sent point to point from
+ one client to another. */
+
+void silc_server_key_agreement(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcSocketConnection dst_sock;
+ SilcIDListData idata;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (packet->src_id_type != SILC_ID_CLIENT ||
+ packet->dst_id_type != SILC_ID_CLIENT)
+ return;
+
+ if (!packet->dst_id)
+ return;
+
+ /* Get the route to the client */
+ dst_sock = silc_server_get_client_route(server, packet->dst_id,
+ packet->dst_id_len, NULL, &idata);
+ if (!dst_sock)
+ return;
+
+ /* Relay the packet */
+ silc_server_relay_packet(server, dst_sock, idata->send_key,
+ idata->hmac_send, idata->psn_send++,
+ packet, FALSE);
+}
+
+/* Received connection auth request packet that is used during connection
+ phase to resolve the mandatory authentication method. This packet can
+ actually be received at anytime but usually it is used only during
+ the connection authentication phase. Now, protocol says that this packet
+ can come from client or server, however, we support only this coming
+ from client and expect that server always knows what authentication
+ method to use. */
+
+void silc_server_connection_auth_request(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
- client = silc_server_config_find_client_conn(server->config,
++ SilcServerConfigSectionClient *client = NULL;
+ uint16 conn_type;
+ int ret, port;
+ SilcAuthMethod auth_meth;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (packet->src_id_type && packet->src_id_type != SILC_ID_CLIENT)
+ return;
+
+ /* Parse the payload */
+ ret = silc_buffer_unformat(packet->buffer,
+ SILC_STR_UI_SHORT(&conn_type),
+ SILC_STR_UI_SHORT(NULL),
+ SILC_STR_END);
+ if (ret == -1)
+ return;
+
+ if (conn_type != SILC_SOCKET_TYPE_CLIENT)
+ return;
+
+ /* Get the authentication method for the client */
+ auth_meth = SILC_AUTH_NONE;
+ port = server->sockets[server->sock]->port; /* Listenning port */
- client = silc_server_config_find_client_conn(server->config,
++ client = silc_server_config_find_client(server->config,
+ sock->ip,
+ port);
+ if (!client)
++ client = silc_server_config_find_client(server->config,
+ sock->hostname,
+ port);
+ if (client)
+ auth_meth = client->auth_meth;
+
+ /* Send it back to the client */
+ silc_server_send_connection_auth_request(server, sock,
+ conn_type,
+ auth_meth);
+}
+
+/* Received REKEY packet. The sender of the packet wants to regenerate
+ its session keys. This starts the REKEY protocol. */
+
+void silc_server_rekey(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcProtocol protocol;
+ SilcServerRekeyInternalContext *proto_ctx;
+ SilcIDListData idata = (SilcIDListData)sock->user_data;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Allocate internal protocol context. This is sent as context
+ to the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->server = (void *)server;
+ proto_ctx->sock = sock;
+ proto_ctx->responder = TRUE;
+ proto_ctx->pfs = idata->rekey->pfs;
+
+ /* Perform rekey protocol. Will call the final callback after the
+ protocol is over. */
+ silc_protocol_alloc(SILC_PROTOCOL_SERVER_REKEY,
+ &protocol, proto_ctx, silc_server_rekey_final);
+ sock->protocol = protocol;
+
+ if (proto_ctx->pfs == FALSE)
+ /* Run the protocol */
+ silc_protocol_execute(protocol, server->schedule, 0, 0);
+}
+
+/* Received file transger packet. This packet is never for us. It is to
+ the client in the packet's destination ID. Sending of this sort of packet
+ equals sending private message, ie. it is sent point to point from
+ one client to another. */
+
+void silc_server_ftp(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcSocketConnection dst_sock;
+ SilcIDListData idata;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (packet->src_id_type != SILC_ID_CLIENT ||
+ packet->dst_id_type != SILC_ID_CLIENT)
+ return;
+
+ if (!packet->dst_id)
+ return;
+
+ /* Get the route to the client */
+ dst_sock = silc_server_get_client_route(server, packet->dst_id,
+ packet->dst_id_len, NULL, &idata);
+ if (!dst_sock)
+ return;
+
+ /* Relay the packet */
+ silc_server_relay_packet(server, dst_sock, idata->send_key,
+ idata->hmac_send, idata->psn_send++,
+ packet, FALSE);
+}
--- /dev/null
- char *motd;
+/*
+
+ packet_send.c
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 1997 - 2001 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; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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.
+
+*/
+/*
+ * Server packet routines to send packets.
+ */
+/* $Id$ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+
+/* Routine that sends packet or marks packet to be sent. This is used
+ directly only in special cases. Normal cases should use
+ silc_server_packet_send. Returns < 0 error. */
+
+int silc_server_packet_send_real(SilcServer server,
+ SilcSocketConnection sock,
+ bool force_send)
+{
+ int ret;
+
+ /* If disconnecting, ignore the data */
+ if (SILC_IS_DISCONNECTING(sock))
+ return -1;
+
+ /* If rekey protocol is active we must assure that all packets are
+ sent through packet queue. */
+ if (SILC_SERVER_IS_REKEY(sock))
+ force_send = FALSE;
+
+ /* If outbound data is already pending do not force send */
+ if (SILC_IS_OUTBUF_PENDING(sock))
+ force_send = FALSE;
+
+ /* Send the packet */
+ ret = silc_packet_send(sock, force_send);
+ if (ret != -2)
+ return ret;
+
+ /* Mark that there is some outgoing data available for this connection.
+ This call sets the connection both for input and output (the input
+ is set always and this call keeps the input setting, actually).
+ Actual data sending is performed by silc_server_packet_process. */
+ SILC_SET_CONNECTION_FOR_OUTPUT(server->schedule, sock->sock);
+
+ /* Mark to socket that data is pending in outgoing buffer. This flag
+ is needed if new data is added to the buffer before the earlier
+ put data is sent to the network. */
+ SILC_SET_OUTBUF_PENDING(sock);
+
+ return 0;
+}
+
+/* Assembles a new packet to be sent out to network. This doesn't actually
+ send the packet but creates the packet and fills the outgoing data
+ buffer and marks the packet ready to be sent to network. However, If
+ argument force_send is TRUE the packet is sent immediately and not put
+ to queue. Normal case is that the packet is not sent immediately. */
+
+void silc_server_packet_send(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ unsigned char *data,
+ uint32 data_len,
+ bool force_send)
+{
+ void *dst_id = NULL;
+ SilcIdType dst_id_type = SILC_ID_NONE;
+ SilcIDListData idata = (SilcIDListData)sock->user_data;
+
+ if (!sock)
+ return;
+
+ /* If disconnecting, ignore the data */
+ if (SILC_IS_DISCONNECTING(sock))
+ return;
+
+ /* If entry is disabled do not sent anything. */
+ if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED)
+ return;
+
+ /* Get data used in the packet sending, keys and stuff */
+ switch(sock->type) {
+ case SILC_SOCKET_TYPE_CLIENT:
+ if (sock->user_data) {
+ dst_id = ((SilcClientEntry)sock->user_data)->id;
+ dst_id_type = SILC_ID_CLIENT;
+ }
+ break;
+ case SILC_SOCKET_TYPE_SERVER:
+ case SILC_SOCKET_TYPE_ROUTER:
+ if (sock->user_data) {
+ dst_id = ((SilcServerEntry)sock->user_data)->id;
+ dst_id_type = SILC_ID_SERVER;
+ }
+ break;
+ default:
+ break;
+ }
+
+ silc_server_packet_send_dest(server, sock, type, flags, dst_id,
+ dst_id_type, data, data_len, force_send);
+}
+
+/* Assembles a new packet to be sent out to network. This doesn't actually
+ send the packet but creates the packet and fills the outgoing data
+ buffer and marks the packet ready to be sent to network. However, If
+ argument force_send is TRUE the packet is sent immediately and not put
+ to queue. Normal case is that the packet is not sent immediately.
+ Destination information is sent as argument for this function. */
+
+void silc_server_packet_send_dest(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ void *dst_id,
+ SilcIdType dst_id_type,
+ unsigned char *data,
+ uint32 data_len,
+ bool force_send)
+{
+ SilcPacketContext packetdata;
+ SilcIDListData idata = (SilcIDListData)sock->user_data;
+ SilcCipher cipher = NULL;
+ SilcHmac hmac = NULL;
+ uint32 sequence = 0;
+ unsigned char *dst_id_data = NULL;
+ uint32 dst_id_len = 0;
+ int block_len = 0;
+
+ /* If disconnecting, ignore the data */
+ if (SILC_IS_DISCONNECTING(sock))
+ return;
+
+ /* If entry is disabled do not sent anything. */
+ if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED)
+ return;
+
+ SILC_LOG_DEBUG(("Sending packet, type %d", type));
+
+ if (dst_id) {
+ dst_id_data = silc_id_id2str(dst_id, dst_id_type);
+ dst_id_len = silc_id_get_len(dst_id, dst_id_type);
+ }
+
+ if (idata) {
+ cipher = idata->send_key;
+ hmac = idata->hmac_send;
+ sequence = idata->psn_send++;
+ block_len = silc_cipher_get_block_len(cipher);
+ }
+
+ /* Set the packet context pointers */
+ packetdata.type = type;
+ packetdata.flags = flags;
+ packetdata.src_id = silc_id_id2str(server->id, server->id_type);
+ packetdata.src_id_len = silc_id_get_len(server->id, server->id_type);
+ packetdata.src_id_type = server->id_type;
+ packetdata.dst_id = dst_id_data;
+ packetdata.dst_id_len = dst_id_len;
+ packetdata.dst_id_type = dst_id_type;
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + dst_id_len;
+ packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
+
+ /* Prepare outgoing data buffer for packet sending */
+ silc_packet_send_prepare(sock,
+ SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len,
+ packetdata.padlen,
+ data_len);
+
+ SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
+
+ packetdata.buffer = sock->outbuf;
+
+ /* Put the data to the buffer */
+ if (data && data_len)
+ silc_buffer_put(sock->outbuf, data, data_len);
+
+ /* Create the outgoing packet */
+ silc_packet_assemble(&packetdata, cipher);
+
+ /* Encrypt the packet */
+ silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, sock->outbuf->len);
+
+ SILC_LOG_HEXDUMP(("Outgoing packet (%d), len %d", sequence,
+ sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_server_packet_send_real(server, sock, force_send);
+
+ if (packetdata.src_id)
+ silc_free(packetdata.src_id);
+ if (packetdata.dst_id)
+ silc_free(packetdata.dst_id);
+}
+
+/* Assembles a new packet to be sent out to network. This doesn't actually
+ send the packet but creates the packet and fills the outgoing data
+ buffer and marks the packet ready to be sent to network. However, If
+ argument force_send is TRUE the packet is sent immediately and not put
+ to queue. Normal case is that the packet is not sent immediately.
+ The source and destination information is sent as argument for this
+ function. */
+
+void silc_server_packet_send_srcdest(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ void *src_id,
+ SilcIdType src_id_type,
+ void *dst_id,
+ SilcIdType dst_id_type,
+ unsigned char *data,
+ uint32 data_len,
+ bool force_send)
+{
+ SilcPacketContext packetdata;
+ SilcIDListData idata;
+ SilcCipher cipher = NULL;
+ SilcHmac hmac = NULL;
+ uint32 sequence = 0;
+ unsigned char *dst_id_data = NULL;
+ uint32 dst_id_len = 0;
+ unsigned char *src_id_data = NULL;
+ uint32 src_id_len = 0;
+ int block_len = 0;
+
+ SILC_LOG_DEBUG(("Sending packet, type %d", type));
+
+ /* Get data used in the packet sending, keys and stuff */
+ idata = (SilcIDListData)sock->user_data;
+
+ if (dst_id) {
+ dst_id_data = silc_id_id2str(dst_id, dst_id_type);
+ dst_id_len = silc_id_get_len(dst_id, dst_id_type);
+ }
+
+ if (src_id) {
+ src_id_data = silc_id_id2str(src_id, src_id_type);
+ src_id_len = silc_id_get_len(src_id, src_id_type);
+ }
+
+ if (idata) {
+ cipher = idata->send_key;
+ hmac = idata->hmac_send;
+ sequence = idata->psn_send++;
+ block_len = silc_cipher_get_block_len(cipher);
+ }
+
+ /* Set the packet context pointers */
+ packetdata.type = type;
+ packetdata.flags = flags;
+ packetdata.src_id = src_id_data;
+ packetdata.src_id_len = src_id_len;
+ packetdata.src_id_type = src_id_type;
+ packetdata.dst_id = dst_id_data;
+ packetdata.dst_id_len = dst_id_len;
+ packetdata.dst_id_type = dst_id_type;
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + dst_id_len;
+ packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
+
+ /* Prepare outgoing data buffer for packet sending */
+ silc_packet_send_prepare(sock,
+ SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len,
+ packetdata.padlen,
+ data_len);
+
+ SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
+
+ packetdata.buffer = sock->outbuf;
+
+ /* Put the data to the buffer */
+ if (data && data_len)
+ silc_buffer_put(sock->outbuf, data, data_len);
+
+ /* Create the outgoing packet */
+ silc_packet_assemble(&packetdata, cipher);
+
+ /* Encrypt the packet */
+ silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, sock->outbuf->len);
+
+ SILC_LOG_HEXDUMP(("Outgoing packet (%d), len %d", sequence,
+ sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_server_packet_send_real(server, sock, force_send);
+
+ if (packetdata.src_id)
+ silc_free(packetdata.src_id);
+ if (packetdata.dst_id)
+ silc_free(packetdata.dst_id);
+}
+
+/* Broadcast received packet to our primary route. This function is used
+ by router to further route received broadcast packet. It is expected
+ that the broadcast flag from the packet is checked before calling this
+ function. This does not test or set the broadcast flag. */
+
+void silc_server_packet_broadcast(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcIDListData idata;
+ void *id;
+
+ SILC_LOG_DEBUG(("Broadcasting received broadcast packet"));
+
+ /* If the packet is originated from our primary route we are
+ not allowed to send the packet. */
+ id = silc_id_str2id(packet->src_id, packet->src_id_len, packet->src_id_type);
+ if (id && !SILC_ID_SERVER_COMPARE(id, server->router->id)) {
+ idata = (SilcIDListData)sock->user_data;
+
+ silc_buffer_push(buffer, buffer->data - buffer->head);
+ silc_packet_send_prepare(sock, 0, 0, buffer->len);
+ silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
+ silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
+ sock->outbuf, sock->outbuf->len);
+
+ SILC_LOG_HEXDUMP(("Broadcasted packet (%d), len %d", idata->psn_send - 1,
+ sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_server_packet_send_real(server, sock, TRUE);
+ silc_free(id);
+ return;
+ }
+
+ SILC_LOG_DEBUG(("Will not broadcast to primary route since it is the "
+ "original sender of this packet"));
+ silc_free(id);
+}
+
+/* Routes received packet to `sock'. This is used to route the packets that
+ router receives but are not destined to it. */
+
+void silc_server_packet_route(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcIDListData idata;
+
+ SILC_LOG_DEBUG(("Routing received packet"));
+
+ idata = (SilcIDListData)sock->user_data;
+
+ silc_buffer_push(buffer, buffer->data - buffer->head);
+ silc_packet_send_prepare(sock, 0, 0, buffer->len);
+ silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
+ silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
+ sock->outbuf, sock->outbuf->len);
+
+ SILC_LOG_HEXDUMP(("Routed packet (%d), len %d", idata->psn_send - 1,
+ sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_server_packet_send_real(server, sock, TRUE);
+}
+
+/* This routine can be used to send a packet to table of clients provided
+ in `clients'. If `route' is FALSE the packet is routed only to local
+ clients (for server locally connected, and for router local cell). */
+
+void silc_server_packet_send_clients(SilcServer server,
+ SilcClientEntry *clients,
+ uint32 clients_count,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ bool route,
+ unsigned char *data,
+ uint32 data_len,
+ bool force_send)
+{
+ SilcSocketConnection sock = NULL;
+ SilcClientEntry client = NULL;
+ SilcServerEntry *routed = NULL;
+ uint32 routed_count = 0;
+ bool gone = FALSE;
+ int i, k;
+
+ SILC_LOG_DEBUG(("Sending packet to list of clients"));
+
+ /* Send to all clients in table */
+ for (i = 0; i < clients_count; i++) {
+ client = clients[i];
+
+ /* If client has router set it is not locally connected client and
+ we will route the message to the router set in the client. Though,
+ send locally connected server in all cases. */
+ if (server->server_type == SILC_ROUTER && client->router &&
+ ((!route && client->router->router == server->id_entry) || route)) {
+
+ /* Check if we have sent the packet to this route already */
+ for (k = 0; k < routed_count; k++)
+ if (routed[k] == client->router)
+ break;
+ if (k < routed_count)
+ continue;
+
+ /* Route only once to router */
+ sock = (SilcSocketConnection)client->router->connection;
+ if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ if (gone)
+ continue;
+ gone = TRUE;
+ }
+
+ /* Send the packet */
+ silc_server_packet_send_dest(server, sock, type, flags,
+ client->router->id, SILC_ID_SERVER,
+ data, data_len, force_send);
+
+ /* Mark this route routed already */
+ routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1));
+ routed[routed_count++] = client->router;
+ continue;
+ }
+
+ if (client->router)
+ continue;
+
+ /* Send to locally connected client */
+ sock = (SilcSocketConnection)client->connection;
+ silc_server_packet_send_dest(server, sock, type, flags,
+ client->id, SILC_ID_CLIENT,
+ data, data_len, force_send);
+ }
+
+ silc_free(routed);
+}
+
+/* Internal routine to actually create the channel packet and send it
+ to network. This is common function in channel message sending. If
+ `channel_message' is TRUE this encrypts the message as it is strictly
+ a channel message. If FALSE normal encryption process is used. */
+
+static void
+silc_server_packet_send_to_channel_real(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet,
+ SilcCipher cipher,
+ SilcHmac hmac,
+ uint32 sequence,
+ unsigned char *data,
+ uint32 data_len,
+ bool channel_message,
+ bool force_send)
+{
+ int block_len;
+
+ if (!sock)
+ return;
+
+ packet->truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packet->src_id_len + packet->dst_id_len;
+
+ block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
+ if (channel_message)
+ packet->padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+ packet->src_id_len +
+ packet->dst_id_len), block_len);
+ else
+ packet->padlen = SILC_PACKET_PADLEN(packet->truelen, block_len);
+
+ /* Prepare outgoing data buffer for packet sending */
+ silc_packet_send_prepare(sock,
+ SILC_PACKET_HEADER_LEN +
+ packet->src_id_len +
+ packet->dst_id_len,
+ packet->padlen,
+ data_len);
+
+ packet->buffer = sock->outbuf;
+
+ /* Put the data to buffer, assemble and encrypt the packet. The packet
+ is encrypted with normal session key shared with the client, unless
+ the `channel_message' is TRUE. */
+ silc_buffer_put(sock->outbuf, data, data_len);
+ silc_packet_assemble(packet, cipher);
+ if (channel_message)
+ silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf,
+ SILC_PACKET_HEADER_LEN + packet->src_id_len +
+ packet->dst_id_len + packet->padlen);
+ else
+ silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf,
+ sock->outbuf->len);
+
+ SILC_LOG_HEXDUMP(("Channel packet (%d), len %d", sequence,
+ sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_server_packet_send_real(server, sock, force_send);
+}
+
+/* This routine is used by the server to send packets to channel. The
+ packet sent with this function is distributed to all clients on
+ the channel. Usually this is used to send notify messages to the
+ channel, things like notify about new user joining to the channel.
+ If `route' is FALSE then the packet is sent only locally and will not
+ be routed anywhere (for router locally means cell wide). If `sender'
+ is provided then the packet is not sent to that connection since it
+ originally came from it. If `send_to_clients' is FALSE then the
+ packet is not sent clients, only servers. */
+
+void silc_server_packet_send_to_channel(SilcServer server,
+ SilcSocketConnection sender,
+ SilcChannelEntry channel,
+ SilcPacketType type,
+ bool route,
+ unsigned char *data,
+ uint32 data_len,
+ bool force_send)
+{
+ SilcSocketConnection sock = NULL;
+ SilcPacketContext packetdata;
+ SilcClientEntry client = NULL;
+ SilcServerEntry *routed = NULL;
+ SilcChannelClientEntry chl;
+ SilcHashTableList htl;
+ SilcIDListData idata;
+ uint32 routed_count = 0;
+ bool gone = FALSE;
+ int k;
+
+ /* This doesn't send channel message packets */
+ assert(type != SILC_PACKET_CHANNEL_MESSAGE);
+
+ SILC_LOG_DEBUG(("Sending packet to channel"));
+
+ /* Set the packet context pointers. */
+ packetdata.flags = 0;
+ packetdata.type = type;
+ packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
+ packetdata.src_id_len = silc_id_get_len(server->id, SILC_ID_SERVER);
+ packetdata.src_id_type = SILC_ID_SERVER;
+ packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+ packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
+ packetdata.dst_id_type = SILC_ID_CHANNEL;
+
+ /* If there are global users in the channel we will send the message
+ first to our router for further routing. */
+ if (route && server->server_type != SILC_ROUTER && !server->standalone &&
+ channel->global_users) {
+ SilcServerEntry router;
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ router = server->router;
+ sock = (SilcSocketConnection)router->connection;
+ idata = (SilcIDListData)router;
+
+ if (sock != sender) {
+ SILC_LOG_DEBUG(("Sending packet to router for routing"));
+
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ idata->send_key,
+ idata->hmac_send,
+ idata->psn_send++,
+ data, data_len, FALSE,
+ force_send);
+ }
+ }
+
+ routed = silc_calloc(silc_hash_table_count(channel->user_list),
+ sizeof(*routed));
+
+ /* Send the message to clients on the channel's client list. */
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+ client = chl->client;
+ if (!client)
+ continue;
+
+ /* If client has router set it is not locally connected client and
+ we will route the message to the router set in the client. Though,
+ send locally connected server in all cases. */
+ if (server->server_type == SILC_ROUTER && client->router &&
+ ((!route && client->router->router == server->id_entry) || route)) {
+
+ /* Check if we have sent the packet to this route already */
+ for (k = 0; k < routed_count; k++)
+ if (routed[k] == client->router)
+ break;
+ if (k < routed_count)
+ continue;
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)client->router->connection;
+ idata = (SilcIDListData)client->router;
+
+ if (sender && sock == sender)
+ continue;
+
+ /* Route only once to router */
+ if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ if (gone)
+ continue;
+ gone = TRUE;
+ }
+
+ /* Send the packet */
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ idata->send_key,
+ idata->hmac_send,
+ idata->psn_send++,
+ data, data_len, FALSE,
+ force_send);
+
+ /* Mark this route routed already */
+ routed[routed_count++] = client->router;
+ continue;
+ }
+
+ if (client->router)
+ continue;
+
+ /* Send to locally connected client */
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)client->connection;
+ idata = (SilcIDListData)client;
+
+ if (sender && sock == sender)
+ continue;
+
+ /* Send the packet */
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ idata->send_key,
+ idata->hmac_send,
+ idata->psn_send++,
+ data, data_len, FALSE,
+ force_send);
+ }
+
+ silc_hash_table_list_reset(&htl);
+ silc_free(routed);
+ silc_free(packetdata.src_id);
+ silc_free(packetdata.dst_id);
+}
+
+/* This checks whether the relayed packet came from router. If it did
+ then we'll need to encrypt it with the channel key. This is called
+ from the silc_server_packet_relay_to_channel. */
+
+static bool
+silc_server_packet_relay_to_channel_encrypt(SilcServer server,
+ SilcSocketConnection sock,
+ SilcChannelEntry channel,
+ unsigned char *data,
+ unsigned int data_len)
+{
+ /* If we are router and the packet came from router and private key
+ has not been set for the channel then we must encrypt the packet
+ as it was decrypted with the session key shared between us and the
+ router which sent it. This is so, because cells does not share the
+ same channel key. */
+ if (server->server_type == SILC_ROUTER &&
+ sock->type == SILC_SOCKET_TYPE_ROUTER &&
+ !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY) &&
+ channel->channel_key) {
+ SilcBuffer chp;
+ uint32 iv_len, i;
+ uint16 dlen, flags;
+
+ iv_len = silc_cipher_get_block_len(channel->channel_key);
+ if (channel->iv[0] == '\0')
+ for (i = 0; i < iv_len; i++) channel->iv[i] =
+ silc_rng_get_byte(server->rng);
+ else
+ silc_hash_make(server->md5hash, channel->iv, iv_len, channel->iv);
+
+ /* Encode new payload. This encrypts it also. */
+ SILC_GET16_MSB(flags, data);
+ SILC_GET16_MSB(dlen, data + 2);
+
+ if (dlen > data_len) {
+ SILC_LOG_WARNING(("Corrupted channel message, cannot relay it"));
+ return FALSE;
+ }
+
+ chp = silc_channel_message_payload_encode(flags, dlen, data + 4,
+ iv_len, channel->iv,
+ channel->channel_key,
+ channel->hmac);
+ memcpy(data, chp->data, chp->len);
+ silc_buffer_free(chp);
+ }
+
+ return TRUE;
+}
+
+/* This routine is explicitly used to relay messages to some channel.
+ Packets sent with this function we have received earlier and are
+ totally encrypted. This just sends the packet to all clients on
+ the channel. If the sender of the packet is someone on the channel
+ the message will not be sent to that client. The SILC Packet header
+ is encrypted with the session key shared between us and the client.
+ MAC is also computed before encrypting the header. Rest of the
+ packet will be untouched. */
+
+void silc_server_packet_relay_to_channel(SilcServer server,
+ SilcSocketConnection sender_sock,
+ SilcChannelEntry channel,
+ void *sender,
+ SilcIdType sender_type,
+ void *sender_entry,
+ unsigned char *data,
+ uint32 data_len,
+ bool force_send)
+{
+ bool found = FALSE;
+ SilcSocketConnection sock = NULL;
+ SilcPacketContext packetdata;
+ SilcClientEntry client = NULL;
+ SilcServerEntry *routed = NULL;
+ SilcChannelClientEntry chl;
+ uint32 routed_count = 0;
+ SilcIDListData idata;
+ SilcHashTableList htl;
+ bool gone = FALSE;
+ int k;
+
+ SILC_LOG_DEBUG(("Relaying packet to channel"));
+
+ /* This encrypts the packet, if needed. It will be encrypted if
+ it came from the router thus it needs to be encrypted with the
+ channel key. If the channel key does not exist, then we know we
+ don't have a single local user on the channel. */
+ if (!silc_server_packet_relay_to_channel_encrypt(server, sender_sock,
+ channel, data,
+ data_len))
+ return;
+
+ /* Set the packet context pointers. */
+ packetdata.flags = 0;
+ packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
+ packetdata.src_id = silc_id_id2str(sender, sender_type);
+ packetdata.src_id_len = silc_id_get_len(sender, sender_type);
+ packetdata.src_id_type = sender_type;
+ packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+ packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
+ packetdata.dst_id_type = SILC_ID_CHANNEL;
+
+ /* If there are global users in the channel we will send the message
+ first to our router for further routing. */
+ if (server->server_type != SILC_ROUTER && !server->standalone &&
+ channel->global_users) {
+ SilcServerEntry router = server->router;
+
+ /* Check that the sender is not our router. */
+ if (sender_sock != (SilcSocketConnection)router->connection) {
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)router->connection;
+ idata = (SilcIDListData)router;
+
+ SILC_LOG_DEBUG(("Sending channel message to router for routing"));
+
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ idata->send_key,
+ idata->hmac_send,
+ idata->psn_send++,
+ data, data_len, TRUE,
+ force_send);
+ }
+ }
+
+ routed = silc_calloc(silc_hash_table_count(channel->user_list),
+ sizeof(*routed));
+
+ /* Mark that to the route the original sender if from is not routed */
+ if (sender_type == SILC_ID_CLIENT) {
+ client = (SilcClientEntry)sender_entry;
+ if (client->router) {
+ routed[routed_count++] = client->router;
+ SILC_LOG_DEBUG(("************* router %s",
+ silc_id_render(client->router->id, SILC_ID_SERVER)));
+ }
+ }
+
+ /* Send the message to clients on the channel's client list. */
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+ client = chl->client;
+ if (!client)
+ continue;
+
+ /* Do not send to the sender */
+ if (!found && client == sender_entry) {
+ found = TRUE;
+ continue;
+ }
+
+ /* If the client has set router it means that it is not locally
+ connected client and we will route the packet further. */
+ if (server->server_type == SILC_ROUTER && client->router) {
+
+ /* Sender maybe server as well so we want to make sure that
+ we won't send the message to the server it came from. */
+ if (!found && SILC_ID_SERVER_COMPARE(client->router->id, sender)) {
+ found = TRUE;
+ routed[routed_count++] = client->router;
+ continue;
+ }
+
+ /* Check if we have sent the packet to this route already */
+ for (k = 0; k < routed_count; k++)
+ if (routed[k] == client->router)
+ break;
+ if (k < routed_count)
+ continue;
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)client->router->connection;
+ idata = (SilcIDListData)client->router;
+
+ /* Do not send to the sender. Check first whether the true
+ sender's router is same as this client's router. Also check
+ if the sender socket is the same as this client's router
+ socket. */
+ if (sender_entry &&
+ ((SilcClientEntry)sender_entry)->router == client->router)
+ continue;
+ if (sender_sock && sock == sender_sock)
+ continue;
+
+ SILC_LOG_DEBUG(("Relaying packet to client ID(%s) %s (%s)",
+ silc_id_render(client->id, SILC_ID_CLIENT),
+ sock->hostname, sock->ip));
+
+ /* Mark this route routed already. */
+ routed[routed_count++] = client->router;
+
+ /* If the remote connection is router then we'll decrypt the
+ channel message and re-encrypt it with the session key shared
+ between us and the remote router. This is done because the
+ channel keys are cell specific and we have different channel
+ key than the remote router has. */
+ if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ if (gone)
+ continue;
+
+ SILC_LOG_DEBUG(("Remote is router, encrypt with session key"));
+ gone = TRUE;
+
+ /* If private key mode is not set then decrypt the packet
+ and re-encrypt it */
+ if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
+ unsigned char *tmp = silc_calloc(data_len, sizeof(*data));
+ memcpy(tmp, data, data_len);
+
+ /* Decrypt the channel message (we don't check the MAC) */
+ if (channel->channel_key &&
+ !silc_channel_message_payload_decrypt(tmp, data_len,
+ channel->channel_key,
+ NULL)) {
+ memset(tmp, 0, data_len);
+ silc_free(tmp);
+ continue;
+ }
+
+ /* Now re-encrypt and send it to the router */
+ silc_server_packet_send_srcdest(server, sock,
+ SILC_PACKET_CHANNEL_MESSAGE, 0,
+ sender, sender_type,
+ channel->id, SILC_ID_CHANNEL,
+ tmp, data_len, force_send);
+
+ /* Free the copy of the channel message */
+ memset(tmp, 0, data_len);
+ silc_free(tmp);
+ } else {
+ /* Private key mode is set, we don't have the channel key, so
+ just re-encrypt the entire packet and send it to the router. */
+ silc_server_packet_send_srcdest(server, sock,
+ SILC_PACKET_CHANNEL_MESSAGE, 0,
+ sender, sender_type,
+ channel->id, SILC_ID_CHANNEL,
+ data, data_len, force_send);
+ }
+ continue;
+ }
+
+ /* Send the packet (to normal server) */
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ idata->send_key,
+ idata->hmac_send,
+ idata->psn_send++,
+ data, data_len, TRUE,
+ force_send);
+
+ continue;
+ }
+
+ if (client->router)
+ continue;
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)client->connection;
+ idata = (SilcIDListData)client;
+
+ if (sender_sock && sock == sender_sock)
+ continue;
+
+ SILC_LOG_DEBUG(("Sending packet to client ID(%s) %s (%s)",
+ silc_id_render(client->id, SILC_ID_CLIENT),
+ sock->hostname, sock->ip));
+
+ /* Send the packet */
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ idata->send_key,
+ idata->hmac_send,
+ idata->psn_send++,
+ data, data_len, TRUE,
+ force_send);
+ }
+
+ silc_hash_table_list_reset(&htl);
+ silc_free(routed);
+ silc_free(packetdata.src_id);
+ silc_free(packetdata.dst_id);
+}
+
+/* This function is used to send packets strictly to all local clients
+ on a particular channel. This is used for example to distribute new
+ channel key to all our locally connected clients on the channel.
+ The packets are always encrypted with the session key shared between
+ the client, this means these are not _to the channel_ but _to the client_
+ on the channel. */
+
+void silc_server_packet_send_local_channel(SilcServer server,
+ SilcChannelEntry channel,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ unsigned char *data,
+ uint32 data_len,
+ bool force_send)
+{
+ SilcChannelClientEntry chl;
+ SilcHashTableList htl;
+ SilcSocketConnection sock = NULL;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Send the message to clients on the channel's client list. */
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+ if (chl->client && !chl->client->router) {
+ sock = (SilcSocketConnection)chl->client->connection;
+
+ /* Send the packet to the client */
+ silc_server_packet_send_dest(server, sock, type, flags, chl->client->id,
+ SILC_ID_CLIENT, data, data_len,
+ force_send);
+ }
+ }
+ silc_hash_table_list_reset(&htl);
+}
+
+/* Routine used to send (relay, route) private messages to some destination.
+ If the private message key does not exist then the message is re-encrypted,
+ otherwise we just pass it along. This really is not used to send new
+ private messages (as server does not send them) but to relay received
+ private messages. */
+
+void silc_server_send_private_message(SilcServer server,
+ SilcSocketConnection dst_sock,
+ SilcCipher cipher,
+ SilcHmac hmac,
+ uint32 sequence,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+
+ /* Re-encrypt and send if private messge key does not exist */
+ if (!(packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY)) {
+
+ silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ + packet->dst_id_len + packet->padlen);
+ silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
+ silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+
+ /* Re-encrypt packet */
+ silc_packet_encrypt(cipher, hmac, sequence, dst_sock->outbuf, buffer->len);
+
+ /* Send the packet */
+ silc_server_packet_send_real(server, dst_sock, FALSE);
+
+ } else {
+ /* Key exist so encrypt just header and send it */
+ silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ + packet->dst_id_len + packet->padlen);
+ silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
+ silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+
+ /* Encrypt header */
+ silc_packet_encrypt(cipher, hmac, sequence, dst_sock->outbuf,
+ SILC_PACKET_HEADER_LEN + packet->src_id_len +
+ packet->dst_id_len + packet->padlen);
+
+ silc_server_packet_send_real(server, dst_sock, FALSE);
+ }
+}
+
+/* Sends current motd to client */
+
+void silc_server_send_motd(SilcServer server,
+ SilcSocketConnection sock)
+{
- if (server->config && server->config->motd &&
- server->config->motd->motd_file) {
++ char *motd, *motd_file = NULL;
+ uint32 motd_len;
+
- motd = silc_file_readfile(server->config->motd->motd_file, &motd_len);
++ if (server->config)
++ motd_file = server->config->server_info->motd_file;
+
++ if (motd_file) {
++ motd = silc_file_readfile(motd_file, &motd_len);
+ if (!motd)
+ return;
+
+ silc_server_send_notify(server, sock, FALSE, SILC_NOTIFY_TYPE_MOTD, 1,
+ motd, motd_len);
+ silc_free(motd);
+ }
+}
+
+/* Sends error message. Error messages may or may not have any
+ implications. */
+
+void silc_server_send_error(SilcServer server,
+ SilcSocketConnection sock,
+ const char *fmt, ...)
+{
+ va_list ap;
+ unsigned char buf[4096];
+
+ memset(buf, 0, sizeof(buf));
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ silc_server_packet_send(server, sock, SILC_PACKET_ERROR, 0,
+ buf, strlen(buf), FALSE);
+}
+
+/* Sends notify message. If format is TRUE the variable arguments are
+ formatted and the formatted string is sent as argument payload. If it is
+ FALSE then each argument is sent as separate argument and their format
+ in the argument list must be { argument data, argument length }. */
+
+void silc_server_send_notify(SilcServer server,
+ SilcSocketConnection sock,
+ bool broadcast,
+ SilcNotifyType type,
+ uint32 argc, ...)
+{
+ va_list ap;
+ SilcBuffer packet;
+
+ va_start(ap, argc);
+
+ packet = silc_notify_payload_encode(type, argc, ap);
+ silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY,
+ broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
+ packet->data, packet->len, FALSE);
+
+ /* Send to backup routers if this is being broadcasted to primary
+ router. */
+ if (server->router && server->router->connection &&
+ sock == server->router->connection && broadcast)
+ silc_server_backup_send(server, NULL, SILC_PACKET_NOTIFY, 0,
+ packet->data, packet->len, FALSE, TRUE);
+
+ silc_buffer_free(packet);
+ va_end(ap);
+}
+
+/* Sends notify message and gets the arguments from the `args' Argument
+ Payloads. */
+
+void silc_server_send_notify_args(SilcServer server,
+ SilcSocketConnection sock,
+ bool broadcast,
+ SilcNotifyType type,
+ uint32 argc,
+ SilcBuffer args)
+{
+ SilcBuffer packet;
+
+ packet = silc_notify_payload_encode_args(type, argc, args);
+ silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY,
+ broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+}
+
+/* Send CHANNEL_CHANGE notify type. This tells the receiver to replace the
+ `old_id' with the `new_id'. */
+
+void silc_server_send_notify_channel_change(SilcServer server,
+ SilcSocketConnection sock,
+ bool broadcast,
+ SilcChannelID *old_id,
+ SilcChannelID *new_id)
+{
+ SilcBuffer idp1, idp2;
+
+ idp1 = silc_id_payload_encode((void *)old_id, SILC_ID_CHANNEL);
+ idp2 = silc_id_payload_encode((void *)new_id, SILC_ID_CHANNEL);
+
+ silc_server_send_notify(server, sock, broadcast,
+ SILC_NOTIFY_TYPE_CHANNEL_CHANGE,
+ 2, idp1->data, idp1->len, idp2->data, idp2->len);
+ silc_buffer_free(idp1);
+ silc_buffer_free(idp2);
+}
+
+/* Send NICK_CHANGE notify type. This tells the receiver to replace the
+ `old_id' with the `new_id'. */
+
+void silc_server_send_notify_nick_change(SilcServer server,
+ SilcSocketConnection sock,
+ bool broadcast,
+ SilcClientID *old_id,
+ SilcClientID *new_id)
+{
+ SilcBuffer idp1, idp2;
+
+ idp1 = silc_id_payload_encode((void *)old_id, SILC_ID_CLIENT);
+ idp2 = silc_id_payload_encode((void *)new_id, SILC_ID_CLIENT);
+
+ silc_server_send_notify(server, sock, broadcast,
+ SILC_NOTIFY_TYPE_NICK_CHANGE,
+ 2, idp1->data, idp1->len, idp2->data, idp2->len);
+ silc_buffer_free(idp1);
+ silc_buffer_free(idp2);
+}
+
+/* Sends JOIN notify type. This tells that new client by `client_id' ID
+ has joined to the `channel'. */
+
+void silc_server_send_notify_join(SilcServer server,
+ SilcSocketConnection sock,
+ bool broadcast,
+ SilcChannelEntry channel,
+ SilcClientID *client_id)
+{
+ SilcBuffer idp1, idp2;
+
+ idp1 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ idp2 = silc_id_payload_encode((void *)channel->id, SILC_ID_CHANNEL);
+ silc_server_send_notify(server, sock, broadcast, SILC_NOTIFY_TYPE_JOIN,
+ 2, idp1->data, idp1->len,
+ idp2->data, idp2->len);
+ silc_buffer_free(idp1);
+ silc_buffer_free(idp2);
+}
+
+/* Sends LEAVE notify type. This tells that `client_id' has left the
+ `channel'. The Notify packet is always destined to the channel. */
+
+void silc_server_send_notify_leave(SilcServer server,
+ SilcSocketConnection sock,
+ bool broadcast,
+ SilcChannelEntry channel,
+ SilcClientID *client_id)
+{
+ SilcBuffer idp;
+
+ idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
+ SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_LEAVE,
+ 1, idp->data, idp->len);
+ silc_buffer_free(idp);
+}
+
+/* Sends CMODE_CHANGE notify type. This tells that `client_id' changed the
+ `channel' mode to `mode. The Notify packet is always destined to
+ the channel. */
+
+void silc_server_send_notify_cmode(SilcServer server,
+ SilcSocketConnection sock,
+ bool broadcast,
+ SilcChannelEntry channel,
+ uint32 mode_mask,
+ void *id, SilcIdType id_type,
+ char *cipher, char *hmac,
+ char *passphrase)
+{
+ SilcBuffer idp;
+ unsigned char mode[4];
+
+ idp = silc_id_payload_encode((void *)id, id_type);
+ SILC_PUT32_MSB(mode_mask, mode);
+
+ silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
+ SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_CMODE_CHANGE,
+ 5, idp->data, idp->len,
+ mode, 4,
+ cipher, cipher ? strlen(cipher) : 0,
+ hmac, hmac ? strlen(hmac) : 0,
+ passphrase, passphrase ?
+ strlen(passphrase) : 0);
+ silc_buffer_free(idp);
+}
+
+/* Sends CUMODE_CHANGE notify type. This tells that `client_id' changed the
+ `target' client's mode on `channel'. The notify packet is always
+ destined to the channel. */
+
+void silc_server_send_notify_cumode(SilcServer server,
+ SilcSocketConnection sock,
+ bool broadcast,
+ SilcChannelEntry channel,
+ uint32 mode_mask,
+ void *id, SilcIdType id_type,
+ SilcClientID *target)
+{
+ SilcBuffer idp1, idp2;
+ unsigned char mode[4];
+
+ idp1 = silc_id_payload_encode((void *)id, id_type);
+ idp2 = silc_id_payload_encode((void *)target, SILC_ID_CLIENT);
+ SILC_PUT32_MSB(mode_mask, mode);
+
+ silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
+ SILC_ID_CHANNEL,
+ SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
+ idp1->data, idp1->len,
+ mode, 4,
+ idp2->data, idp2->len);
+ silc_buffer_free(idp1);
+ silc_buffer_free(idp2);
+}
+
+/* Sends SIGNOFF notify type. This tells that `client_id' client has
+ left SILC network. This function is used only between server and router
+ traffic. This is not used to send the notify to the channel for
+ client. The `message may be NULL. */
+
+void silc_server_send_notify_signoff(SilcServer server,
+ SilcSocketConnection sock,
+ bool broadcast,
+ SilcClientID *client_id,
+ const char *message)
+{
+ SilcBuffer idp;
+
+ idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ silc_server_send_notify(server, sock, broadcast,
+ SILC_NOTIFY_TYPE_SIGNOFF,
+ message ? 2 : 1, idp->data, idp->len,
+ message, message ? strlen(message): 0);
+ silc_buffer_free(idp);
+}
+
+/* Sends TOPIC_SET notify type. This tells that `id' changed
+ the `channel's topic to `topic'. The Notify packet is always destined
+ to the channel. This function is used to send the topic set notifies
+ between routers. */
+
+void silc_server_send_notify_topic_set(SilcServer server,
+ SilcSocketConnection sock,
+ bool broadcast,
+ SilcChannelEntry channel,
+ void *id, SilcIdType id_type,
+ char *topic)
+{
+ SilcBuffer idp;
+
+ idp = silc_id_payload_encode(id, id_type);
+ silc_server_send_notify_dest(server, sock, broadcast,
+ (void *)channel->id, SILC_ID_CHANNEL,
+ SILC_NOTIFY_TYPE_TOPIC_SET,
+ topic ? 2 : 1,
+ idp->data, idp->len,
+ topic, topic ? strlen(topic) : 0);
+ silc_buffer_free(idp);
+}
+
+/* Send KICKED notify type. This tells that the `client_id' on `channel'
+ was kicked off the channel. The `comment' may indicate the reason
+ for the kicking. This function is used only between server and router
+ traffic. */
+
+void silc_server_send_notify_kicked(SilcServer server,
+ SilcSocketConnection sock,
+ bool broadcast,
+ SilcChannelEntry channel,
+ SilcClientID *client_id,
+ SilcClientID *kicker,
+ char *comment)
+{
+ SilcBuffer idp1;
+ SilcBuffer idp2;
+
+ idp1 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ idp2 = silc_id_payload_encode((void *)kicker, SILC_ID_CLIENT);
+ silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
+ SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_KICKED, 3,
+ idp1->data, idp1->len,
+ comment, comment ? strlen(comment) : 0,
+ idp2->data, idp2->len);
+ silc_buffer_free(idp1);
+ silc_buffer_free(idp2);
+}
+
+/* Send KILLED notify type. This tells that the `client_id' client was
+ killed from the network. The `comment' may indicate the reason
+ for the killing. */
+
+void silc_server_send_notify_killed(SilcServer server,
+ SilcSocketConnection sock,
+ bool broadcast,
+ SilcClientID *client_id,
+ char *comment)
+{
+ SilcBuffer idp;
+
+ idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ silc_server_send_notify_dest(server, sock, broadcast, (void *)client_id,
+ SILC_ID_CLIENT, SILC_NOTIFY_TYPE_KILLED,
+ comment ? 2 : 1, idp->data, idp->len,
+ comment, comment ? strlen(comment) : 0);
+ silc_buffer_free(idp);
+}
+
+/* Sends UMODE_CHANGE notify type. This tells that `client_id' client's
+ user mode in the SILC Network was changed. This function is used to
+ send the packet between routers as broadcast packet. */
+
+void silc_server_send_notify_umode(SilcServer server,
+ SilcSocketConnection sock,
+ bool broadcast,
+ SilcClientID *client_id,
+ uint32 mode_mask)
+{
+ SilcBuffer idp;
+ unsigned char mode[4];
+
+ idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ SILC_PUT32_MSB(mode_mask, mode);
+
+ silc_server_send_notify(server, sock, broadcast,
+ SILC_NOTIFY_TYPE_UMODE_CHANGE, 2,
+ idp->data, idp->len,
+ mode, 4);
+ silc_buffer_free(idp);
+}
+
+/* Sends BAN notify type. This tells that ban has been either `add'ed
+ or `del'eted on the `channel. This function is used to send the packet
+ between routers as broadcast packet. */
+
+void silc_server_send_notify_ban(SilcServer server,
+ SilcSocketConnection sock,
+ bool broadcast,
+ SilcChannelEntry channel,
+ char *add, char *del)
+{
+ SilcBuffer idp;
+
+ idp = silc_id_payload_encode((void *)channel->id, SILC_ID_CHANNEL);
+ silc_server_send_notify(server, sock, broadcast,
+ SILC_NOTIFY_TYPE_BAN, 3,
+ idp->data, idp->len,
+ add, add ? strlen(add) : 0,
+ del, del ? strlen(del) : 0);
+ silc_buffer_free(idp);
+}
+
+/* Sends INVITE notify type. This tells that invite has been either `add'ed
+ or `del'eted on the `channel. The sender of the invite is the `client_id'.
+ This function is used to send the packet between routers as broadcast
+ packet. */
+
+void silc_server_send_notify_invite(SilcServer server,
+ SilcSocketConnection sock,
+ bool broadcast,
+ SilcChannelEntry channel,
+ SilcClientID *client_id,
+ char *add, char *del)
+{
+ SilcBuffer idp, idp2;
+
+ idp = silc_id_payload_encode((void *)channel->id, SILC_ID_CHANNEL);
+ idp2 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ silc_server_send_notify(server, sock, broadcast,
+ SILC_NOTIFY_TYPE_INVITE, 5,
+ idp->data, idp->len,
+ channel->channel_name, strlen(channel->channel_name),
+ idp2->data, idp2->len,
+ add, add ? strlen(add) : 0,
+ del, del ? strlen(del) : 0);
+ silc_buffer_free(idp);
+ silc_buffer_free(idp2);
+}
+
+/* Sends notify message destined to specific entity. */
+
+void silc_server_send_notify_dest(SilcServer server,
+ SilcSocketConnection sock,
+ bool broadcast,
+ void *dest_id,
+ SilcIdType dest_id_type,
+ SilcNotifyType type,
+ uint32 argc, ...)
+{
+ va_list ap;
+ SilcBuffer packet;
+
+ va_start(ap, argc);
+
+ packet = silc_notify_payload_encode(type, argc, ap);
+ silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY,
+ broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
+ dest_id, dest_id_type,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+ va_end(ap);
+}
+
+/* Sends notify message to a channel. The notify message sent is
+ distributed to all clients on the channel. If `route_notify' is TRUE
+ then the notify may be routed to primary route or to some other routers.
+ If FALSE it is assured that the notify is sent only locally. If `sender'
+ is provided then the packet is not sent to that connection since it
+ originally came from it. */
+
+void silc_server_send_notify_to_channel(SilcServer server,
+ SilcSocketConnection sender,
+ SilcChannelEntry channel,
+ bool route_notify,
+ SilcNotifyType type,
+ uint32 argc, ...)
+{
+ va_list ap;
+ SilcBuffer packet;
+
+ va_start(ap, argc);
+
+ packet = silc_notify_payload_encode(type, argc, ap);
+ silc_server_packet_send_to_channel(server, sender, channel,
+ SILC_PACKET_NOTIFY, route_notify,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+ va_end(ap);
+}
+
+/* Send notify message to all channels the client has joined. It is quaranteed
+ that the message is sent only once to a client (ie. if a client is joined
+ on two same channel it will receive only one notify message). Also, this
+ sends only to local clients (locally connected if we are server, and to
+ local servers if we are router). If `sender' is provided the packet is
+ not sent to that client at all. */
+
+void silc_server_send_notify_on_channels(SilcServer server,
+ SilcClientEntry sender,
+ SilcClientEntry client,
+ SilcNotifyType type,
+ uint32 argc, ...)
+{
+ int k;
+ SilcSocketConnection sock = NULL;
+ SilcPacketContext packetdata;
+ SilcClientEntry c;
+ SilcClientEntry *sent_clients = NULL;
+ uint32 sent_clients_count = 0;
+ SilcServerEntry *routed = NULL;
+ uint32 routed_count = 0;
+ SilcHashTableList htl, htl2;
+ SilcChannelEntry channel;
+ SilcChannelClientEntry chl, chl2;
+ SilcIDListData idata;
+ SilcBuffer packet;
+ unsigned char *data;
+ uint32 data_len;
+ bool force_send = FALSE;
+ va_list ap;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!silc_hash_table_count(client->channels))
+ return;
+
+ va_start(ap, argc);
+ packet = silc_notify_payload_encode(type, argc, ap);
+ data = packet->data;
+ data_len = packet->len;
+
+ /* Set the packet context pointers. */
+ packetdata.flags = 0;
+ packetdata.type = SILC_PACKET_NOTIFY;
+ packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
+ packetdata.src_id_len = silc_id_get_len(server->id, SILC_ID_SERVER);
+ packetdata.src_id_type = SILC_ID_SERVER;
+
+ silc_hash_table_list(client->channels, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+ channel = chl->channel;
+
+ /* Send the message to all clients on the channel's client list. */
+ silc_hash_table_list(channel->user_list, &htl2);
+ while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
+ c = chl2->client;
+
+ if (sender && c == sender)
+ continue;
+
+ /* Check if we have sent the packet to this client already */
+ for (k = 0; k < sent_clients_count; k++)
+ if (sent_clients[k] == c)
+ break;
+ if (k < sent_clients_count)
+ continue;
+
+ /* If we are router and if this client has router set it is not
+ locally connected client and we will route the message to the
+ router set in the client. */
+ if (c && c->router && server->server_type == SILC_ROUTER) {
+ /* Check if we have sent the packet to this route already */
+ for (k = 0; k < routed_count; k++)
+ if (routed[k] == c->router)
+ break;
+ if (k < routed_count)
+ continue;
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)c->router->connection;
+ idata = (SilcIDListData)c->router;
+
+ {
+ SILC_LOG_DEBUG(("*****************"));
+ SILC_LOG_DEBUG(("client->router->id %s",
+ silc_id_render(c->router->id, SILC_ID_SERVER)));
+ SILC_LOG_DEBUG(("client->router->connection->user_data->id %s",
+ silc_id_render(((SilcServerEntry)sock->user_data)->id, SILC_ID_SERVER)));
+ }
+
+ packetdata.dst_id = silc_id_id2str(c->router->id, SILC_ID_SERVER);
+ packetdata.dst_id_len = silc_id_get_len(c->router->id, SILC_ID_SERVER);
+ packetdata.dst_id_type = SILC_ID_SERVER;
+
+ /* Send the packet */
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ idata->send_key,
+ idata->hmac_send,
+ idata->psn_send++,
+ data, data_len, FALSE,
+ force_send);
+
+ silc_free(packetdata.dst_id);
+
+ /* We want to make sure that the packet is routed to same router
+ only once. Mark this route as sent route. */
+ routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1));
+ routed[routed_count++] = c->router;
+ continue;
+ }
+
+ if (c && c->router)
+ continue;
+
+ /* Send to locally connected client */
+ if (c) {
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)c->connection;
+ idata = (SilcIDListData)c;
+
+ packetdata.dst_id = silc_id_id2str(c->id, SILC_ID_CLIENT);
+ packetdata.dst_id_len = silc_id_get_len(c->id, SILC_ID_CLIENT);
+ packetdata.dst_id_type = SILC_ID_CLIENT;
+
+ /* Send the packet */
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ idata->send_key,
+ idata->hmac_send,
+ idata->psn_send++,
+ data, data_len, FALSE,
+ force_send);
+
+ silc_free(packetdata.dst_id);
+
+ /* Make sure that we send the notify only once per client. */
+ sent_clients = silc_realloc(sent_clients, sizeof(*sent_clients) *
+ (sent_clients_count + 1));
+ sent_clients[sent_clients_count++] = c;
+ }
+ }
+ silc_hash_table_list_reset(&htl2);
+ }
+
+ silc_hash_table_list_reset(&htl);
+ silc_free(routed);
+ silc_free(sent_clients);
+ silc_free(packetdata.src_id);
+ silc_buffer_free(packet);
+ va_end(ap);
+}
+
+/* Sends New ID Payload to remote end. The packet is used to distribute
+ information about new registered clients, servers, channel etc. usually
+ to routers so that they can keep these information up to date.
+ If the argument `broadcast' is TRUE then the packet is sent as
+ broadcast packet. */
+
+void silc_server_send_new_id(SilcServer server,
+ SilcSocketConnection sock,
+ bool broadcast,
+ void *id, SilcIdType id_type,
+ uint32 id_len)
+{
+ SilcBuffer idp;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ idp = silc_id_payload_encode(id, id_type);
+ silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID,
+ broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
+ idp->data, idp->len, FALSE);
+
+ /* Send to backup routers if this is being broadcasted to primary
+ router. */
+ if (server->router && server->router->connection &&
+ sock == server->router->connection && broadcast)
+ silc_server_backup_send(server, NULL, SILC_PACKET_NEW_ID, 0,
+ idp->data, idp->len, FALSE, TRUE);
+
+ silc_buffer_free(idp);
+}
+
+/* Send New Channel Payload to notify about newly created channel in the
+ SILC network. Router uses this to notify other routers in the network
+ about new channel. This packet is broadcasted by router. */
+
+void silc_server_send_new_channel(SilcServer server,
+ SilcSocketConnection sock,
+ bool broadcast,
+ char *channel_name,
+ void *channel_id,
+ uint32 channel_id_len,
+ uint32 mode)
+{
+ SilcBuffer packet;
+ unsigned char *cid;
+ uint32 name_len = strlen(channel_name);
+
+ SILC_LOG_DEBUG(("Start"));
+
+ cid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
+ if (!cid)
+ return;
+
+ /* Encode the channel payload */
+ packet = silc_channel_payload_encode(channel_name, name_len,
+ cid, channel_id_len, mode);
+
+ silc_server_packet_send(server, sock, SILC_PACKET_NEW_CHANNEL,
+ broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
+ packet->data, packet->len, FALSE);
+
+ /* Send to backup routers if this is being broadcasted to primary
+ router. */
+ if (server->server_type == SILC_ROUTER &&
+ server->router && server->router->connection &&
+ sock == server->router->connection && broadcast)
+ silc_server_backup_send(server, NULL, SILC_PACKET_NEW_CHANNEL, 0,
+ packet->data, packet->len, FALSE, TRUE);
+
+ silc_free(cid);
+ silc_buffer_free(packet);
+}
+
+/* Send Channel Key payload to distribute the new channel key. Normal server
+ sends this to router when new client joins to existing channel. Router
+ sends this to the local server who sent the join command in case where
+ the channel did not exist yet. Both normal and router servers uses this
+ also to send this to locally connected clients on the channel. This
+ must not be broadcasted packet. Routers do not send this to each other.
+ If `sender is provided then the packet is not sent to that connection since
+ it originally came from it. */
+
+void silc_server_send_channel_key(SilcServer server,
+ SilcSocketConnection sender,
+ SilcChannelEntry channel,
+ unsigned char route)
+{
+ SilcBuffer packet;
+ unsigned char *chid;
+ uint32 tmp_len;
+
+ SILC_LOG_DEBUG(("Sending key to channel %s", channel->channel_name));
+
+ chid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+ if (!chid)
+ return;
+
+ /* Encode channel key packet */
+ tmp_len = strlen(channel->channel_key->cipher->name);
+ packet = silc_channel_key_payload_encode(silc_id_get_len(channel->id,
+ SILC_ID_CHANNEL),
+ chid, tmp_len,
+ channel->channel_key->cipher->name,
+ channel->key_len / 8, channel->key);
+ silc_server_packet_send_to_channel(server, sender, channel,
+ SILC_PACKET_CHANNEL_KEY,
+ route, packet->data, packet->len,
+ FALSE);
+ silc_buffer_free(packet);
+ silc_free(chid);
+}
+
+/* Generic function to send any command. The arguments must be sent already
+ encoded into correct form in correct order. */
+
+void silc_server_send_command(SilcServer server,
+ SilcSocketConnection sock,
+ SilcCommand command,
+ uint16 ident,
+ uint32 argc, ...)
+{
+ SilcBuffer packet;
+ va_list ap;
+
+ va_start(ap, argc);
+
+ packet = silc_command_payload_encode_vap(command, ident, argc, ap);
+ silc_server_packet_send(server, sock, SILC_PACKET_COMMAND, 0,
+ packet->data, packet->len, TRUE);
+ silc_buffer_free(packet);
+ va_end(ap);
+}
+
+/* Generic function to send any command reply. The arguments must be sent
+ already encoded into correct form in correct order. */
+
+void silc_server_send_command_reply(SilcServer server,
+ SilcSocketConnection sock,
+ SilcCommand command,
+ SilcCommandStatus status,
+ uint16 ident,
+ uint32 argc, ...)
+{
+ SilcBuffer packet;
+ va_list ap;
+
+ va_start(ap, argc);
+
+ packet = silc_command_reply_payload_encode_vap(command, status, ident,
+ argc, ap);
+ silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, TRUE);
+ silc_buffer_free(packet);
+ va_end(ap);
+}
+
+/* Generic function to send any command reply. The arguments must be sent
+ already encoded into correct form in correct order. */
+
+void silc_server_send_dest_command_reply(SilcServer server,
+ SilcSocketConnection sock,
+ void *dst_id,
+ SilcIdType dst_id_type,
+ SilcCommand command,
+ SilcCommandStatus status,
+ uint16 ident,
+ uint32 argc, ...)
+{
+ SilcBuffer packet;
+ va_list ap;
+
+ va_start(ap, argc);
+
+ packet = silc_command_reply_payload_encode_vap(command, status, ident,
+ argc, ap);
+ silc_server_packet_send_dest(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
+ dst_id, dst_id_type, packet->data,
+ packet->len, TRUE);
+ silc_buffer_free(packet);
+ va_end(ap);
+}
+
+/* Send the heartbeat packet. */
+
+void silc_server_send_heartbeat(SilcServer server,
+ SilcSocketConnection sock)
+{
+ silc_server_packet_send(server, sock, SILC_PACKET_HEARTBEAT, 0,
+ NULL, 0, FALSE);
+}
+
+/* Generic function to relay packet we've received. This is used to relay
+ packets to a client but generally can be used to other purposes as well. */
+
+void silc_server_relay_packet(SilcServer server,
+ SilcSocketConnection dst_sock,
+ SilcCipher cipher,
+ SilcHmac hmac,
+ uint32 sequence,
+ SilcPacketContext *packet,
+ bool force_send)
+{
+ silc_buffer_push(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ + packet->dst_id_len + packet->padlen);
+
+ silc_packet_send_prepare(dst_sock, 0, 0, packet->buffer->len);
+ silc_buffer_put(dst_sock->outbuf, packet->buffer->data, packet->buffer->len);
+
+ /* Re-encrypt packet */
+ silc_packet_encrypt(cipher, hmac, sequence, dst_sock->outbuf,
+ packet->buffer->len);
+
+ /* Send the packet */
+ silc_server_packet_send_real(server, dst_sock, force_send);
+
+ silc_buffer_pull(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ + packet->dst_id_len + packet->padlen);
+}
+
+/* Routine used to send the connection authentication packet. */
+
+void silc_server_send_connection_auth_request(SilcServer server,
+ SilcSocketConnection sock,
+ uint16 conn_type,
+ SilcAuthMethod auth_meth)
+{
+ SilcBuffer packet;
+
+ packet = silc_buffer_alloc(4);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(conn_type),
+ SILC_STR_UI_SHORT(auth_meth),
+ SILC_STR_END);
+
+ silc_server_packet_send(server, sock, SILC_PACKET_CONNECTION_AUTH_REQUEST,
+ 0, packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+}
+
+/* Purge the outgoing packet queue to the network if there is data. This
+ function can be used to empty the packet queue. It is guaranteed that
+ after this function returns the outgoing data queue is empty. */
+
+void silc_server_packet_queue_purge(SilcServer server,
+ SilcSocketConnection sock)
+{
+ if (sock && SILC_IS_OUTBUF_PENDING(sock) &&
+ (SILC_IS_DISCONNECTED(sock) == FALSE)) {
+ server->stat.packets_sent++;
+
+ if (sock->outbuf->data - sock->outbuf->head)
+ silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
+
+ silc_packet_send(sock, TRUE);
+
+ SILC_SET_CONNECTION_FOR_INPUT(server->schedule, sock->sock);
+ SILC_UNSET_OUTBUF_PENDING(sock);
+ silc_buffer_clear(sock->outbuf);
+ }
+}
/* Remote end is client */
if (conn_type == SILC_SOCKET_TYPE_CLIENT) {
- SilcServerConfigSectionClientConnection *client = ctx->cconfig;
- SilcConfigServerSectionClientConnection *client = NULL;
- client =
- silc_config_server_find_client_conn(server->config,
- ctx->sock->ip,
- ctx->sock->port);
- if (!client)
- client =
- silc_config_server_find_client_conn(server->config,
- ctx->sock->hostname,
- ctx->sock->port);
++ SilcServerConfigSectionClient *client = ctx->cconfig;
if (client) {
switch(client->auth_meth) {
/* Remote end is server */
if (conn_type == SILC_SOCKET_TYPE_SERVER) {
- SilcServerConfigSectionServerConnection *serv = ctx->sconfig;
- SilcConfigServerSectionServerConnection *serv = NULL;
- serv =
- silc_config_server_find_server_conn(server->config,
- ctx->sock->ip,
- ctx->sock->port);
- if (!serv)
- serv =
- silc_config_server_find_server_conn(server->config,
- ctx->sock->hostname,
- ctx->sock->port);
++ SilcServerConfigSectionServer *serv = ctx->sconfig;
if (serv) {
switch(serv->auth_meth) {
/* Remote end is router */
if (conn_type == SILC_SOCKET_TYPE_ROUTER) {
- SilcServerConfigSectionServerConnection *serv = ctx->rconfig;
- SilcConfigServerSectionServerConnection *serv = NULL;
- serv =
- silc_config_server_find_router_conn(server->config,
- ctx->sock->ip,
- ctx->sock->port);
- if (!serv)
- serv =
- silc_config_server_find_router_conn(server->config,
- ctx->sock->hostname,
- ctx->sock->port);
-
++ SilcServerConfigSectionRouter *serv = ctx->rconfig;
+
if (serv) {
switch(serv->auth_meth) {
- case SILC_PROTOCOL_CONN_AUTH_NONE:
+ case SILC_AUTH_NONE:
/* No authentication required */
SILC_LOG_DEBUG(("No authentication required"));
break;
{
int *sock = NULL, sock_count, i;
SilcServerID *id;
- SilcServerList *id_entry;
- SilcHashObject hash;
+ SilcServerEntry id_entry;
+ SilcIDListPurge purge;
- SilcServerConfigSectionListenPort *listen;
SILC_LOG_DEBUG(("Initializing server"));
assert(server);
assert(server->config);
- /* Set log files where log message should be saved. */
- server->config->server = server;
- silc_config_server_setlogfiles(server->config);
-
+ /* Set public and private keys */
- if (!server->config->server_keys ||
- !server->config->server_keys->public_key ||
- !server->config->server_keys->private_key) {
++ if (!server->config->server_info ||
++ !server->config->server_info->public_key ||
++ !server->config->server_info->private_key) {
+ SILC_LOG_ERROR(("Server public key and/or private key does not exist"));
+ return FALSE;
+ }
- server->public_key = server->config->server_keys->public_key;
- server->private_key = server->config->server_keys->private_key;
++ server->public_key = server->config->server_info->public_key;
++ server->private_key = server->config->server_info->private_key;
+
+ /* XXX After server is made as Silc Server Library this can be given
+ as argument, for now this is hard coded */
+ server->params = silc_calloc(1, sizeof(*server->params));
+ server->params->retry_count = SILC_SERVER_RETRY_COUNT;
+ server->params->retry_interval_min = SILC_SERVER_RETRY_INTERVAL_MIN;
+ server->params->retry_interval_max = SILC_SERVER_RETRY_INTERVAL_MAX;
+ server->params->retry_keep_trying = FALSE;
+ server->params->protocol_timeout = 60;
+ server->params->require_reverse_mapping = FALSE;
+
- /* Set log files where log message should be saved. */
- server->config->server = server;
-
/* Register all configured ciphers, PKCS and hash functions. */
- if (!silc_server_config_register_ciphers(server->config))
- silc_config_server_register_ciphers(server->config);
- silc_config_server_register_pkcs(server->config);
- silc_config_server_register_hashfuncs(server->config);
++ if (!silc_server_config_register_ciphers(server))
+ silc_cipher_register_default();
- if (!silc_server_config_register_pkcs(server->config))
++ if (!silc_server_config_register_pkcs(server))
+ silc_pkcs_register_default();
- if (!silc_server_config_register_hashfuncs(server->config))
++ if (!silc_server_config_register_hashfuncs(server))
+ silc_hash_register_default();
- if (!silc_server_config_register_hmacs(server->config))
++ if (!silc_server_config_register_hmacs(server))
+ silc_hmac_register_default();
/* Initialize random number generator for the server. */
server->rng = silc_rng_alloc();
silc_hash_alloc("md5", &server->md5hash);
silc_hash_alloc("sha1", &server->sha1hash);
- /* Initialize none cipher */
- silc_cipher_alloc("none", &server->none_cipher);
-
- /* XXXXX Generate RSA key pair */
- {
- unsigned char *public_key;
- unsigned char *private_key;
- unsigned int pk_len, prv_len;
-
- if (silc_pkcs_alloc("rsa", &server->public_key) == FALSE) {
- SILC_LOG_ERROR(("Could not create RSA key pair"));
- goto err0;
- }
-
- if (server->public_key->pkcs->init(server->public_key->context,
- 1024, server->rng) == FALSE) {
- SILC_LOG_ERROR(("Could not generate RSA key pair"));
- goto err0;
- }
-
- public_key =
- server->public_key->pkcs->get_public_key(server->public_key->context,
- &pk_len);
- private_key =
- server->public_key->pkcs->get_private_key(server->public_key->context,
- &prv_len);
-
- SILC_LOG_HEXDUMP(("public key"), public_key, pk_len);
- SILC_LOG_HEXDUMP(("private key"), private_key, prv_len);
-
- /* XXX Save keys */
- silc_pkcs_save_public_key(server->public_key, "pubkey.pub",
- public_key, pk_len);
+ /* Allocate PKCS context for local public and private keys */
+ silc_pkcs_alloc(server->public_key->name, &server->pkcs);
+ silc_pkcs_public_key_set(server->pkcs, server->public_key);
+ silc_pkcs_private_key_set(server->pkcs, server->private_key);
- memset(public_key, 0, pk_len);
- memset(private_key, 0, prv_len);
- silc_free(public_key);
- silc_free(private_key);
- }
-
- /* Create a listening server. Note that our server can listen on
- multiple ports. All listeners are created here and now. */
- /* XXX Still check this whether to use server_info or listen_port. */
+ /* Create a listening server. Note that our server can listen on multiple
+ ports. All listeners are created here and now. */
sock_count = 0;
- listen = server->config->listen_port;
- while(listen) {
- while(server->config->listen_port) {
++ while (1) {
int tmp;
-- tmp = silc_net_create_server(server->config->listen_port->port,
- server->config->listen_port->listener_ip);
- server->config->listen_port->host);
- if (tmp < 0)
++ tmp = silc_net_create_server(server->config->server_info->port,
++ server->config->server_info->server_ip);
+
+ if (tmp < 0) {
- SILC_LOG_ERROR(("Could not create server listener: %s on %d",
- server->config->listen_port->listener_ip,
- server->config->listen_port->port));
++ SILC_LOG_ERROR(("Could not create server listener: %s on %hd",
++ server->config->server_info->server_ip,
++ server->config->server_info->port));
goto err0;
+ }
- sock = silc_realloc(sock, (sizeof(int *) * (sock_count + 1)));
+ sock = silc_realloc(sock, sizeof(*sock) * (sock_count + 1));
sock[sock_count] = tmp;
- server->config->listen_port = server->config->listen_port->next;
sock_count++;
- listen = listen->next;
++ break;
}
+ /* Initialize ID caches */
+ server->local_list->clients =
+ silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor);
+ server->local_list->servers = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
+ server->local_list->channels = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
+
+ /* These are allocated for normal server as well as these hold some
+ global information that the server has fetched from its router. For
+ router these are used as they are supposed to be used on router. */
+ server->global_list->clients =
+ silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor);
+ server->global_list->servers = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
+ server->global_list->channels = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
+
/* Allocate the entire socket list that is used in server. Eventually
all connections will have entry in this table (it is a table of
pointers to the actual object that is allocated individually
/* If server connections has been configured then we must be router as
normal server cannot have server connections, only router connections. */
- if (server->config->servers)
+ if (server->config->servers) {
- SilcServerConfigSectionServerConnection *ptr = server->config->servers;
++ SilcServerConfigSectionServer *ptr = server->config->servers;
+
server->server_type = SILC_ROUTER;
+ while (ptr) {
+ if (ptr->backup_router) {
+ server->server_type = SILC_BACKUP_ROUTER;
+ server->backup_router = TRUE;
+ server->id_entry->server_type = SILC_BACKUP_ROUTER;
+ break;
+ }
+ ptr = ptr->next;
+ }
+ }
+
+ /* Register the ID Cache purge task. This periodically purges the ID cache
+ and removes the expired cache entries. */
+
+ /* Clients local list */
+ purge = silc_calloc(1, sizeof(*purge));
+ purge->cache = server->local_list->clients;
+ purge->schedule = server->schedule;
+ purge->timeout = 600;
+ silc_schedule_task_add(purge->schedule, 0,
+ silc_idlist_purge,
+ (void *)purge, purge->timeout, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+
+ /* Clients global list */
+ purge = silc_calloc(1, sizeof(*purge));
+ purge->cache = server->global_list->clients;
+ purge->schedule = server->schedule;
+ purge->timeout = 300;
+ silc_schedule_task_add(purge->schedule, 0,
+ silc_idlist_purge,
+ (void *)purge, purge->timeout, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
SILC_LOG_DEBUG(("Server initialized"));
return FALSE;
}
- if (!server->config->identity || !server->config->identity->user ||
- !server->config->identity->group) {
+/* Fork server to background */
+
+void silc_server_daemonise(SilcServer server)
+{
+ int i;
+
+ SILC_LOG_DEBUG(("Forking SILC server to background"));
+
+ i = fork();
+
+ if (i < 0) {
+ SILC_LOG_DEBUG(("fork() failed, cannot proceed"));
+ exit(1);
+ }
+ else if (i) {
+ if (geteuid())
+ SILC_LOG_DEBUG(("Server started as user"));
+ else
+ SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
+ exit(0);
+ }
+ setsid();
+}
+
+/* Drop root privligies. If this cannot be done, die. */
+
+void silc_server_drop(SilcServer server)
+{
+ /* Are we executing silcd as root or a regular user? */
+ if (!geteuid()) {
+ struct passwd *pw;
+ struct group *gr;
+ char *user, *group;
+
- user=server->config->identity->user;
- group=server->config->identity->group;
++ if (!server->config->server_info->user || !server->config->server_info->group) {
+ fprintf(stderr, "Error:"
+ "\tSILC server must not be run as root. For the security of your\n"
+ "\tsystem it is strongly suggested that you run SILC under dedicated\n"
+ "\tuser account. Modify the [Identity] configuration section to run\n"
+ "\tthe server as non-root user.\n");
+ exit(1);
+ }
+
+ /* Get the values given for user and group in configuration file */
++ user=server->config->server_info->user;
++ group=server->config->server_info->group;
+
+ /* Check whether the user/group information is text */
+ if (atoi(user)!=0 || atoi(group)!=0) {
+ SILC_LOG_DEBUG(("Invalid user and/or group information"));
+ SILC_LOG_DEBUG(("User and/or group given as number"));
+ fprintf(stderr, "Invalid user and/or group information\n");
+ fprintf(stderr, "Please assign them as names, not numbers\n");
+ exit(1);
+ }
+
+ /* Catch the nasty incident of string "0" returning 0 from atoi */
+ if (strcmp("0", user)==0 || strcmp("0", group)==0) {
+ SILC_LOG_DEBUG(("User and/or group configured to 0. Unacceptable"));
+ fprintf(stderr, "User and/or group configured to 0. Exiting\n");
+ exit(1);
+ }
+
+ if (!(pw=getpwnam(user))) {
+ fprintf(stderr, "No such user %s found\n", user);
+ exit(1);
+ }
+
+ if (!(gr=getgrnam(group))) {
+ fprintf(stderr, "No such group %s found\n", group);
+ exit(1);
+ }
+
+ /* Check whether user and/or group is set to root. If yes, exit
+ immediately. Otherwise, setgid and setuid server to user.group */
+ if (gr->gr_gid==0 || pw->pw_uid==0) {
+ fprintf(stderr, "Error:"
+ "\tSILC server must not be run as root. For the security of your\n"
+ "\tsystem it is strongly suggested that you run SILC under dedicated\n"
+ "\tuser account. Modify the [Identity] configuration section to run\n"
+ "\tthe server as non-root user.\n");
+ exit(1);
+ } else {
+ SILC_LOG_DEBUG(("Changing to group %s", group));
+ if (setgid(gr->gr_gid)==0) {
+ SILC_LOG_DEBUG(("Setgid to %s", group));
+ } else {
+ SILC_LOG_DEBUG(("Setgid to %s failed", group));
+ fprintf(stderr, "Tried to setgid %s but no such group. Exiting\n",
+ group);
+ exit(1);
+ }
+#if defined HAVE_SETGROUPS && defined HAVE_INITGROUPS
+ if (setgroups(0, NULL)!=0) {
+ SILC_LOG_DEBUG(("Setgroups to NULL failed"));
+ fprintf(stderr, "Tried to setgroups NULL but failed. Exiting\n");
+ exit(1);
+ }
+ if (initgroups(user, gr->gr_gid)!=0) {
+ SILC_LOG_DEBUG(("Initgroups to user %s (gid=%d) failed", user, gr->gr_gid));
+ fprintf(stderr, "Tried to initgroups %s (gid=%d) but no such user. Exiting\n",
+ user, gr->gr_gid);
+ exit(1);
+ }
+#endif
+ SILC_LOG_DEBUG(("Changing to user %s", user));
+ if (setuid(pw->pw_uid)==0) {
+ SILC_LOG_DEBUG(("Setuid to %s", user));
+ } else {
+ SILC_LOG_DEBUG(("Setuid to %s failed", user));
+ fprintf(stderr, "Tried to setuid %s but no such user. Exiting\n",
+ user);
+ exit(1);
+ }
+ }
+ }
+}
+
+/* The heart of the server. This runs the scheduler thus runs the server.
+ When this returns the server has been stopped and the program will
+ be terminated. */
+
+void silc_server_run(SilcServer server)
+{
+ SILC_LOG_DEBUG(("Running server"));
+
+ SILC_LOG_INFO(("SILC Server started"));
+
+ /* Start the scheduler, the heart of the SILC server. When this returns
+ the program will be terminated. */
+ silc_schedule(server->schedule);
+}
+
/* Stops the SILC server. This function is used to shutdown the server.
This is usually called after the scheduler has returned. After stopping
the server one should call silc_server_free. */
SILC_LOG_DEBUG(("Server stopped"));
}
-/* The heart of the server. This runs the scheduler thus runs the server. */
+/* Function that is called when the network connection to a router has
+ been established. This will continue with the key exchange protocol
+ with the remote router. */
-void silc_server_run(SilcServer server)
+void silc_server_start_key_exchange(SilcServer server,
+ SilcServerConnection sconn,
+ int sock)
{
- SILC_LOG_DEBUG(("Running server"));
+ SilcSocketConnection newsocket;
+ SilcProtocol protocol;
+ SilcServerKEInternalContext *proto_ctx;
+ void *context;
- /* Start the scheduler, the heart of the SILC server. When this returns
- the program will be terminated. */
- silc_schedule();
+ /* Cancel any possible retry timeouts */
+ silc_schedule_task_del_by_callback(server->schedule,
+ silc_server_connect_router);
+
+ /* Set socket options */
+ silc_net_set_socket_nonblock(sock);
+ silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+
+ /* Create socket connection for the connection. Even though we
+ know that we are connecting to a router we will mark the socket
+ to be unknown connection until we have executed authentication
+ protocol. */
+ silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket);
+ server->sockets[sock] = newsocket;
+ newsocket->hostname = strdup(sconn->remote_host);
+ newsocket->ip = strdup(sconn->remote_host);
+ newsocket->port = sconn->remote_port;
+ sconn->sock = newsocket;
+
+ /* Allocate internal protocol context. This is sent as context
+ to the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->server = (void *)server;
+ proto_ctx->context = (void *)sconn;
+ proto_ctx->sock = newsocket;
+ proto_ctx->rng = server->rng;
+ proto_ctx->responder = FALSE;
+
+ /* Perform key exchange protocol. silc_server_connect_to_router_second
+ will be called after the protocol is finished. */
+ silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
+ &protocol, proto_ctx,
+ silc_server_connect_to_router_second);
+ newsocket->protocol = protocol;
+
+ /* Register a timeout task that will be executed if the protocol
+ is not executed within set limit. */
+ proto_ctx->timeout_task =
+ silc_schedule_task_add(server->schedule, sock,
+ silc_server_timeout_remote,
+ server, server->params->protocol_timeout,
+ server->params->protocol_timeout_usec,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_LOW);
+
+ /* Register the connection for network input and output. This sets
+ that scheduler will listen for incoming packets for this connection
+ and sets that outgoing packets may be sent to this connection as
+ well. However, this doesn't set the scheduler for outgoing traffic,
+ it will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
+ later when outgoing data is available. */
+ context = (void *)server;
+ SILC_REGISTER_CONNECTION_FOR_IO(sock);
+
+ /* Run the protocol */
+ silc_protocol_execute(protocol, server->schedule, 0, 0);
+}
+
+/* Timeout callback that will be called to retry connecting to remote
+ router. This is used by both normal and router server. This will wait
+ before retrying the connecting. The timeout is generated by exponential
+ backoff algorithm. */
+
+SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
+{
+ SilcServerConnection sconn = (SilcServerConnection)context;
+ SilcServer server = sconn->server;
+
+ SILC_LOG_INFO(("Retrying connecting to a router"));
+
+ /* Calculate next timeout */
+ if (sconn->retry_count >= 1) {
+ sconn->retry_timeout = sconn->retry_timeout * SILC_SERVER_RETRY_MULTIPLIER;
+ if (sconn->retry_timeout > SILC_SERVER_RETRY_INTERVAL_MAX)
+ sconn->retry_timeout = SILC_SERVER_RETRY_INTERVAL_MAX;
+ } else {
+ sconn->retry_timeout = server->params->retry_interval_min;
+ }
+ sconn->retry_count++;
+ sconn->retry_timeout = sconn->retry_timeout +
+ silc_rng_get_rn32(server->rng) % SILC_SERVER_RETRY_RANDOMIZER;
+
+ /* If we've reached max retry count, give up. */
+ if (sconn->retry_count > server->params->retry_count &&
+ server->params->retry_keep_trying == FALSE) {
+ SILC_LOG_ERROR(("Could not connect to router, giving up"));
+ silc_free(sconn->remote_host);
+ silc_free(sconn);
+ return;
+ }
+
+ /* Wait one before retrying */
+ silc_schedule_task_add(server->schedule, fd, silc_server_connect_router,
+ context, sconn->retry_timeout,
+ server->params->retry_interval_min_usec,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
- sock = silc_net_create_connection(server->config->listen_port->local_ip,
+/* Generic routine to use connect to a router. */
+
+SILC_TASK_CALLBACK(silc_server_connect_router)
+{
+ SilcServerConnection sconn = (SilcServerConnection)context;
+ SilcServer server = sconn->server;
+ int sock;
+
+ SILC_LOG_INFO(("Connecting to the %s %s on port %d",
+ (sconn->backup ? "backup router" : "router"),
+ sconn->remote_host, sconn->remote_port));
+
+ server->router_connect = time(0);
+
+ /* Connect to remote host */
++ sock = silc_net_create_connection(server->config->server_info->server_ip,
+ sconn->remote_port,
+ sconn->remote_host);
+ if (sock < 0) {
+ SILC_LOG_ERROR(("Could not connect to router %s:%d",
+ sconn->remote_host, sconn->remote_port));
+ if (!sconn->no_reconnect)
+ silc_schedule_task_add(server->schedule, fd,
+ silc_server_connect_to_router_retry,
+ context, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ return;
+ }
+
+ /* Continue with key exchange protocol */
+ silc_server_start_key_exchange(server, sconn, sock);
+}
+
/* This function connects to our primary router or if we are a router this
establishes all our primary routes. This is called at the start of the
server to do authentication and key exchange with our router - called
SILC_TASK_CALLBACK(silc_server_connect_to_router)
{
SilcServer server = (SilcServer)context;
- SilcSocketConnection newsocket;
- int sock;
+ SilcServerConnection sconn;
- SilcServerConfigSectionServerConnection *ptr;
++ SilcServerConfigSectionRouter *ptr;
SILC_LOG_DEBUG(("Connecting to router(s)"));
SilcServerKEInternalContext *ctx =
(SilcServerKEInternalContext *)protocol->context;
SilcServer server = (SilcServer)ctx->server;
- SilcSocketConnection sock = NULL;
+ SilcServerConnection sconn = (SilcServerConnection)ctx->context;
+ SilcSocketConnection sock = ctx->sock;
SilcServerConnAuthInternalContext *proto_ctx;
- SilcServerConfigSectionServerConnection *conn = NULL;
++ SilcServerConfigSectionRouter *conn = NULL;
SILC_LOG_DEBUG(("Start"));
silc_buffer_free(packet);
silc_free(id_string);
- SILC_LOG_DEBUG(("Connected to router %s", sock->hostname));
+ SILC_LOG_INFO(("Connected to router %s", sock->hostname));
+
+ /* Check that we do not have this ID already */
+ id_entry = silc_idlist_find_server_by_id(server->local_list,
+ ctx->dest_id, TRUE, NULL);
+ if (id_entry) {
+ silc_idcache_del_by_context(server->local_list->servers, id_entry);
+ } else {
+ id_entry = silc_idlist_find_server_by_id(server->global_list,
+ ctx->dest_id, TRUE, NULL);
+ if (id_entry)
+ silc_idcache_del_by_context(server->global_list->servers, id_entry);
+ }
+
+ SILC_LOG_DEBUG(("New server id(%s)",
+ silc_id_render(ctx->dest_id, SILC_ID_SERVER)));
- /* Add the connected router to local server list */
- server->standalone = FALSE;
- conn_data = (SilcIDListUnknown *)sock->user_data;
- silc_idlist_add_server(&server->local_list->servers,
- sock->hostname ? sock->hostname : sock->ip,
- SILC_ROUTER, ctx->dest_id, NULL,
- conn_data->send_key, conn_data->receive_key,
- conn_data->pkcs, conn_data->hmac, &id_entry);
+ /* Add the connected router to global server list */
+ id_entry = silc_idlist_add_server(server->global_list,
+ strdup(sock->hostname),
+ SILC_ROUTER, ctx->dest_id, NULL, sock);
+ if (!id_entry) {
+ silc_free(ctx->dest_id);
+ silc_server_disconnect_remote(server, sock, "Server closed connection: "
+ "Authentication failed");
+ goto out;
+ }
- id_entry->hmac_key = conn_data->hmac_key;
- id_entry->hmac_key_len = conn_data->hmac_key_len;
- id_entry->connection = sock;
+ silc_idlist_add_data(id_entry, (SilcIDListData)sock->user_data);
+ silc_free(sock->user_data);
sock->user_data = (void *)id_entry;
sock->type = SILC_SOCKET_TYPE_ROUTER;
- server->id_entry->router = id_entry;
+ idata = (SilcIDListData)sock->user_data;
+ idata->status |= SILC_IDLIST_STATUS_REGISTERED;
+
+ /* Perform keepalive. The `hb_context' will be freed automatically
+ when finally calling the silc_socket_free function. XXX hardcoded
+ timeout!! */
+ hb_context = silc_calloc(1, sizeof(*hb_context));
+ hb_context->server = server;
+ silc_socket_set_heartbeat(sock, 300, hb_context,
+ silc_server_perform_heartbeat,
+ server->schedule);
+
+ /* Register re-key timeout */
+ idata->rekey->timeout = 3600; /* XXX hardcoded */
+ idata->rekey->context = (void *)server;
+ silc_schedule_task_add(server->schedule, sock->sock,
+ silc_server_rekey_callback,
+ (void *)sock, idata->rekey->timeout, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+
+ if (!sconn->backup) {
+ /* Mark this router our primary router if we're still standalone */
+ if (server->standalone) {
+ server->id_entry->router = id_entry;
+ server->router = id_entry;
+ server->standalone = FALSE;
+
+ /* If we are router then announce our possible servers. */
+ if (server->server_type == SILC_ROUTER)
+ silc_server_announce_servers(server, FALSE, 0,
+ server->router->connection);
+
+ /* Announce our clients and channels to the router */
+ silc_server_announce_clients(server, 0, server->router->connection);
+ silc_server_announce_channels(server, 0, server->router->connection);
+ }
+ } else {
+ /* Add this server to be our backup router */
+ silc_server_backup_add(server, id_entry, sconn->backup_replace_ip,
+ sconn->backup_replace_port, FALSE);
+ }
+
+ sock->protocol = NULL;
- /* Free the temporary connection data context from key exchange */
- silc_free(conn_data);
+ /* Call the completion callback to indicate that we've connected to
+ the router */
+ if (sconn->callback)
+ (*sconn->callback)(server, id_entry, sconn->callback_context);
+
+ out:
+ /* Free the temporary connection data context */
+ if (sconn) {
+ silc_free(sconn->remote_host);
+ silc_free(sconn->backup_replace_ip);
+ silc_free(sconn);
+ }
+ if (sconn == server->router_conn)
+ server->router_conn = NULL;
/* Free the protocol object */
+ if (sock->protocol == protocol)
+ sock->protocol = NULL;
silc_protocol_free(protocol);
if (ctx->packet)
- silc_buffer_free(ctx->packet);
+ silc_packet_context_free(ctx->packet);
if (ctx->ske)
silc_ske_free(ctx->ske);
+ silc_free(ctx->auth_data);
silc_free(ctx);
- sock->protocol = NULL;
}
-/* Accepts new connections to the server. Accepting new connections are
- done in three parts to make it async. */
+/* Host lookup callbcak that is called after the incoming connection's
+ IP and FQDN lookup is performed. This will actually check the acceptance
+ of the incoming connection and will register the key exchange protocol
+ for this connection. */
-SILC_TASK_CALLBACK(silc_server_accept_new_connection)
+static void
+silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
+ void *context)
{
SilcServer server = (SilcServer)context;
- SilcSocketConnection newsocket;
SilcServerKEInternalContext *proto_ctx;
- int sock;
+ void *cconfig, *sconfig, *rconfig;
- SilcServerConfigSectionDenyConnection *deny;
++ SilcServerConfigSectionDeny *deny;
+ int port;
- SILC_LOG_DEBUG(("Accepting new connection"));
+ SILC_LOG_DEBUG(("Start"));
- sock = silc_net_accept_connection(server->sock);
- if (sock < 0) {
- SILC_LOG_ERROR(("Could not accept new connection: %s", strerror(errno)));
+ /* Check whether we could resolve both IP and FQDN. */
+ if (!sock->ip || (!strcmp(sock->ip, sock->hostname) &&
+ server->params->require_reverse_mapping)) {
+ SILC_LOG_ERROR(("IP/DNS lookup failed %s",
+ sock->hostname ? sock->hostname :
+ sock->ip ? sock->ip : ""));
+ server->stat.conn_failures++;
+ silc_server_disconnect_remote(server, sock,
+ "Server closed connection: Unknown host");
return;
}
- /* Check max connections */
- if (sock > SILC_SERVER_MAX_CONNECTIONS) {
- if (server->config->redirect) {
- /* XXX Redirecting connection to somewhere else now?? */
- /*silc_server_send_notify("Server is full, trying to redirect..."); */
- } else {
- SILC_LOG_ERROR(("Refusing connection, server is full"));
- }
+ /* Register the connection for network input and output. This sets
+ that scheduler will listen for incoming packets for this connection
+ and sets that outgoing packets may be sent to this connection as well.
+ However, this doesn't set the scheduler for outgoing traffic, it
+ will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
+ later when outgoing data is available. */
+ SILC_REGISTER_CONNECTION_FOR_IO(sock->sock);
+
+ SILC_LOG_INFO(("Incoming connection from %s (%s)", sock->hostname,
+ sock->ip));
+
+ port = server->sockets[server->sock]->port; /* Listenning port */
+
+ /* Check whether this connection is denied to connect to us. */
- deny = silc_server_config_denied_conn(server->config, sock->ip, port);
++ deny = silc_server_config_find_denied(server->config, sock->ip, port);
+ if (!deny)
- deny = silc_server_config_denied_conn(server->config, sock->hostname,
++ deny = silc_server_config_find_denied(server->config, sock->hostname,
+ port);
+ if (deny) {
+ /* The connection is denied */
+ SILC_LOG_INFO(("Connection %s (%s) is denied",
+ sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock, deny->comment ?
- deny->comment :
++ silc_server_disconnect_remote(server, sock, deny->reason ?
++ deny->reason :
+ "Server closed connection: "
+ "Connection refused");
+ server->stat.conn_failures++;
return;
}
- /* Set socket options */
- silc_net_set_socket_nonblock(sock);
- silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
-
- /* We don't create a ID yet, since we don't know what type of connection
- this is yet. But, we do add the connection to the socket table. */
- silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket);
- server->sockets[sock] = newsocket;
-
- /* XXX This MUST be done async as this will block the entire server
- process. Either we have to do our own resolver stuff or in the future
- we can use threads. */
- /* Perform mandatory name and address lookups for the remote host. */
- silc_net_check_host_by_sock(sock, &newsocket->hostname, &newsocket->ip);
- if (!newsocket->ip || !newsocket->hostname) {
- SILC_LOG_DEBUG(("IP lookup/DNS lookup failed"));
- SILC_LOG_ERROR(("IP lookup/DNS lookup failed"));
+ /* Check whether we have configred this sort of connection at all. We
+ have to check all configurations since we don't know what type of
+ connection this is. */
- if (!(cconfig = silc_server_config_find_client_conn(server->config,
++ if (!(cconfig = silc_server_config_find_client(server->config,
+ sock->ip, port)))
- cconfig = silc_server_config_find_client_conn(server->config,
++ cconfig = silc_server_config_find_client(server->config,
+ sock->hostname,
+ port);
+ if (!(sconfig = silc_server_config_find_server_conn(server->config,
+ sock->ip,
+ port)))
+ sconfig = silc_server_config_find_server_conn(server->config,
+ sock->hostname,
+ port);
+ if (!(rconfig = silc_server_config_find_router_conn(server->config,
+ sock->ip, port)))
+ rconfig = silc_server_config_find_router_conn(server->config,
+ sock->hostname,
+ port);
+ if (!cconfig && !sconfig && !rconfig) {
+ SILC_LOG_INFO(("Connection %s (%s) is not allowed",
+ sock->hostname, sock->ip));
+ silc_server_disconnect_remote(server, sock,
+ "Server closed connection: "
+ "Connection refused");
+ server->stat.conn_failures++;
return;
}
case SILC_SOCKET_TYPE_SERVER:
case SILC_SOCKET_TYPE_ROUTER:
{
- SilcServerList *id_entry;
- SilcIDListUnknown *conn_data = sock->user_data;
-
+ SilcServerEntry new_server;
- SilcServerConfigSectionServerConnection *conn =
++ /* XXX FIXME: Now server and router has different table, so this is probably broken. */
++ SilcServerConfigSectionRouter *conn =
+ ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
+ ctx->sconfig : ctx->rconfig;
+
SILC_LOG_DEBUG(("Remote host is %s",
- sock->type == SILC_SOCKET_TYPE_SERVER ?
- "server" : "router"));
-
- /* Add the server to the ID list. We don't have the server's ID
- yet but we will receive it after the server sends NEW_SERVER
- packet to us. */
- silc_idlist_add_server(&server->local_list->servers, NULL,
- sock->type == SILC_SOCKET_TYPE_SERVER ?
- SILC_SERVER : SILC_ROUTER, NULL, NULL,
- conn_data->send_key, conn_data->receive_key,
- conn_data->pkcs, conn_data->hmac, &id_entry);
-
- id_entry->hmac_key = conn_data->hmac_key;
- id_entry->hmac_key_len = conn_data->hmac_key_len;
- id_entry->connection = sock;
-
- /* Free the temporary connection data context from key exchange */
- silc_free(conn_data);
-
- /* Mark the entry to the ID list to the socket connection for
- fast referencing in the future. */
- sock->user_data = (void *)id_entry;
-
- /* There is connection to other server now, if it is router then
- we will have connection to outside world. If we are router but
- normal server connected to us then we will remain standalone,
- if we are standlone. */
- if (server->standalone && sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
+ "server" : (conn->backup_router ?
+ "backup router" : "router")));
+ SILC_LOG_INFO(("Connection from %s (%s) is %s", sock->hostname,
+ sock->ip, ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
+ "server" : (conn->backup_router ?
+ "backup router" : "router")));
+
+ /* Add the server into server cache. The server name and Server ID
+ is updated after we have received NEW_SERVER packet from the
+ server. We mark ourselves as router for this server if we really
+ are router. */
+ new_server =
+ silc_idlist_add_server((ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
+ server->local_list : (conn->backup_router ?
+ server->local_list :
+ server->global_list)),
+ NULL,
+ (ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
+ SILC_SERVER : SILC_ROUTER),
+ NULL,
+ (ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
+ server->id_entry : (conn->backup_router ?
+ server->id_entry : NULL)),
+ sock);
+ if (!new_server) {
+ SILC_LOG_ERROR(("Could not add new server to cache"));
+ silc_free(sock->user_data);
+ silc_server_disconnect_remote(server, sock,
+ "Server closed connection: "
+ "Authentication failed");
+ server->stat.auth_failures++;
+ goto out;
+ }
+
+ /* Statistics */
+ if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER)
+ server->stat.my_servers++;
+ else
+ server->stat.my_routers++;
+ server->stat.servers++;
+
+ id_entry = (void *)new_server;
+
+ /* If the incoming connection is router and marked as backup router
+ then add it to be one of our backups */
+ if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER && conn->backup_router) {
+ silc_server_backup_add(server, new_server, conn->backup_replace_ip,
+ conn->backup_replace_port, conn->backup_local);
+
+ /* Change it back to SERVER type since that's what it really is. */
+ if (conn->backup_local)
+ ctx->conn_type = SILC_SOCKET_TYPE_SERVER;
+
+ new_server->server_type = SILC_BACKUP_ROUTER;
+ }
+
+ /* Check whether this connection is to be our primary router connection
+ if we do not already have the primary route. */
+ if (server->standalone && ctx->conn_type == SILC_SOCKET_TYPE_ROUTER) {
+ if (silc_server_config_is_primary_route(server->config) &&
+ !conn->initiator)
+ break;
+
SILC_LOG_DEBUG(("We are not standalone server anymore"));
server->standalone = FALSE;
+ if (!server->id_entry->router) {
+ server->id_entry->router = id_entry;
+ server->router = id_entry;
+ }
}
+
break;
}
default:
--- /dev/null
- sock = silc_net_create_connection(server->config->listen_port->local_ip,
+/*
+
+ server_backup.c
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 2001 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 "serverincludes.h"
+#include "server_internal.h"
+
+SILC_TASK_CALLBACK(silc_server_protocol_backup_done);
+
+/* Backup router */
+typedef struct {
+ SilcServerEntry server;
+ SilcIDIP ip;
+ uint16 port;
+ bool local;
+} SilcServerBackupEntry;
+
+/* Holds IP address and port of the primary router that was replaced
+ by backup router. */
+typedef struct {
+ SilcIDIP ip;
+ uint16 port;
+ SilcServerEntry server; /* Backup router that replaced the primary */
+} SilcServerBackupReplaced;
+
+/* Backup context */
+struct SilcServerBackupStruct {
+ SilcServerBackupEntry *servers;
+ uint32 servers_count;
+ SilcServerBackupReplaced **replaced;
+ uint32 replaced_count;
+};
+
+typedef struct {
+ uint8 session;
+ bool connected;
+ SilcServerEntry server_entry;
+} SilcServerBackupProtocolSession;
+
+/* Backup resuming protocol context */
+typedef struct {
+ SilcServer server;
+ SilcSocketConnection sock;
+ bool responder;
+ uint8 type;
+ uint8 session;
+ SilcServerBackupProtocolSession *sessions;
+ uint32 sessions_count;
+ long start;
+} *SilcServerBackupProtocolContext;
+
+/* Adds the `backup_server' to be one of our backup router. This can be
+ called multiple times to set multiple backup routers. The `ip' and `port'
+ is the IP and port that the `backup_router' will replace if the `ip'
+ will become unresponsive. If `local' is TRUE then the `backup_server' is
+ in the local cell, if FALSE it is in some other cell. */
+
+void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
+ const char *ip, int port, bool local)
+{
+ int i;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!ip)
+ return;
+
+ if (!server->backup)
+ server->backup = silc_calloc(1, sizeof(*server->backup));
+
+ for (i = 0; i < server->backup->servers_count; i++) {
+ if (!server->backup->servers[i].server) {
+ server->backup->servers[i].server = backup_server;
+ server->backup->servers[i].local = local;
+ memset(server->backup->servers[i].ip.data, 0,
+ sizeof(server->backup->servers[i].ip.data));
+ silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
+ sizeof(server->backup->servers[i].ip.data));
+ //server->backup->servers[i].port = port;
+ return;
+ }
+ }
+
+ i = server->backup->servers_count;
+ server->backup->servers = silc_realloc(server->backup->servers,
+ sizeof(*server->backup->servers) *
+ (i + 1));
+ server->backup->servers[i].server = backup_server;
+ server->backup->servers[i].local = local;
+ memset(server->backup->servers[i].ip.data, 0,
+ sizeof(server->backup->servers[i].ip.data));
+ silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
+ sizeof(server->backup->servers[i].ip.data));
+ //server->backup->servers[i].port = server_id->port;
+ server->backup->servers_count++;
+}
+
+/* Returns backup router for IP and port in `replacing' or NULL if there
+ does not exist backup router. */
+
+SilcServerEntry silc_server_backup_get(SilcServer server,
+ SilcServerID *server_id)
+{
+ int i;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!server->backup)
+ return NULL;
+
+ for (i = 0; i < server->backup->servers_count; i++) {
+ SILC_LOG_HEXDUMP(("IP"), server_id->ip.data, 16);
+ SILC_LOG_HEXDUMP(("IP"), server->backup->servers[i].ip.data, 16);
+ if (server->backup->servers[i].server &&
+ !memcmp(&server->backup->servers[i].ip, &server_id->ip.data,
+ sizeof(server_id->ip.data)))
+ return server->backup->servers[i].server;
+ }
+
+ return NULL;
+}
+
+/* Deletes the backup server `server_entry'. */
+void silc_server_backup_del(SilcServer server, SilcServerEntry server_entry)
+{
+ int i;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!server->backup)
+ return ;
+
+ for (i = 0; i < server->backup->servers_count; i++) {
+ if (server->backup->servers[i].server == server_entry) {
+ server->backup->servers[i].server = NULL;
+ return;
+ }
+ }
+}
+
+/* Marks the IP address and port from the `server_id' as being replaced
+ by backup router indicated by the `server'. If the router connects at
+ a later time we can check whether it has been replaced by an backup
+ router. */
+
+void silc_server_backup_replaced_add(SilcServer server,
+ SilcServerID *server_id,
+ SilcServerEntry server_entry)
+{
+ int i;
+ SilcServerBackupReplaced *r = silc_calloc(1, sizeof(*r));;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!server->backup)
+ server->backup = silc_calloc(1, sizeof(*server->backup));
+ if (!server->backup->replaced) {
+ server->backup->replaced =
+ silc_calloc(1, sizeof(*server->backup->replaced));
+ server->backup->replaced_count = 1;
+ }
+
+ SILC_LOG_DEBUG(("********************************"));
+ SILC_LOG_DEBUG(("Replaced added"));
+
+ memcpy(&r->ip, &server_id->ip, sizeof(server_id->ip));
+ //r->port = server_id->port;
+ r->server = server_entry;
+
+ for (i = 0; i < server->backup->replaced_count; i++) {
+ if (!server->backup->replaced[i]) {
+ server->backup->replaced[i] = r;
+ return;
+ }
+ }
+
+ i = server->backup->replaced_count;
+ server->backup->replaced = silc_realloc(server->backup->replaced,
+ sizeof(*server->backup->replaced) *
+ (i + 1));
+ server->backup->replaced[i] = r;
+ server->backup->replaced_count++;
+}
+
+/* Checks whether the IP address and port from the `server_id' has been
+ replaced by an backup router. If it has been then this returns TRUE
+ and the bacup router entry to the `server' pointer if non-NULL. Returns
+ FALSE if the router is not replaced by backup router. */
+
+bool silc_server_backup_replaced_get(SilcServer server,
+ SilcServerID *server_id,
+ SilcServerEntry *server_entry)
+{
+ int i;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ SILC_LOG_DEBUG(("*************************************"));
+
+ if (!server->backup || !server->backup->replaced)
+ return FALSE;
+
+ for (i = 0; i < server->backup->replaced_count; i++) {
+ if (!server->backup->replaced[i])
+ continue;
+ SILC_LOG_HEXDUMP(("IP"), server_id->ip.data, server_id->ip.data_len);
+ SILC_LOG_HEXDUMP(("IP"), server->backup->replaced[i]->ip.data,
+ server->backup->replaced[i]->ip.data_len);
+ if (!memcmp(&server->backup->replaced[i]->ip, &server_id->ip.data,
+ sizeof(server_id->ip.data))) {
+ if (server_entry)
+ *server_entry = server->backup->replaced[i]->server;
+ SILC_LOG_DEBUG(("REPLACED"));
+ return TRUE;
+ }
+ }
+
+ SILC_LOG_DEBUG(("NOT REPLACED"));
+ return FALSE;
+}
+
+/* Deletes a replaced host by the set `server_entry. */
+
+void silc_server_backup_replaced_del(SilcServer server,
+ SilcServerEntry server_entry)
+{
+ int i;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!server->backup || !server->backup->replaced)
+ return;
+
+ for (i = 0; i < server->backup->replaced_count; i++) {
+ if (!server->backup->replaced[i])
+ continue;
+ if (server->backup->replaced[i]->server == server_entry) {
+ silc_free(server->backup->replaced[i]);
+ server->backup->replaced[i] = NULL;
+ return;
+ }
+ }
+}
+
+/* Broadcast the received packet indicated by `packet' to all of our backup
+ routers. All router wide information is passed using broadcast packets.
+ That is why all backup routers need to get this data too. It is expected
+ that the caller already knows that the `packet' is broadcast packet. */
+
+void silc_server_backup_broadcast(SilcServer server,
+ SilcSocketConnection sender,
+ SilcPacketContext *packet)
+{
+ SilcServerEntry backup;
+ SilcSocketConnection sock;
+ SilcBuffer buffer;
+ SilcIDListData idata;
+ int i;
+
+ if (!server->backup || server->server_type != SILC_ROUTER)
+ return;
+
+ SILC_LOG_DEBUG(("Broadcasting received packet to backup routers"));
+
+ buffer = packet->buffer;
+ silc_buffer_push(buffer, buffer->data - buffer->head);
+
+ for (i = 0; i < server->backup->servers_count; i++) {
+ backup = server->backup->servers[i].server;
+
+ if (!backup || backup->connection == sender ||
+ server->backup->servers[i].local == FALSE)
+ continue;
+
+ idata = (SilcIDListData)backup;
+ sock = backup->connection;
+
+ silc_packet_send_prepare(sock, 0, 0, buffer->len);
+ silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
+ silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
+ sock->outbuf, sock->outbuf->len);
+
+ SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_server_packet_send_real(server, sock, FALSE);
+ }
+}
+
+/* A generic routine to send data to all backup routers. If the `sender'
+ is provided it will indicate the original sender of the packet and the
+ packet won't be resent to that entity. The `data' is the data that will
+ be assembled to packet context before sending. The packet will be
+ encrypted this function. If the `force_send' is TRUE the data is sent
+ immediately and not put to queue. If `local' is TRUE then the packet
+ will be sent only to local backup routers inside the cell. If false the
+ packet can go from one cell to the other. This function has no effect
+ if there are no any backup routers. */
+
+void silc_server_backup_send(SilcServer server,
+ SilcServerEntry sender,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ unsigned char *data,
+ uint32 data_len,
+ bool force_send,
+ bool local)
+{
+ SilcServerEntry backup;
+ SilcSocketConnection sock;
+ int i;
+
+ if (!server->backup || server->server_type != SILC_ROUTER)
+ return;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ for (i = 0; i < server->backup->servers_count; i++) {
+ backup = server->backup->servers[i].server;
+ if (!backup)
+ continue;
+
+ if (sender == backup)
+ continue;
+
+ if (local && server->backup->servers[i].local == FALSE)
+ continue;
+
+ sock = backup->connection;
+ silc_server_packet_send(server, backup->connection, type, flags,
+ data, data_len, force_send);
+ }
+}
+
+/* Same as silc_server_backup_send but sets a specific Destination ID to
+ the packet. The Destination ID is indicated by the `dst_id' and the
+ ID type `dst_id_type'. For example, packets destined to channels must
+ be sent using this function. */
+
+void silc_server_backup_send_dest(SilcServer server,
+ SilcServerEntry sender,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ void *dst_id,
+ SilcIdType dst_id_type,
+ unsigned char *data,
+ uint32 data_len,
+ bool force_send,
+ bool local)
+{
+ SilcServerEntry backup;
+ SilcSocketConnection sock;
+ int i;
+
+ if (!server->backup || server->server_type != SILC_ROUTER)
+ return;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ for (i = 0; i < server->backup->servers_count; i++) {
+ backup = server->backup->servers[i].server;
+ if (!backup)
+ continue;
+
+ if (sender == backup)
+ continue;
+
+ if (local && server->backup->servers[i].local == FALSE)
+ continue;
+
+ sock = backup->connection;
+ silc_server_packet_send_dest(server, backup->connection, type, flags,
+ dst_id, dst_id_type, data, data_len,
+ force_send);
+ }
+}
+
+/* Processes incoming RESUME_ROUTER packet. This can give the packet
+ for processing to the protocol handler or allocate new protocol if
+ start command is received. */
+
+void silc_server_backup_resume_router(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ uint8 type, session;
+ SilcServerBackupProtocolContext ctx;
+ int i, ret;
+
+ if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+ sock->type == SILC_SOCKET_TYPE_UNKNOWN)
+ return;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ ret = silc_buffer_unformat(packet->buffer,
+ SILC_STR_UI_CHAR(&type),
+ SILC_STR_UI_CHAR(&session),
+ SILC_STR_END);
+ if (ret < 0)
+ return;
+
+ /* Activate the protocol for this socket if necessary */
+ if ((type == SILC_SERVER_BACKUP_RESUMED ||
+ type == SILC_SERVER_BACKUP_RESUMED_GLOBAL) &&
+ sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol &&
+ ((SilcIDListData)sock->user_data)->status &
+ SILC_IDLIST_STATUS_DISABLED) {
+ SilcServerEntry backup_router;
+
+ if (silc_server_backup_replaced_get(server,
+ ((SilcServerEntry)sock->
+ user_data)->id,
+ &backup_router)) {
+ SilcSocketConnection bsock =
+ (SilcSocketConnection)backup_router->connection;
+ if (bsock->protocol && bsock->protocol->protocol &&
+ bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
+ sock->protocol = bsock->protocol;
+ ctx = sock->protocol->context;
+ ctx->sock = sock;
+ }
+ }
+ }
+
+ /* If the backup resuming protocol is active then process the packet
+ in the protocol. */
+ if (sock->protocol && sock->protocol->protocol &&
+ sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
+ ctx = sock->protocol->context;
+ ctx->type = type;
+
+ SILC_LOG_DEBUG(("********************************"));
+ SILC_LOG_DEBUG(("Continuing protocol, type %d", type));
+
+ if (type != SILC_SERVER_BACKUP_RESUMED &&
+ type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
+ for (i = 0; i < ctx->sessions_count; i++) {
+ if (session == ctx->sessions[i].session) {
+ ctx->session = session;
+ silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+ return;
+ }
+ }
+ } else {
+ silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+ return;
+ }
+
+ SILC_LOG_DEBUG(("Bad resume router packet"));
+ return;
+ }
+
+ /* We don't have protocol active. If we are router and the packet is
+ coming from our primary router then lets check whether it means we've
+ been replaced by an backup router in my cell. This is usually received
+ immediately after we've connected to our primary router. */
+
+ if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
+ server->router == sock->user_data &&
+ type == SILC_SERVER_BACKUP_REPLACED) {
+ /* We have been replaced by an backup router in our cell. We must
+ mark our primary router connection disabled since we are not allowed
+ to use it at this moment. */
+ SilcIDListData idata = (SilcIDListData)sock->user_data;
+
+ SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
+ "wait until backup resuming protocol is executed"));
+
+ SILC_LOG_DEBUG(("We are replaced by an backup router in this cell"));
+ idata->status |= SILC_IDLIST_STATUS_DISABLED;
+ return;
+ }
+
+ if (type == SILC_SERVER_BACKUP_START ||
+ type == SILC_SERVER_BACKUP_START_GLOBAL) {
+ /* We have received a start for resuming protocol. */
+ SilcServerBackupProtocolContext proto_ctx;
+
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->server = server;
+ proto_ctx->sock = sock;
+ proto_ctx->responder = TRUE;
+ proto_ctx->type = type;
+ proto_ctx->session = session;
+ proto_ctx->start = time(0);
+
+ SILC_LOG_DEBUG(("Starting backup resuming protocol as responder"));
+
+ /* Run the backup resuming protocol */
+ silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
+ &sock->protocol, proto_ctx,
+ silc_server_protocol_backup_done);
+ silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+ }
+}
+
+/* Timeout task callback to connect to remote router */
+
+SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
+{
+ SilcServerConnection sconn = (SilcServerConnection)context;
+ SilcServer server = sconn->server;
+ int sock;
+
+ SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
+ sconn->remote_port));
+
+ /* Connect to remote host */
- SilcServerConfigSectionServerConnection *primary;
++ sock = silc_net_create_connection(server->config->server_info->server_ip,
+ sconn->remote_port,
+ sconn->remote_host);
+ if (sock < 0) {
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_backup_connect_to_router,
+ context, 5, 0, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ return;
+ }
+
+ /* Continue with key exchange protocol */
+ silc_server_start_key_exchange(server, sconn, sock);
+}
+
+/* Constantly tries to reconnect to a primary router indicated by the
+ `ip' and `port'. The `connected' callback will be called when the
+ connection is created. */
+
+void silc_server_backup_reconnect(SilcServer server,
+ const char *ip, uint16 port,
+ SilcServerConnectRouterCallback callback,
+ void *context)
+{
+ SilcServerConnection sconn;
+
+ sconn = silc_calloc(1, sizeof(*sconn));
+ sconn->server = server;
+ sconn->remote_host = strdup(ip);
+ sconn->remote_port = port;
+ sconn->callback = callback;
+ sconn->callback_context = context;
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_backup_connect_to_router,
+ sconn, 1, 0, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+}
+
+SILC_TASK_CALLBACK(silc_server_backup_connected_later)
+{
+ SilcServerBackupProtocolContext proto_ctx =
+ (SilcServerBackupProtocolContext)context;
+ SilcServer server = proto_ctx->server;
+ SilcSocketConnection sock = proto_ctx->sock;
+
+ SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
+
+ /* Run the backup resuming protocol */
+ silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
+ &sock->protocol, proto_ctx,
+ silc_server_protocol_backup_done);
+ silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+}
+
+/* Called when we've established connection back to our primary router
+ when we've acting as backup router and have replaced the primary router
+ in the cell. This function will start the backup resuming protocol. */
+
+void silc_server_backup_connected(SilcServer server,
+ SilcServerEntry server_entry,
+ void *context)
+{
+ SilcServerBackupProtocolContext proto_ctx;
+ SilcSocketConnection sock = (SilcSocketConnection)server_entry->connection;
+
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->server = server;
+ proto_ctx->sock = sock;
+ proto_ctx->responder = FALSE;
+ proto_ctx->type = SILC_SERVER_BACKUP_START;
+ proto_ctx->start = time(0);
+
+ /* Start through scheduler */
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_backup_connected_later,
+ proto_ctx, 0, 1,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+}
+
+/* Called when normal server has connected to its primary router after
+ backup router has sent the START packet in reusming protocol. We will
+ move the protocol context from the backup router connection to the
+ primary router. */
+
+static void silc_server_backup_connect_primary(SilcServer server,
+ SilcServerEntry server_entry,
+ void *context)
+{
+ SilcSocketConnection backup_router = (SilcSocketConnection)context;
+ SilcSocketConnection sock = (SilcSocketConnection)server_entry->connection;
+ SilcIDListData idata = (SilcIDListData)server_entry;
+ SilcServerBackupProtocolContext ctx =
+ (SilcServerBackupProtocolContext)backup_router->protocol->context;
+ SilcBuffer buffer;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ SILC_LOG_DEBUG(("********************************"));
+ SILC_LOG_DEBUG(("Sending CONNECTED packet, session %d", ctx->session));
+
+ /* Send the CONNECTED packet back to the backup router. */
+ buffer = silc_buffer_alloc(2);
+ silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+ silc_buffer_format(buffer,
+ SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
+ SILC_STR_UI_CHAR(ctx->session),
+ SILC_STR_END);
+ silc_server_packet_send(server, backup_router,
+ SILC_PACKET_RESUME_ROUTER, 0,
+ buffer->data, buffer->len, FALSE);
+ silc_buffer_free(buffer);
+
+ /* The primary connection is disabled until it sends the RESUMED packet
+ to us. */
+ idata->status |= SILC_IDLIST_STATUS_DISABLED;
+
+ /* Move this protocol context from this backup router connection to
+ the primary router connection since it will send the subsequent
+ packets in this protocol. We don't talk with backup router
+ anymore. */
+ sock->protocol = backup_router->protocol;
+ ctx->sock = (SilcSocketConnection)server_entry->connection;
+ backup_router->protocol = NULL;
+}
+
+SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcServerBackupProtocolContext ctx = protocol->context;
+ SilcServer server = ctx->server;
+ SilcBuffer packet;
+ int i;
+
+ for (i = 0; i < ctx->sessions_count; i++)
+ if (ctx->sessions[i].server_entry == ctx->sock->user_data)
+ ctx->session = ctx->sessions[i].session;
+
+ /* We've received all the CONNECTED packets and now we'll send the
+ ENDING packet to the new primary router. */
+ packet = silc_buffer_alloc(2);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
+ SILC_STR_UI_CHAR(ctx->session),
+ SILC_STR_END);
+ silc_server_packet_send(server, ctx->sock,
+ SILC_PACKET_RESUME_ROUTER, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+
+ protocol->state = SILC_PROTOCOL_STATE_END;
+}
+
+/* Resume protocol with RESUME_ROUTER packet:
+
+ SILC_PACKET_RESUME_ROUTER:
+
+ <uint8 type> <uint8 Session ID>
+
+ <type> = the protocol opcode
+ <Session ID> = Identifier for this packet and any subsequent reply
+ packets must include this identifier.
+
+ Types:
+
+ 1 = To router: Comensing backup resuming protocol. This will
+ indicate that the sender is backup router acting as primary
+ and the receiver is primary router that has been replaced by
+ the backup router.
+
+ To server. Comensing backup resuming protocol. This will
+ indicate that the sender is backup router and the receiver
+ must reconnect to the real primary router of the cell.
+
+ 2 = To Router: Comesning backup resuming protocol in another
+ cell. The receiver will connect to its primary router
+ (the router that is now online again) but will not use
+ the link. If the receiver is not configured to connect
+ to any router it does as locally configured. The sender
+ is always backup router.
+
+ To server: this is never sent to server.
+
+ 3 = To backup router: Sender is normal server or router and it
+ tells to backup router that they have connected to the
+ primary router. Backup router never sends this type.
+
+ 4 = To router: Ending backup resuming protocol. This is sent
+ to the real primary router to tell that it can take over
+ the task as being primary router.
+
+ To server: same as sending for router.
+
+ Backup router sends this also to the primary route but only
+ after it has sent them to normal servers and has purged all
+ traffic coming from normal servers.
+
+ 5 = To router: Sender is the real primary router after it has
+ received type 4 from backup router. To tell that it is again
+ primary router of the cell.
+
+ 20 = To router: This is sent only when router is connecting to
+ another router and has been replaced by an backup router.
+ The sender knows that the connectee has been replaced.
+
+ */
+
+/* Backup resuming protocol. This protocol is executed when the primary
+ router wants to resume its position as being primary router. */
+
+SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcServerBackupProtocolContext ctx = protocol->context;
+ SilcServer server = ctx->server;
+ SilcBuffer packet;
+ SilcIDCacheList list;
+ SilcIDCacheEntry id_cache;
+ SilcServerEntry server_entry;
+ int i;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
+ protocol->state = SILC_PROTOCOL_STATE_START;
+
+ SILC_LOG_DEBUG(("State=%d", protocol->state));
+
+ switch(protocol->state) {
+ case SILC_PROTOCOL_STATE_START:
+ if (ctx->responder == FALSE) {
+ /* Initiator of the protocol. We are backup router */
+
+ packet = silc_buffer_alloc(2);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+
+ SILC_LOG_DEBUG(("********************************"));
+ SILC_LOG_DEBUG(("Sending START packets"));
+
+ /* Send the START packet to primary router and normal servers. */
+ if (silc_idcache_get_all(server->local_list->servers, &list)) {
+ if (silc_idcache_list_first(list, &id_cache)) {
+ while (id_cache) {
+ server_entry = (SilcServerEntry)id_cache->context;
+ if (!server_entry || (server_entry == server->id_entry) ||
+ !server_entry->connection || !server_entry->data.send_key ||
+ (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ else
+ continue;
+ }
+
+ ctx->sessions = silc_realloc(ctx->sessions,
+ sizeof(*ctx->sessions) *
+ (ctx->sessions_count + 1));
+ ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
+ ctx->sessions[ctx->sessions_count].connected = FALSE;
+ ctx->sessions[ctx->sessions_count].server_entry = server_entry;
+
+ SILC_LOG_DEBUG(("********************************"));
+ SILC_LOG_DEBUG(("START (local) for session %d",
+ ctx->sessions_count));
+
+ /* This connection is performing this protocol too now */
+ ((SilcSocketConnection)server_entry->connection)->protocol =
+ protocol;
+
+ if (server_entry->server_type == SILC_ROUTER)
+ packet->data[0] = SILC_SERVER_BACKUP_START;
+ else
+ packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
+ packet->data[1] = ctx->sessions_count;
+ silc_server_packet_send(server, server_entry->connection,
+ SILC_PACKET_RESUME_ROUTER, 0,
+ packet->data, packet->len, FALSE);
+ ctx->sessions_count++;
+
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ }
+
+ silc_idcache_list_free(list);
+ }
+
+ if (silc_idcache_get_all(server->global_list->servers, &list)) {
+ if (silc_idcache_list_first(list, &id_cache)) {
+ while (id_cache) {
+ server_entry = (SilcServerEntry)id_cache->context;
+ if (!server_entry || (server_entry == server->id_entry) ||
+ !server_entry->connection || !server_entry->data.send_key ||
+ (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ else
+ continue;
+ }
+
+ ctx->sessions = silc_realloc(ctx->sessions,
+ sizeof(*ctx->sessions) *
+ (ctx->sessions_count + 1));
+ ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
+ ctx->sessions[ctx->sessions_count].connected = FALSE;
+ ctx->sessions[ctx->sessions_count].server_entry = server_entry;
+
+ SILC_LOG_DEBUG(("********************************"));
+ SILC_LOG_DEBUG(("START (global) for session %d",
+ ctx->sessions_count));
+
+ /* This connection is performing this protocol too now */
+ ((SilcSocketConnection)server_entry->connection)->protocol =
+ protocol;
+
+ if (server_entry->server_type == SILC_ROUTER)
+ packet->data[0] = SILC_SERVER_BACKUP_START;
+ else
+ packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
+ packet->data[1] = ctx->sessions_count;
+ silc_server_packet_send(server, server_entry->connection,
+ SILC_PACKET_RESUME_ROUTER, 0,
+ packet->data, packet->len, FALSE);
+ ctx->sessions_count++;
+
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ }
+
+ silc_idcache_list_free(list);
+ }
+
+ silc_buffer_free(packet);
+
+ /* Announce all of our information */
+ silc_server_announce_servers(server, TRUE, 0, ctx->sock);
+ silc_server_announce_clients(server, 0, ctx->sock);
+ silc_server_announce_channels(server, 0, ctx->sock);
+
+ protocol->state++;
+ } else {
+ /* Responder of the protocol. */
++ SilcServerConfigSectionRouter *primary;
+
+ /* We should have received START or START_GLOBAL packet */
+ if (ctx->type != SILC_SERVER_BACKUP_START &&
+ ctx->type != SILC_SERVER_BACKUP_START_GLOBAL) {
+ SILC_LOG_DEBUG(("Bad resume router packet"));
+ break;
+ }
+
+ SILC_LOG_DEBUG(("********************************"));
+ SILC_LOG_DEBUG(("Received START packet, reconnecting to router"));
+
+ /* Connect to the primary router that was down that is now supposed
+ to be back online. We send the CONNECTED packet after we've
+ established the connection to the primary router. */
+ primary = silc_server_config_get_primary_router(server->config);
+ if (primary && server->backup_primary) {
+ silc_server_backup_reconnect(server,
+ primary->host, primary->port,
+ silc_server_backup_connect_primary,
+ ctx->sock);
+ } else {
+ /* Nowhere to connect just return the CONNECTED packet */
+
+ SILC_LOG_DEBUG(("********************************"));
+ SILC_LOG_DEBUG(("Sending CONNECTED packet, session %d", ctx->session));
+
+ /* Send the CONNECTED packet back to the backup router. */
+ packet = silc_buffer_alloc(2);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
+ SILC_STR_UI_CHAR(ctx->session),
+ SILC_STR_END);
+ silc_server_packet_send(server, ctx->sock,
+ SILC_PACKET_RESUME_ROUTER, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+ }
+
+ if (server->server_type == SILC_ROUTER &&
+ (!server->router ||
+ server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
+ protocol->state++;
+ else
+ protocol->state = SILC_PROTOCOL_STATE_END;
+
+ ctx->sessions = silc_realloc(ctx->sessions,
+ sizeof(*ctx->sessions) *
+ (ctx->sessions_count + 1));
+ ctx->sessions[ctx->sessions_count].session = ctx->session;
+ ctx->sessions_count++;
+ }
+ break;
+
+ case 2:
+ if (ctx->responder == FALSE) {
+ /* Initiator */
+
+ /* We should have received CONNECTED packet */
+ if (ctx->type != SILC_SERVER_BACKUP_CONNECTED) {
+ SILC_LOG_DEBUG(("Bad resume router packet"));
+ break;
+ }
+
+ SILC_LOG_DEBUG(("********************************"));
+ SILC_LOG_DEBUG(("Received CONNECTED packet, session %d", ctx->session));
+
+ for (i = 0; i < ctx->sessions_count; i++) {
+ if (ctx->sessions[i].session == ctx->session) {
+ ctx->sessions[i].connected = TRUE;
+ break;
+ }
+ }
+
+ for (i = 0; i < ctx->sessions_count; i++) {
+ if (!ctx->sessions[i].connected)
+ return;
+ }
+
+ SILC_LOG_DEBUG(("********************************"));
+ SILC_LOG_DEBUG(("Sending ENDING packet to primary"));
+
+ /* Send with a timeout */
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_backup_send_resumed,
+ protocol, 1, 0, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ return;
+ } else {
+ /* Responder */
+
+ /* We should have been received ENDING packet */
+ if (ctx->type != SILC_SERVER_BACKUP_ENDING) {
+ SILC_LOG_DEBUG(("Bad resume router packet"));
+ break;
+ }
+
+ SILC_LOG_DEBUG(("********************************"));
+ SILC_LOG_DEBUG(("Received ENDING packet, sending RESUMED packets"));
+
+ /* This state is received by the primary router but also servers
+ and perhaps other routers so check that if we are the primary
+ router of the cell then start sending RESUMED packets. If we
+ are normal server or one of those other routers then procede
+ to next state. */
+ if (server->router &&
+ !(server->router->data.status & SILC_IDLIST_STATUS_DISABLED) &&
+ silc_server_config_is_primary_route(server->config)) {
+ /* We'll wait for RESUMED packet */
+ protocol->state = SILC_PROTOCOL_STATE_END;
+ break;
+ }
+
+ /* Switch announced informations to our primary router of using the
+ backup router. */
+ silc_server_update_servers_by_server(server, ctx->sock->user_data,
+ server->router);
+ silc_server_update_clients_by_server(server, ctx->sock->user_data,
+ server->router, TRUE, FALSE);
+ if (server->server_type == SILC_SERVER)
+ silc_server_update_channels_by_server(server, ctx->sock->user_data,
+ server->router);
+
+ packet = silc_buffer_alloc(2);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+
+ /* We are the primary router, start sending RESUMED packets. */
+ if (silc_idcache_get_all(server->local_list->servers, &list)) {
+ if (silc_idcache_list_first(list, &id_cache)) {
+ while (id_cache) {
+ server_entry = (SilcServerEntry)id_cache->context;
+ if (!server_entry || (server_entry == server->id_entry) ||
+ !server_entry->connection || !server_entry->data.send_key) {
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ else
+ continue;
+ }
+
+ SILC_LOG_DEBUG(("********************************"));
+ SILC_LOG_DEBUG(("RESUMED packet (local)"));
+
+ server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+
+ /* This connection is performing this protocol too now */
+ ((SilcSocketConnection)server_entry->connection)->protocol =
+ protocol;
+
+ if (server_entry->server_type == SILC_ROUTER)
+ packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
+ else
+ packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
+ silc_server_packet_send(server, server_entry->connection,
+ SILC_PACKET_RESUME_ROUTER, 0,
+ packet->data, packet->len, FALSE);
+
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ }
+
+ silc_idcache_list_free(list);
+ }
+
+ if (silc_idcache_get_all(server->global_list->servers, &list)) {
+ if (silc_idcache_list_first(list, &id_cache)) {
+ while (id_cache) {
+ server_entry = (SilcServerEntry)id_cache->context;
+ if (!server_entry || (server_entry == server->id_entry) ||
+ !server_entry->connection || !server_entry->data.send_key) {
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ else
+ continue;
+ }
+
+ SILC_LOG_DEBUG(("********************************"));
+ SILC_LOG_DEBUG(("RESUMED packet (global)"));
+
+ server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+
+ /* This connection is performing this protocol too now */
+ ((SilcSocketConnection)server_entry->connection)->protocol =
+ protocol;
+
+ if (server_entry->server_type == SILC_ROUTER)
+ packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
+ else
+ packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
+ silc_server_packet_send(server, server_entry->connection,
+ SILC_PACKET_RESUME_ROUTER, 0,
+ packet->data, packet->len, FALSE);
+
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ }
+
+ silc_idcache_list_free(list);
+ }
+
+ silc_buffer_free(packet);
+
+ SILC_LOG_INFO(("We are now the primary router of our cell again"));
+
+ /* For us this is the end of this protocol. */
+ if (protocol->final_callback)
+ silc_protocol_execute_final(protocol, server->schedule);
+ else
+ silc_protocol_free(protocol);
+ }
+ break;
+
+ case SILC_PROTOCOL_STATE_END:
+ {
+ SilcIDListData idata;
+ SilcServerEntry router, backup_router;
+
+ /* We should have been received RESUMED packet from our primary
+ router. */
+ if (ctx->type != SILC_SERVER_BACKUP_RESUMED &&
+ ctx->type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
+ SILC_LOG_DEBUG(("Bad resume router packet"));
+ break;
+ }
+
+ SILC_LOG_DEBUG(("********************************"));
+ SILC_LOG_DEBUG(("Received RESUMED packet"));
+
+ /* We have now new primary router. All traffic goes there from now on. */
+ if (server->backup_router)
+ server->server_type = SILC_BACKUP_ROUTER;
+
+ router = (SilcServerEntry)ctx->sock->user_data;
+ if (silc_server_backup_replaced_get(server, router->id,
+ &backup_router)) {
+
+ if (backup_router == server->router) {
+ server->id_entry->router = router;
+ server->router = router;
+ SILC_LOG_INFO(("Switching back to primary router %s",
+ server->router->server_name));
+ SILC_LOG_DEBUG(("Switching back to primary router %s",
+ server->router->server_name));
+ idata = (SilcIDListData)server->router;
+ idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
+ } else {
+ SILC_LOG_INFO(("Resuming the use of router %s",
+ router->server_name));
+ SILC_LOG_DEBUG(("Resuming the use of router %s",
+ router->server_name));
+ idata = (SilcIDListData)router;
+ idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
+ }
+
+ /* Update the client entries of the backup router to the new
+ router */
+ silc_server_update_servers_by_server(server, backup_router, router);
+ silc_server_update_clients_by_server(server, backup_router,
+ router, TRUE, FALSE);
+ if (server->server_type == SILC_SERVER)
+ silc_server_update_channels_by_server(server, backup_router, router);
+ silc_server_backup_replaced_del(server, backup_router);
+ silc_server_backup_add(server, backup_router,
+ ctx->sock->ip, ctx->sock->port,
+ backup_router->server_type != SILC_ROUTER ?
+ TRUE : FALSE);
+
+ /* Announce all of our information to the router. */
+ if (server->server_type == SILC_ROUTER)
+ silc_server_announce_servers(server, FALSE, 0, router->connection);
+
+ /* Announce our clients and channels to the router */
+ silc_server_announce_clients(server, 0, router->connection);
+ silc_server_announce_channels(server, 0, router->connection);
+ }
+
+ /* Protocol has ended, call the final callback */
+ if (protocol->final_callback)
+ silc_protocol_execute_final(protocol, server->schedule);
+ else
+ silc_protocol_free(protocol);
+ }
+ break;
+
+ case SILC_PROTOCOL_STATE_ERROR:
+ /* Protocol has ended, call the final callback */
+ if (protocol->final_callback)
+ silc_protocol_execute_final(protocol, server->schedule);
+ else
+ silc_protocol_free(protocol);
+ break;
+
+ case SILC_PROTOCOL_STATE_FAILURE:
+ /* Protocol has ended, call the final callback */
+ if (protocol->final_callback)
+ silc_protocol_execute_final(protocol, server->schedule);
+ else
+ silc_protocol_free(protocol);
+ break;
+
+ case SILC_PROTOCOL_STATE_UNKNOWN:
+ break;
+ }
+}
+
+SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcServerBackupProtocolContext ctx = protocol->context;
+ SilcServer server = ctx->server;
+ SilcServerEntry server_entry;
+ SilcSocketConnection sock;
+ SilcIDCacheList list;
+ SilcIDCacheEntry id_cache;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+ protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
+ SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
+ }
+
+ /* Remove this protocol from all server entries that has it */
+ if (silc_idcache_get_all(server->local_list->servers, &list)) {
+ if (silc_idcache_list_first(list, &id_cache)) {
+ while (id_cache) {
+ server_entry = (SilcServerEntry)id_cache->context;
+ sock = (SilcSocketConnection)server_entry->connection;
+
+ if (sock->protocol == protocol) {
+ sock->protocol = NULL;
+
+ if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
+ server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+ }
+
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ }
+ silc_idcache_list_free(list);
+ }
+
+ if (silc_idcache_get_all(server->global_list->servers, &list)) {
+ if (silc_idcache_list_first(list, &id_cache)) {
+ while (id_cache) {
+ server_entry = (SilcServerEntry)id_cache->context;
+ sock = (SilcSocketConnection)server_entry->connection;
+
+ if (sock->protocol == protocol) {
+ sock->protocol = NULL;
+
+ if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
+ server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+ }
+
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ }
+ silc_idcache_list_free(list);
+ }
+
+ if (ctx->sock->protocol)
+ ctx->sock->protocol = NULL;
+ silc_protocol_free(protocol);
+ silc_free(ctx->sessions);
+ silc_free(ctx);
+}
serverconfig.c
-- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
++ Author: Johnny Mnemonic <johnny@themnemonic.org>
-- Copyright (C) 1997 - 2000 Pekka Riikonen
++ Copyright (C) 1997 - 2002 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; either version 2 of the License, or
(at your option) any later version.
--
++
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
#include "serverincludes.h"
#include "server_internal.h"
- SilcServerConfigSection silc_server_config_sections[] = {
- { "[Cipher]",
- SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER, 4 },
- { "[PKCS]",
- SILC_CONFIG_SERVER_SECTION_TYPE_PKCS, 1 },
- { "[Hash]",
- SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION, 4 },
- { "[hmac]",
- SILC_CONFIG_SERVER_SECTION_TYPE_HMAC, 3 },
- { "[ServerKeys]",
- SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_KEYS, 2 },
- { "[ServerInfo]",
- SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO, 4 },
- { "[AdminInfo]",
- SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO, 4 },
- { "[ListenPort]",
- SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT, 3 },
- { "[Identity]",
- SILC_CONFIG_SERVER_SECTION_TYPE_IDENTITY, 2 },
- { "[Logging]",
- SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING, 3 },
- { "[ConnectionClass]",
- SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS, 4 },
- { "[ClientConnection]",
- SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION, 5 },
- { "[ServerConnection]",
- SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION, 6 },
- { "[RouterConnection]",
- SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION, 7 },
- { "[AdminConnection]",
- SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION, 5 },
- { "[DenyConnection]",
- SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION, 3 },
- { "[motd]",
- SILC_CONFIG_SERVER_SECTION_TYPE_MOTD, 1 },
- { "[pid]",
- SILC_CONFIG_SERVER_SECTION_TYPE_PID, 1},
-
- { NULL, SILC_CONFIG_SERVER_SECTION_TYPE_NONE, 0 }
- };
-/* XXX
- All possible configuration sections for SILC server.
--
- /* Allocates a new configuration object, opens configuration file and
- parses the file. The parsed data is returned to the newly allocated
- configuration object. */
- <Cipher>
-
- Format:
-
- +<Cipher name>:<SIM path>
-
- <PKCS>
-
- Format:
-
- +<PKCS name>:<key length>
-
- <HashFunction>
-
- Format:
-
- +<Hash function name>:<SIM path>
-
- <ServerInfo>
-
- This section is used to set the server informations.
-
- Format:
-
- +<Server DNS name>:<Server IP>:<Geographic location>:<Port>
-
- <AdminInfo>
-
- This section is used to set the server's administrative information.
-
- Format:
-
- +<Location>:<Server type>:<Admin's name>:<Admin's email address>
-
- <ListenPort>
-
- This section is used to set ports the server is listenning.
-
- Format:
-
- +<Local IP/UNIX socket path>:<Remote IP>:<Port>
-
- <Logging>
-
- This section is used to set various logging files, their paths
- and maximum sizes. All the other directives except those defined
- below are ignored in this section. Log files are purged after they
- reach the maximum set byte size.
-
- Format:
-
- +infologfile:<path>:<max byte size>
- +errorlogfile:<path>:<max byte size>
-
- <ConnectionClass>
-
- This section is used to define connection classes. These can be
- used to optimize the server and the connections.
-
- Format:
-
- +<Class number>:<Ping freq>:<Connect freq>:<Max links>
-
- <ClientAuth>
-
- This section is used to define client authentications.
-
- Format:
-
- +<Remote address or name>:<auth method>:<password/cert/key/???>:<Port>:<Class>
-
- <AdminAuth>
-
- This section is used to define the server's administration
- authentications.
-
- Format:
-
- +<Hostname>:<auth method>:<password/cert/key/???>:<Nickname hash>:<Class>
-
- <ServerConnection>
++#define SILC_CONFIG_SERVER_AUTH_METH_PASSWD "passwd"
++#define SILC_CONFIG_SERVER_AUTH_METH_PUBKEY "pubkey"
- SilcServerConfig silc_server_config_alloc(char *filename)
- {
- SilcServerConfig new;
- SilcBuffer buffer;
- SilcServerConfigParse config_parse;
- This section is used to define the server connections to this
- server/router. Only routers can have normal server connections.
- Normal servers leave this section epmty. The remote server cannot be
- older than specified Version ID.
--
- SILC_LOG_DEBUG(("Allocating new configuration object"));
- Format:
-
- +<Remote address or name>:<auth method>:<password/key/???>:<Port>:<Version ID>:<Class>
-
- <RouterConnection>
-
- This section is used to define the router connections to this
- server/router. Both normal server and router can have router
- connections. Normal server usually has only one connection while
- a router can have multiple. The remote server cannot be older than
- specified Version ID.
-
- Format:
-
- +<Remote address or name>:<auth method>:<password/key/???>:<Port>:<Version ID>:<Class>
-
- <DenyConnection>
-
- This section is used to deny specific connections to your server. This
- can be used to deny both clients and servers.
-
- Format:
-
- +<Remote address or name or nickname>:<Time interval>:<Comment>:<Port>
-
- <RedirectClient>
-
- This section is used to set the alternate servers that clients will be
- redirected to when our server is full.
-
- Format:
-
- +<Remote address or name>:<Port>
++#if 0
++#define SERVER_CONFIG_DEBUG(fmt) SILC_LOG_DEBUG(fmt)
++#else
++#define SERVER_CONFIG_DEBUG(fmt)
++#endif
- new = silc_calloc(1, sizeof(*new));
- if (!new) {
- fprintf(stderr, "Could not allocate new configuration object");
- return NULL;
-*/
-SilcConfigServerSection silc_config_server_sections[] = {
- { "[Cipher]",
- SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER, 4 },
- { "[PKCS]",
- SILC_CONFIG_SERVER_SECTION_TYPE_PKCS, 2 },
- { "[HashFunction]",
- SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION, 4 },
- { "[ServerInfo]",
- SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO, 4 },
- { "[AdminInfo]",
- SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO, 4 },
- { "[ListenPort]",
- SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT, 3 },
- { "[Logging]",
- SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING, 3 },
- { "[ConnectionClass]",
- SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS, 4 },
- { "[ClientConnection]",
- SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION, 5 },
- { "[ServerConnection]",
- SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION, 6 },
- { "[RouterConnection]",
- SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION, 6 },
- { "[AdminConnection]",
- SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION, 5 },
- { "[DenyConnection]",
- SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION, 4 },
- { "[RedirectClient]",
- SILC_CONFIG_SERVER_SECTION_TYPE_REDIRECT_CLIENT, 2 },
-
- { NULL, SILC_CONFIG_SERVER_SECTION_TYPE_NONE, 0 }
-};
++/* auto-declare needed variables for the common list parsing */
++#define SILC_SERVER_CONFIG_SECTION_INIT(__type__) \
++ SilcServerConfig config = (SilcServerConfig) context; \
++ __type__ *findtmp, *tmp = (__type__ *) config->tmp; \
++ int got_errno = 0
++
++/* append the tmp field to the specified list */
++#define SILC_SERVER_CONFIG_LIST_APPENDTMP(__list__) \
++ if (!__list__) \
++ __list__ = tmp; \
++ else { \
++ for (findtmp = __list__; findtmp->next; findtmp = findtmp->next); \
++ findtmp->next = tmp; \
+ }
- new->filename = filename;
-
- SILC_LOG_DEBUG(("Loading config data from `%s'", filename));
-
- /* Open configuration file and parse it */
- config_parse = NULL;
- buffer = NULL;
- silc_config_open(filename, &buffer);
- if (!buffer)
- goto fail;
- if ((silc_server_config_parse(new, buffer, &config_parse)) == FALSE)
- goto fail;
- if ((silc_server_config_parse_lines(new, config_parse)) == FALSE)
- goto fail;
-
- silc_buffer_free(buffer);
-
- return new;
-
- fail:
- silc_buffer_free(buffer);
- silc_free(new);
- return NULL;
- }
-/* Allocates a new configuration object, opens configuration file and
- parses the file. The parsed data is returned to the newly allocated
- configuration object. */
++/* loops all elements in a list and provides a di struct pointer of the
++ * specified type containing the current element */
++#define SILC_SERVER_CONFIG_LIST_DESTROY(__type__, __list__) \
++ for (tmp = (void *) __list__; tmp;) { \
++ __type__ *di = (__type__ *) tmp; \
++ tmp = (void *) di->next;
- /* Free's a configuration object. */
-
- void silc_server_config_free(SilcServerConfig config)
-SilcConfigServer silc_config_server_alloc(char *filename)
++/* free an authdata according to its auth method */
++static void my_free_authdata(SilcAuthMethod auth_meth, void *auth_data)
{
- if (config) {
- silc_free(config->filename);
- silc_free(config->server_keys);
- silc_free(config->server_info);
- silc_free(config->admin_info);
- silc_free(config->listen_port);
- silc_free(config->identity);
- silc_free(config->conn_class);
- silc_free(config->clients);
- silc_free(config->admins);
- silc_free(config->servers);
- silc_free(config->routers);
- silc_free(config->denied);
- silc_free(config->motd);
- silc_free(config->pidfile);
- silc_free(config);
- SilcConfigServer new;
- SilcBuffer buffer;
- SilcConfigServerParse config_parse;
-
- SILC_LOG_DEBUG(("Allocating new configuration object"));
-
- new = silc_calloc(1, sizeof(*new));
- if (!new) {
- fprintf(stderr, "Could not allocate new configuration object");
- return NULL;
++ if (auth_meth == SILC_AUTH_PASSWORD) {
++ silc_free(auth_data);
++ } else if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
++ silc_pkcs_public_key_free((SilcPublicKey) auth_data);
}
-
- new->filename = filename;
-
- /* Open configuration file and parse it */
- config_parse = NULL;
- buffer = NULL;
- silc_config_open(filename, &buffer);
- if (!buffer)
- goto fail;
- if ((silc_config_server_parse(new, buffer, &config_parse)) == FALSE)
- goto fail;
- if ((silc_config_server_parse_lines(new, config_parse)) == FALSE)
- goto fail;
-
- silc_free(buffer);
-
- return new;
-
- fail:
- silc_free(new);
- return NULL;
}
- /* Parses the the buffer and returns the parsed lines into return_config
- argument. The return_config argument doesn't have to be initialized
- before calling this. It will be initialized during the parsing. The
- buffer sent as argument can be safely free'd after this function has
- succesfully returned. */
-/* Free's a configuration object. */
--
- int silc_server_config_parse(SilcServerConfig config, SilcBuffer buffer,
- SilcServerConfigParse *return_config)
-void silc_config_server_free(SilcConfigServer config)
++/* parse an authdata according to its auth method */
++static bool my_parse_authdata(SilcAuthMethod auth_meth, char *p, uint32 line,
++ void **auth_data, uint32 *auth_data_len)
{
- int i, begin, linenum;
- char line[1024], *cp;
- SilcServerConfigSection *cptr = NULL;
- SilcServerConfigParse parse = *return_config, first = NULL;
-
- SILC_LOG_DEBUG(("Parsing configuration file"));
-
- begin = 0;
- linenum = 0;
- while((begin = silc_gets(line, sizeof(line),
- buffer->data, buffer->len, begin)) != EOF) {
- cp = line;
- linenum++;
-
- /* Check for bad line */
- if (silc_check_line(cp))
- continue;
-
- /* Remove tabs and whitespaces from the line */
- if (strchr(cp, '\t')) {
- i = 0;
- while(strchr(cp + i, '\t')) {
- *strchr(cp + i, '\t') = ' ';
- i++;
- }
- }
- for (i = 0; i < strlen(cp); i++) {
- if (cp[i] != ' ') {
- if (i)
- cp++;
- break;
- }
- cp++;
- }
-
- /* Parse line */
- switch(cp[0]) {
- case '[':
- /*
- * Start of a section
- */
-
- /* Remove new line sign */
- if (strchr(cp, '\n'))
- *strchr(cp, '\n') = '\0';
-
- /* Check for matching sections */
- for (cptr = silc_server_config_sections; cptr->section; cptr++)
- if (!strncasecmp(cp, cptr->section, strlen(cptr->section)))
- break;
-
- if (!cptr->section) {
- fprintf(stderr, "%s:%d: Unknown section `%s'\n",
- config->filename, linenum, cp);
- if (config) {
- silc_free(config->filename);
- silc_free(config->server_info);
- silc_free(config->admin_info);
- silc_free(config->listen_port);
- silc_free(config->conn_class);
- silc_free(config->clients);
- silc_free(config->admins);
- silc_free(config->servers);
- silc_free(config->routers);
- silc_free(config->denied);
- silc_free(config->redirect);
- silc_free(config);
++ if (auth_meth == SILC_AUTH_PASSWORD) {
++ /* p is a plain text password */
++ *auth_data = (void *) strdup(p);
++ *auth_data_len = (uint32) strlen(p);
++ } else if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
++ /* p is a public key */
++ SilcPublicKey public_key;
++
++ if (!silc_pkcs_load_public_key(p, &public_key, SILC_PKCS_FILE_PEM))
++ if (!silc_pkcs_load_public_key(p, &public_key, SILC_PKCS_FILE_BIN)) {
++ fprintf(stderr, "\nError while parsing config file at line %lu: "
++ "Could not load public key file!\n", line);
+ return FALSE;
+ }
-
- break;
- default:
- /*
- * Start of a configuration line
- */
-
- if (cptr->type != SILC_CONFIG_SERVER_SECTION_TYPE_NONE) {
-
- if (strchr(cp, '\n'))
- *strchr(cp, '\n') = ':';
-
- if (parse == NULL) {
- parse = silc_calloc(1, sizeof(*parse));
- parse->line = NULL;
- parse->section = NULL;
- parse->next = NULL;
- parse->prev = NULL;
- } else {
- if (parse->next == NULL) {
- parse->next = silc_calloc(1, sizeof(*parse->next));
- parse->next->line = NULL;
- parse->next->section = NULL;
- parse->next->next = NULL;
- parse->next->prev = parse;
- parse = parse->next;
- }
- }
-
- if (first == NULL)
- first = parse;
-
- /* Add the line to parsing structure for further parsing. */
- if (parse) {
- parse->section = cptr;
- parse->line = silc_buffer_alloc(strlen(cp) + 1);
- parse->linenum = linenum;
- silc_buffer_pull_tail(parse->line, strlen(cp));
- silc_buffer_put(parse->line, cp, strlen(cp));
- }
- }
- break;
- }
++ *auth_data = (void *) public_key;
++ *auth_data_len = 0;
++ } else {
++ fprintf(stderr, "\nError while parsing config file at line %lu: Specify "
++ "the AuthMethod before specifying the AuthData.\n", line);
++ return FALSE;
}
-
- /* Set the return_config argument to its first value so that further
- parsing can be started from the first line. */
- *return_config = first;
-
+ return TRUE;
}
- /* Parses the lines earlier read from configuration file. The config object
- must not be initialized, it will be initialized in this function. The
- parse_config argument is uninitialized automatically during this
- function. */
-/* Parses the the buffer and returns the parsed lines into return_config
- argument. The return_config argument doesn't have to be initialized
- before calling this. It will be initialized during the parsing. The
- buffer sent as argument can be safely free'd after this function has
- succesfully returned. */
++/* Callbacks */
- int silc_server_config_parse_lines(SilcServerConfig config,
- SilcServerConfigParse parse_config)
-int silc_config_server_parse(SilcConfigServer config, SilcBuffer buffer,
- SilcConfigServerParse *return_config)
++SILC_CONFIG_CALLBACK(fetch_generic)
{
- int ret, check = FALSE;
- uint32 checkmask;
- char *tmp;
- SilcServerConfigParse pc = parse_config;
- SilcBuffer line;
-
- SILC_LOG_DEBUG(("Parsing configuration lines"));
-
- if (!config)
- return FALSE;
-
- checkmask = 0;
- while(pc) {
- check = FALSE;
- line = pc->line;
-
- /* Get number of tokens in line */
- ret = silc_config_check_num_token(line);
- if (ret < pc->section->maxfields) {
- /* Bad line */
- fprintf(stderr, "%s:%d: Missing tokens, %d tokens (should be %d)\n",
- config->filename, pc->linenum, ret,
- pc->section->maxfields);
- break;
- }
-
- /* Parse the line */
- switch(pc->section->type) {
- case SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER:
-
- SILC_SERVER_CONFIG_LIST_ALLOC(config->cipher);
-
- /* Get cipher name */
- ret = silc_config_get_token(line, &config->cipher->alg_name);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Cipher name not defined\n",
- config->filename, pc->linenum);
- break;
- }
-
- /* Get module name */
- config->cipher->sim_name = NULL;
- ret = silc_config_get_token(line, &config->cipher->sim_name);
- if (ret < 0)
- break;
-
- /* Get key length */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Cipher key length not defined\n",
- config->filename, pc->linenum);
- break;
- }
- config->cipher->key_len = atoi(tmp);
- silc_free(tmp);
-
- /* Get block length */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Cipher block length not defined\n",
- config->filename, pc->linenum);
- break;
- }
- config->cipher->block_len = atoi(tmp);
- silc_free(tmp);
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_PKCS:
-
- SILC_SERVER_CONFIG_LIST_ALLOC(config->pkcs);
-
- /* Get PKCS name */
- ret = silc_config_get_token(line, &config->pkcs->alg_name);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: PKCS name not defined\n",
- config->filename, pc->linenum);
- break;
- }
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION:
-
- SILC_SERVER_CONFIG_LIST_ALLOC(config->hash_func);
-
- /* Get Hash function name */
- ret = silc_config_get_token(line, &config->hash_func->alg_name);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Hash function name not defined\n",
- config->filename, pc->linenum);
- break;
- }
-
- /* Get Hash function module name */
- config->hash_func->sim_name = NULL;
- ret = silc_config_get_token(line, &config->hash_func->sim_name);
- if (ret < 0)
- break;
-
- /* Get block length */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Hash function block length not defined\n",
- config->filename, pc->linenum);
- break;
- }
- config->hash_func->block_len = atoi(tmp);
- silc_free(tmp);
-
- /* Get hash length */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Hash function hash length not defined\n",
- config->filename, pc->linenum);
- break;
- }
- config->hash_func->key_len = atoi(tmp);
- silc_free(tmp);
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_HMAC:
-
- SILC_SERVER_CONFIG_LIST_ALLOC(config->hmac);
-
- /* Get HMAC name */
- ret = silc_config_get_token(line, &config->hmac->alg_name);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: HMAC name not defined\n",
- config->filename, pc->linenum);
- break;
- }
-
- /* Get hash name */
- ret = silc_config_get_token(line, &config->hmac->sim_name);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Hash function name not defined\n",
- config->filename, pc->linenum);
- break;
- }
-
- /* Get MAC length */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: HMAC's MAC length not defined\n",
- config->filename, pc->linenum);
- break;
- }
- config->hmac->key_len = atoi(tmp);
- silc_free(tmp);
- int i, begin;
- unsigned int linenum;
- char line[1024], *cp;
- SilcConfigServerSection *cptr = NULL;
- SilcConfigServerParse parse = *return_config, first = NULL;
--
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
- SILC_LOG_DEBUG(("Parsing configuration file"));
--
- case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_KEYS:
- begin = 0;
- linenum = 0;
- while((begin = silc_gets(line, sizeof(line),
- buffer->data, buffer->len, begin)) != EOF) {
- cp = line;
- linenum++;
--
- if (!config->server_keys)
- config->server_keys = silc_calloc(1, sizeof(*config->server_keys));
- /* Check for bad line */
- if (silc_check_line(cp))
- continue;
--
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Public key name not defined\n",
- config->filename, pc->linenum);
- break;
- /* Remove tabs and whitespaces from the line */
- if (strchr(cp, '\t')) {
- i = 0;
- while(strchr(cp + i, '\t')) {
- *strchr(cp + i, '\t') = ' ';
- i++;
-- }
-
- if (!silc_pkcs_load_public_key(tmp, &config->server_keys->public_key,
- SILC_PKCS_FILE_PEM))
- if (!silc_pkcs_load_public_key(tmp, &config->server_keys->public_key,
- SILC_PKCS_FILE_BIN)) {
- fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
- config->filename, pc->linenum, tmp);
- break;
- }
- silc_free(tmp);
-
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Private key name not defined\n",
- config->filename, pc->linenum);
- }
- for (i = 0; i < strlen(cp); i++) {
- if (cp[i] != ' ') {
- if (i)
- cp++;
-- break;
-- }
-
- if (!silc_pkcs_load_private_key(tmp, &config->server_keys->private_key,
- SILC_PKCS_FILE_BIN))
- if (!silc_pkcs_load_private_key(tmp,
- &config->server_keys->private_key,
- SILC_PKCS_FILE_PEM)) {
- fprintf(stderr, "%s:%d: Could not load private key file `%s'\n",
- config->filename, pc->linenum, tmp);
- break;
- }
- silc_free(tmp);
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO:
-
- if (!config->server_info)
- config->server_info = silc_calloc(1, sizeof(*config->server_info));
- cp++;
- }
--
- /* Get server name */
- ret = silc_config_get_token(line, &config->server_info->server_name);
- if (ret < 0)
- break;
- if (ret == 0) {
- /* Server name not defined */
- /* Parse line */
- switch(cp[0]) {
- case '[':
- /*
- * Start of a section
- */
--
- }
- /* Remove new line sign */
- if (strchr(cp, '\n'))
- *strchr(cp, '\n') = '\0';
--
- /* Get server IP */
- ret = silc_config_get_token(line, &config->server_info->server_ip);
- if (ret < 0)
- break;
- if (ret == 0) {
- /* Server IP not defined */
-
- }
-
- /* Get server location */
- ret = silc_config_get_token(line, &config->server_info->location);
- if (ret < 0)
- break;
-
- /* Get server port */
- /* XXX: Need port here??? */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- /* Port not defined */
-
- }
- config->server_info->port = atoi(tmp);
- silc_free(tmp);
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO:
-
- if (!config->admin_info)
- config->admin_info = silc_calloc(1, sizeof(*config->admin_info));
-
- /* Get location */
- ret = silc_config_get_token(line, &config->admin_info->location);
- if (ret < 0)
- break;
-
- /* Get server type */
- ret = silc_config_get_token(line, &config->admin_info->server_type);
- if (ret < 0)
- break;
-
- /* Get admins name */
- ret = silc_config_get_token(line, &config->admin_info->admin_name);
- if (ret < 0)
- break;
-
- /* Get admins email address */
- ret = silc_config_get_token(line, &config->admin_info->admin_email);
- if (ret < 0)
- break;
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT:
-
- SILC_SERVER_CONFIG_LIST_ALLOC(config->listen_port);
-
- /* Get local IP */
- ret = silc_config_get_token(line, &config->listen_port->local_ip);
- if (ret < 0)
- break;
-
- /* Get listener IP */
- ret = silc_config_get_token(line, &config->listen_port->listener_ip);
- if (ret < 0)
- break;
-
- /* Get port */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- /* Any port */
- config->listen_port->port = 0;
- } else {
- config->listen_port->port = atoi(tmp);
- silc_free(tmp);
- }
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_IDENTITY:
-
- if (!config->identity)
- config->identity = silc_calloc(1, sizeof(*config->identity));
-
- /* Get user */
- ret = silc_config_get_token(line, &config->identity->user);
- if (ret < 0)
- break;
- /* Get group */
- ret = silc_config_get_token(line, &config->identity->group);
- if (ret < 0)
- break;
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS:
-
- SILC_SERVER_CONFIG_LIST_ALLOC(config->conn_class);
-
- /* Get class number */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- /* Class number not defined */
-
- }
- config->conn_class->class = atoi(tmp);
- silc_free(tmp);
-
- /* Get ping frequency */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- config->conn_class->ping_freq = atoi(tmp);
- silc_free(tmp);
-
- /* Get connect frequency */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- config->conn_class->connect_freq = atoi(tmp);
- silc_free(tmp);
-
- /* Get max links */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- config->conn_class->max_links = atoi(tmp);
- silc_free(tmp);
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING:
-
- SILC_SERVER_CONFIG_LIST_ALLOC(config->logging);
-
- /* Get log section type and check it */
- ret = silc_config_get_token(line, &config->logging->logtype);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Log file section not defined\n",
- config->filename, pc->linenum);
- break;
- }
- if (strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_INFO)
- && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_WARNING)
- && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_ERROR)
- && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_FATAL)
- && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LO_QUICK)
- && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LO_FDELAY)) {
- fprintf(stderr, "%s:%d: Unknown log file section '%s'\n",
- config->filename, pc->linenum, config->logging->logtype);
- break;
- }
-
- /* Get log filename */
- ret = silc_config_get_token(line, &config->logging->filename);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Log file name not defined\n",
- config->filename, pc->linenum);
- break;
- }
-
- /* Get max byte size */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret) {
- config->logging->maxsize = atoi(tmp);
- silc_free(tmp);
- }
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION:
-
- SILC_SERVER_CONFIG_LIST_ALLOC(config->clients);
-
- /* Get host */
- ret = silc_config_get_token(line, &config->clients->host);
- if (ret < 0)
- break;
- if (ret == 0)
- /* Any host */
- config->clients->host = strdup("*");
-
- /* Get authentication method */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret) {
- if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
- strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
- fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
- config->filename, pc->linenum, tmp);
- break;
- }
-
- if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
- config->clients->auth_meth = SILC_AUTH_PASSWORD;
-
- if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
- config->clients->auth_meth = SILC_AUTH_PUBLIC_KEY;
-
- silc_free(tmp);
- }
-
- /* Get authentication data */
- ret = silc_config_get_token(line, (char **)&config->clients->auth_data);
- if (ret < 0)
- break;
-
- if (config->clients->auth_meth == SILC_AUTH_PASSWORD) {
- config->clients->auth_data_len = strlen(config->clients->auth_data);
- } else if (config->clients->auth_meth == SILC_AUTH_PUBLIC_KEY) {
- /* Get the public key */
- SilcPublicKey public_key;
-
- if (!silc_pkcs_load_public_key(config->clients->auth_data,
- &public_key, SILC_PKCS_FILE_PEM))
- if (!silc_pkcs_load_public_key(config->clients->auth_data,
- &public_key, SILC_PKCS_FILE_BIN)) {
- fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
- config->filename, pc->linenum,
- (char *)config->clients->auth_data);
- break;
- }
-
- silc_free(config->clients->auth_data);
- config->clients->auth_data = (void *)public_key;
- config->clients->auth_data_len = 0;
- }
-
- /* Get port */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret) {
- config->clients->port = atoi(tmp);
- silc_free(tmp);
- }
-
- /* Get class number */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret) {
- config->clients->class = atoi(tmp);
- silc_free(tmp);
- }
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION:
-
- SILC_SERVER_CONFIG_LIST_ALLOC(config->servers);
-
- /* Get host */
- ret = silc_config_get_token(line, &config->servers->host);
- if (ret < 0)
- break;
- if (ret == 0)
- /* Any host */
- config->servers->host = strdup("*");
-
- /* Get authentication method */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret) {
- if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
- strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
- fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
- config->filename, pc->linenum, tmp);
- /* Check for matching sections */
- for (cptr = silc_config_server_sections; cptr->section; cptr++)
- if (!strcmp(cp, cptr->section))
-- break;
- }
-
- if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
- config->servers->auth_meth = SILC_AUTH_PASSWORD;
-
- if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
- config->servers->auth_meth = SILC_AUTH_PUBLIC_KEY;
-
- silc_free(tmp);
- }
-
- /* Get authentication data */
- ret = silc_config_get_token(line, (char **)&config->servers->auth_data);
- if (ret < 0)
- break;
-
- if (config->servers->auth_meth == SILC_AUTH_PASSWORD) {
- config->servers->auth_data_len = strlen(config->servers->auth_data);
- } else if (config->servers->auth_meth == SILC_AUTH_PUBLIC_KEY) {
- /* Get the public key */
- SilcPublicKey public_key;
-
- if (!silc_pkcs_load_public_key(config->servers->auth_data,
- &public_key, SILC_PKCS_FILE_PEM))
- if (!silc_pkcs_load_public_key(config->servers->auth_data,
- &public_key, SILC_PKCS_FILE_BIN)) {
- fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
- config->filename, pc->linenum,
- (char *)config->servers->auth_data);
- break;
- }
-
- silc_free(config->servers->auth_data);
- config->servers->auth_data = (void *)public_key;
- config->servers->auth_data_len = 0;
- }
-
- /* Get port */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret) {
- config->servers->port = atoi(tmp);
- silc_free(tmp);
- }
-
- /* Get version */
- ret = silc_config_get_token(line, &config->servers->version);
- if (ret < 0)
- break;
++ SilcServerConfig config = (SilcServerConfig) context;
- /* Get class number */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret) {
- config->servers->class = atoi(tmp);
- silc_free(tmp);
- if (!cptr->section) {
- fprintf(stderr, "%s:%d: Unknown section `%s'\n",
- config->filename, linenum, cp);
- return FALSE;
-- }
++ if (!strcmp(name, "modulepath")) {
++ if (config->module_path) return SILC_CONFIG_EDOUBLE;
++ /* dup it only if non-empty, otherwise point it to NULL */
++ config->module_path = (*(char *)val ? strdup((char *) val) : NULL);
++ }
++ else
++ return SILC_CONFIG_EINTERNAL;
++ return SILC_CONFIG_OK;
++}
- /* Check whether this connection is backup router connection */
- ret = silc_config_get_token(line, &tmp);
- if (ret != -1) {
- config->servers->backup_router = atoi(tmp);
- if (config->servers->backup_router != 0)
- config->servers->backup_router = TRUE;
- silc_free(tmp);
- break;
- default:
- /*
- * Start of a configuration line
- */
-
- if (cptr->type != SILC_CONFIG_SERVER_SECTION_TYPE_NONE) {
-
- if (strchr(cp, '\n'))
- *strchr(cp, '\n') = ':';
-
- if (parse == NULL) {
- parse = silc_calloc(1, sizeof(*parse));
- parse->line = NULL;
- parse->section = NULL;
- parse->next = NULL;
- parse->prev = NULL;
- } else {
- if (parse->next == NULL) {
- parse->next = silc_calloc(1, sizeof(*parse->next));
- parse->next->line = NULL;
- parse->next->section = NULL;
- parse->next->next = NULL;
- parse->next->prev = parse;
- parse = parse->next;
- }
- }
-
- if (first == NULL)
- first = parse;
-
- /* Add the line to parsing structure for further parsing. */
- if (parse) {
- parse->section = cptr;
- parse->line = silc_buffer_alloc(strlen(cp) + 1);
- parse->linenum = linenum;
- silc_buffer_pull_tail(parse->line, strlen(cp));
- silc_buffer_put(parse->line, cp, strlen(cp));
- }
-- }
- break;
++SILC_CONFIG_CALLBACK(fetch_cipher)
++{
++ SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionCipher);
++
++ SERVER_CONFIG_DEBUG(("Received CIPHER type=%d name=\"%s\" (val=%x)", type, name, context));
++ if (type == SILC_CONFIG_ARG_BLOCK) {
++ /* check the temporary struct's fields */
++ if (!tmp) /* empty sub-block? */
++ return SILC_CONFIG_OK;
++ if (!tmp->name) {
++ got_errno = SILC_CONFIG_EMISSFIELDS;
++ goto got_err;
+ }
++ /* the temporary struct is ok, append it to the list */
++ SILC_SERVER_CONFIG_LIST_APPENDTMP(config->cipher);
++ config->tmp = NULL;
++ return SILC_CONFIG_OK;
++ }
++ /* if there isn't a temporary struct alloc one */
++ if (!tmp) {
++ config->tmp = silc_calloc(1, sizeof(*findtmp));
++ tmp = (SilcServerConfigSectionCipher *) config->tmp;
+ }
-
- /* Set the return_config argument to its first value so that further
- parsing can be started from the first line. */
- *return_config = first;
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
- return TRUE;
++ /* Identify and save this value */
++ if (!strcmp(name, "name")) {
++ if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
++ tmp->name = strdup((char *) val);
++ }
++ else if (!strcmp(name, "module")) { /* can be empty */
++ if (tmp->module) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
++ /* dup it only if non-empty, otherwise point it to NULL */
++ tmp->module = (*(char *)val ? strdup((char *) val) : NULL);
++ }
++ else if (!strcmp(name, "key_length"))
++ tmp->key_length = *(uint32 *)val;
++ else if (!strcmp(name, "block_length"))
++ tmp->block_length = *(uint32 *)val;
++ else
++ return SILC_CONFIG_EINTERNAL;
++ return SILC_CONFIG_OK;
++
++ got_err:
++ silc_free(tmp->name);
++ silc_free(tmp->module);
++ silc_free(tmp);
++ config->tmp = NULL;
++ return got_errno;
+ }
- case SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION:
-/* Parses the lines earlier read from configuration file. The config object
- must not be initialized, it will be initialized in this function. The
- parse_config argument is uninitialized automatically during this
- function. */
-
-int silc_config_server_parse_lines(SilcConfigServer config,
- SilcConfigServerParse parse_config)
++SILC_CONFIG_CALLBACK(fetch_hash)
+ {
- int ret, check = FALSE;
- unsigned int checkmask;
- char *tmp;
- SilcConfigServerParse pc = parse_config;
- SilcBuffer line;
-
- SILC_LOG_DEBUG(("Parsing configuration lines"));
-
- if (!config)
- return FALSE;
-
- checkmask = 0;
- while(pc) {
- check = FALSE;
- line = pc->line;
-
- /* Get number of tokens in line */
- ret = silc_config_check_num_token(line);
- if (ret != pc->section->maxfields) {
- /* Bad line */
- fprintf(stderr, "%s:%d: Missing tokens, %d tokens (should be %d)\n",
- config->filename, pc->linenum, ret,
- pc->section->maxfields);
- break;
++ SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionHash);
++
++ SERVER_CONFIG_DEBUG(("Received HASH type=%d name=%s (val=%x)", type, name, context));
++ if (type == SILC_CONFIG_ARG_BLOCK) {
++ /* check the temporary struct's fields */
++ if (!tmp) /* empty sub-block? */
++ return SILC_CONFIG_OK;
++ if (!tmp->name || (tmp->block_length == 0) || (tmp->digest_length == 0)) {
++ got_errno = SILC_CONFIG_EMISSFIELDS;
++ goto got_err;
+ }
++ /* the temporary struct in tmp is ok */
++ SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hash);
++ config->tmp = NULL;
++ return SILC_CONFIG_OK;
++ }
++ /* if there isn't a temporary struct alloc one */
++ if (!tmp) {
++ config->tmp = silc_calloc(1, sizeof(*findtmp));
++ tmp = (SilcServerConfigSectionHash *) config->tmp;
++ }
- SILC_SERVER_CONFIG_LIST_ALLOC(config->routers);
- /* Parse the line */
- switch(pc->section->type) {
- case SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER:
-
- SILC_SERVER_CONFIG_LIST_ALLOC(config->cipher);
-
- /* Get cipher name */
- ret = silc_config_get_token(line, &config->cipher->alg_name);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Cipher name not defined\n",
- config->filename, pc->linenum);
- break;
- }
-
- /* Get module name */
- config->cipher->sim_name = NULL;
- ret = silc_config_get_token(line, &config->cipher->sim_name);
- if (ret < 0)
- break;
-
- /* Get block length */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Cipher block length not defined\n",
- config->filename, pc->linenum);
- break;
- }
- config->cipher->block_len = atoi(tmp);
- silc_free(tmp);
-
- /* Get key length */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Cipher key length not defined\n",
- config->filename, pc->linenum);
- break;
- }
- config->cipher->key_len = atoi(tmp);
- silc_free(tmp);
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_PKCS:
-
- SILC_SERVER_CONFIG_LIST_ALLOC(config->pkcs);
-
- /* Get PKCS name */
- ret = silc_config_get_token(line, &config->pkcs->alg_name);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: PKCS name not defined\n",
- config->filename, pc->linenum);
- break;
- }
-
- /* Get key length */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: PKCS key length not defined\n",
- config->filename, pc->linenum);
- break;
- }
- config->pkcs->key_len = atoi(tmp);
- silc_free(tmp);
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION:
-
- SILC_SERVER_CONFIG_LIST_ALLOC(config->hash_func);
-
- /* Get Hash function name */
- ret = silc_config_get_token(line, &config->hash_func->alg_name);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Hash function name not defined\n",
- config->filename, pc->linenum);
- break;
- }
-
- /* Get Hash function module name */
- config->hash_func->sim_name = NULL;
- ret = silc_config_get_token(line, &config->hash_func->sim_name);
- if (ret < 0)
- break;
-
- /* Get block length */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Hash function block length not defined\n",
- config->filename, pc->linenum);
- break;
- }
- config->hash_func->block_len = atoi(tmp);
- silc_free(tmp);
-
- /* Get hash length */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Hash function hash length not defined\n",
- config->filename, pc->linenum);
- break;
- }
- config->hash_func->key_len = atoi(tmp);
- silc_free(tmp);
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO:
-
- if (!config->server_info)
- config->server_info = silc_calloc(1, sizeof(*config->server_info));
-
- /* Get server name */
- ret = silc_config_get_token(line, &config->server_info->server_name);
- if (ret < 0)
- break;
- if (ret == 0) {
- /* Server name not defined */
-
- }
-
- /* Get server IP */
- ret = silc_config_get_token(line, &config->server_info->server_ip);
- if (ret < 0)
- break;
- if (ret == 0) {
- /* Server IP not defined */
-
- }
-
- /* Get server location */
- ret = silc_config_get_token(line, &config->server_info->location);
- if (ret < 0)
- break;
-
- /* Get server port */
- /* XXX: Need port here??? */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- /* Port not defined */
-
- }
- config->server_info->port = atoi(tmp);
- silc_free(tmp);
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO:
-
- if (!config->admin_info)
- config->admin_info = silc_calloc(1, sizeof(*config->admin_info));
-
- /* Get server type */
- ret = silc_config_get_token(line, &config->admin_info->server_type);
- if (ret < 0)
- break;
-
- /* Get admins name */
- ret = silc_config_get_token(line, &config->admin_info->admin_name);
- if (ret < 0)
- break;
-
- /* Get admins email address */
- ret = silc_config_get_token(line, &config->admin_info->admin_email);
- if (ret < 0)
- break;
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT:
-
- SILC_SERVER_CONFIG_LIST_ALLOC(config->listen_port);
-
- /* Get host */
- ret = silc_config_get_token(line, &config->listen_port->host);
- if (ret < 0)
- break;
-
- /* Get remote IP */
- ret = silc_config_get_token(line, &config->listen_port->remote_ip);
- if (ret < 0)
- break;
-
- /* Get port */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- /* Any port */
- config->listen_port->port = 0;
- } else {
- config->listen_port->port = atoi(tmp);
- silc_free(tmp);
- }
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS:
-
- SILC_SERVER_CONFIG_LIST_ALLOC(config->conn_class);
-
- /* Get class number */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- /* Class number not defined */
-
- }
- config->conn_class->class = atoi(tmp);
- silc_free(tmp);
-
- /* Get ping frequency */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- config->conn_class->ping_freq = atoi(tmp);
- silc_free(tmp);
-
- /* Get connect frequency */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- config->conn_class->connect_freq = atoi(tmp);
- silc_free(tmp);
-
- /* Get max links */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- config->conn_class->max_links = atoi(tmp);
- silc_free(tmp);
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING:
-
- SILC_SERVER_CONFIG_LIST_ALLOC(config->logging);
-
- /* Get log section type and check it */
- ret = silc_config_get_token(line, &config->logging->logtype);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Log file section not defined\n",
- config->filename, pc->linenum);
- break;
- }
- if (strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_INFO)
- && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_WARNING)
- && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_ERROR)
- && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_FATAL)) {
- fprintf(stderr, "%s:%d: Unknown log file section '%s'\n",
- config->filename, pc->linenum, config->logging->logtype);
- break;
- }
-
- /* Get log filename */
- ret = silc_config_get_token(line, &config->logging->filename);
- if (ret < 0)
- break;
- if (ret == 0) {
- fprintf(stderr, "%s:%d: Log file name not defined\n",
- config->filename, pc->linenum);
- break;
- }
-
- /* Get max byte size */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret) {
- config->logging->maxsize = atoi(tmp);
- silc_free(tmp);
- }
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION:
-
- SILC_SERVER_CONFIG_LIST_ALLOC(config->clients);
-
- /* Get host */
- ret = silc_config_get_token(line, &config->clients->host);
- if (ret < 0)
- break;
- if (ret == 0)
- /* Any host */
- config->clients->host = strdup("*");
-
- /* Get authentication method */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret) {
- if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
- strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
- fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
- config->filename, pc->linenum, tmp);
- break;
- }
-
- if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
- config->clients->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
-
- if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
- config->clients->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
-
- silc_free(tmp);
- }
-
- /* Get authentication data */
- ret = silc_config_get_token(line, &config->clients->auth_data);
- if (ret < 0)
- break;
- if (ret == 0)
- /* Any host */
- config->clients->host = strdup("*");
-
- /* Get port */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret == 0) {
- config->clients->port = atoi(tmp);
- silc_free(tmp);
- }
-
- /* Get class number */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret) {
- config->clients->class = atoi(tmp);
- silc_free(tmp);
- }
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION:
-
- SILC_SERVER_CONFIG_LIST_ALLOC(config->servers);
++ /* Identify and save this value */
++ if (!strcmp(name, "name")) {
++ if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
++ tmp->name = strdup((char *) val);
++ }
++ else if (!strcmp(name, "module")) { /* can be empty */
++ if (tmp->module) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
++ /* dup it only if non-empty, otherwise point it to NULL */
++ tmp->module = (*(char *)val ? strdup((char *) val) : NULL);
++ }
++ else if (!strcmp(name, "block_length"))
++ tmp->block_length = *(int *)val;
++ else if (!strcmp(name, "digest_length"))
++ tmp->digest_length = *(int *)val;
++ else
++ return SILC_CONFIG_EINTERNAL;
++ return SILC_CONFIG_OK;
++
++ got_err:
++ silc_free(tmp->name);
++ silc_free(tmp->module);
++ silc_free(tmp);
++ config->tmp = NULL;
++ return got_errno;
++}
-- /* Get host */
- ret = silc_config_get_token(line, &config->routers->host);
- ret = silc_config_get_token(line, &config->servers->host);
-- if (ret < 0)
-- break;
- if (ret == 0)
- /* Any host */
- config->servers->host = strdup("*");
++SILC_CONFIG_CALLBACK(fetch_hmac)
++{
++ SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionHmac);
++
++ SERVER_CONFIG_DEBUG(("Received HMAC type=%d name=\"%s\" (val=%x)", type, name, context));
++ if (type == SILC_CONFIG_ARG_BLOCK) {
++ /* check the temporary struct's fields */
++ if (!tmp) /* empty sub-block? */
++ return SILC_CONFIG_OK;
++ if (!tmp->name || !tmp->hash || (tmp->mac_length == 0)) {
++ got_errno = SILC_CONFIG_EMISSFIELDS;
++ goto got_err;
++ }
++ /* the temporary struct is ok, append it to the list */
++ SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hmac);
++ config->tmp = NULL;
++ return SILC_CONFIG_OK;
++ }
++ /* if there isn't a temporary struct alloc one */
++ if (!tmp) {
++ config->tmp = silc_calloc(1, sizeof(*findtmp));
++ tmp = (SilcServerConfigSectionHmac *) config->tmp;
++ }
-- /* Get authentication method */
-- ret = silc_config_get_token(line, &tmp);
-- if (ret < 0)
-- break;
-- if (ret) {
-- if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
-- strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
-- fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
-- config->filename, pc->linenum, tmp);
-- break;
-- }
++ /* Identify and save this value */
++ if (!strcmp(name, "name")) {
++ if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
++ tmp->name = strdup((char *) val);
++ }
++ else if (!strcmp(name, "hash")) {
++ if (tmp->hash) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
++ tmp->hash = strdup((char *) val);
++ }
++ else if (!strcmp(name, "mac_length"))
++ tmp->mac_length = *(int *)val;
++ else
++ return SILC_CONFIG_EINTERNAL;
++ return SILC_CONFIG_OK;
++
++ got_err:
++ silc_free(tmp->name);
++ silc_free(tmp->hash);
++ silc_free(tmp);
++ config->tmp = NULL;
++ return got_errno;
++}
-- if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
- config->routers->auth_meth = SILC_AUTH_PASSWORD;
- config->servers->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
++SILC_CONFIG_CALLBACK(fetch_pkcs)
++{
++ SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionPkcs);
++
++ SERVER_CONFIG_DEBUG(("Received PKCS type=%d name=\"%s\" (val=%x)", type, name, context));
++ if (type == SILC_CONFIG_ARG_BLOCK) {
++ /* check the temporary struct's fields */
++ if (!tmp) /* empty sub-block? */
++ return SILC_CONFIG_OK;
++ if (!tmp->name) {
++ got_errno = SILC_CONFIG_EMISSFIELDS;
++ goto got_err;
++ }
++ /* the temporary struct is ok, append it to the list */
++ SILC_SERVER_CONFIG_LIST_APPENDTMP(config->pkcs);
++ config->tmp = NULL;
++ return SILC_CONFIG_OK;
++ }
++ /* if there isn't a temporary struct alloc one */
++ if (!tmp) {
++ config->tmp = silc_calloc(1, sizeof(*findtmp));
++ tmp = (SilcServerConfigSectionPkcs *) config->tmp;
++ }
-- if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
- config->routers->auth_meth = SILC_AUTH_PUBLIC_KEY;
- config->servers->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
++ /* Identify and save this value */
++ if (!strcmp(name, "name")) {
++ if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
++ tmp->name = strdup((char *) val);
++ }
++ else
++ return SILC_CONFIG_EINTERNAL;
++ return SILC_CONFIG_OK;
++
++ got_err:
++ silc_free(tmp->name);
++ silc_free(tmp);
++ config->tmp = NULL;
++ return got_errno;
++}
-- silc_free(tmp);
-- }
++SILC_CONFIG_CALLBACK(fetch_serverinfo)
++{
++ SilcServerConfig config = (SilcServerConfig) context;
++ SilcServerConfigSectionServerInfo *server_info = config->server_info;
-- /* Get authentication data */
- ret = silc_config_get_token(line, (char **)&config->routers->auth_data);
- ret = silc_config_get_token(line, &config->servers->auth_data);
-- if (ret < 0)
-- break;
++ /* if there isn't the struct alloc it */
++ if (!server_info) {
++ config->server_info = server_info = (SilcServerConfigSectionServerInfo *)
++ silc_calloc(1, sizeof(*server_info));
++ }
- if (config->routers->auth_meth == SILC_AUTH_PASSWORD) {
- config->routers->auth_data_len = strlen(config->routers->auth_data);
- } else if (config->routers->auth_meth == SILC_AUTH_PUBLIC_KEY) {
- /* Get the public key */
- SilcPublicKey public_key;
-
- if (!silc_pkcs_load_public_key(config->routers->auth_data,
- &public_key, SILC_PKCS_FILE_PEM))
- if (!silc_pkcs_load_public_key(config->routers->auth_data,
- &public_key, SILC_PKCS_FILE_BIN)) {
- fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
- config->filename, pc->linenum,
- (char *)config->routers->auth_data);
- break;
- }
-
- silc_free(config->routers->auth_data);
- config->routers->auth_data = (void *)public_key;
- config->routers->auth_data_len = 0;
- /* Get port */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret) {
- config->servers->port = atoi(tmp);
- silc_free(tmp);
++ if (type == SILC_CONFIG_ARG_BLOCK) {
++ /* check for mandatory inputs */
++ return SILC_CONFIG_OK;
++ }
++ if (!strcmp(name, "hostname")) {
++ if (server_info->server_name) return SILC_CONFIG_EDOUBLE;
++ server_info->server_name = strdup((char *) val);
++ }
++ else if (!strcmp(name, "ip")) {
++ if (server_info->server_ip) return SILC_CONFIG_EDOUBLE;
++ server_info->server_ip = strdup((char *) val);
++ }
++ else if (!strcmp(name, "port")) {
++ int port = *(int *)val;
++ if ((port <= 0) || (port > 65535)) {
++ fprintf(stderr, "Invalid port number!\n");
++ return SILC_CONFIG_ESILENT;
++ }
++ server_info->port = (uint16) port;
++ }
++ else if (!strcmp(name, "servertype")) {
++ if (server_info->server_type) return SILC_CONFIG_EDOUBLE;
++ server_info->server_type = strdup((char *) val);
++ }
++ else if (!strcmp(name, "admin")) {
++ if (server_info->admin) return SILC_CONFIG_EDOUBLE;
++ server_info->admin = strdup((char *) val);
++ }
++ else if (!strcmp(name, "email")) {
++ if (server_info->email) return SILC_CONFIG_EDOUBLE;
++ server_info->email = strdup((char *) val);
++ }
++ else if (!strcmp(name, "location")) {
++ if (server_info->location) return SILC_CONFIG_EDOUBLE;
++ server_info->location = strdup((char *) val);
++ }
++ else if (!strcmp(name, "user")) {
++ if (server_info->user) return SILC_CONFIG_EDOUBLE;
++ server_info->user = strdup((char *) val);
++ }
++ else if (!strcmp(name, "group")) {
++ if (server_info->group) return SILC_CONFIG_EDOUBLE;
++ server_info->group = strdup((char *) val);
++ }
++ else if (!strcmp(name, "motdfile")) {
++ if (server_info->motd_file) return SILC_CONFIG_EDOUBLE;
++ server_info->motd_file = strdup((char *) val);
++ }
++ else if (!strcmp(name, "pidfile")) {
++ if (server_info->pid_file) return SILC_CONFIG_EDOUBLE;
++ server_info->pid_file = strdup((char *) val);
++ }
++ else if (!strcmp(name, "publickey")) {
++ char *tmp = (char *) val;
++
++ /* try to load specified file, if fail stop config parsing */
++ if (!silc_pkcs_load_public_key(tmp, &server_info->public_key,
++ SILC_PKCS_FILE_PEM))
++ if (!silc_pkcs_load_public_key(tmp, &server_info->public_key,
++ SILC_PKCS_FILE_BIN)) {
++ fprintf(stderr, "\nError: Could not load public key file.");
++ fprintf(stderr, "\n line %lu: file \"%s\"\n", line, tmp);
++ return SILC_CONFIG_ESILENT;
}
--
- /* Get port */
- /* Get version */
- ret = silc_config_get_token(line, &config->servers->version);
- if (ret < 0)
- break;
-
- /* Get class number */
-- ret = silc_config_get_token(line, &tmp);
-- if (ret < 0)
-- break;
-- if (ret) {
- config->routers->port = atoi(tmp);
- config->servers->class = atoi(tmp);
-- silc_free(tmp);
++ }
++ else if (!strcmp(name, "privatekey")) {
++ char *tmp = (char *) val;
++
++ /* try to load specified file, if fail stop config parsing */
++ if (!silc_pkcs_load_private_key(tmp, &server_info->private_key,
++ SILC_PKCS_FILE_BIN))
++ if (!silc_pkcs_load_private_key(tmp, &server_info->private_key,
++ SILC_PKCS_FILE_PEM)) {
++ fprintf(stderr, "\nError: Could not load private key file.");
++ fprintf(stderr, "\n line %lu: file \"%s\"\n", line, tmp);
++ return SILC_CONFIG_ESILENT;
}
++ }
++ else
++ return SILC_CONFIG_EINTERNAL;
++ return SILC_CONFIG_OK;
++}
- /* Get version */
- ret = silc_config_get_token(line, &config->routers->version);
- if (ret < 0)
- break;
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION:
++SILC_CONFIG_CALLBACK(fetch_logging)
++{
++ SilcServerConfig config = (SilcServerConfig) context;
++ SilcServerConfigSectionLogging *tmp =
++ (SilcServerConfigSectionLogging *) config->tmp;
++ int got_errno;
- /* Get class number */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret) {
- config->routers->class = atoi(tmp);
- silc_free(tmp);
- }
- SILC_SERVER_CONFIG_LIST_ALLOC(config->routers);
++ if (!strcmp(name, "quicklogs")) {
++ silc_log_quick = *(bool *)val;
++ }
++ else if (!strcmp(name, "flushdelay")) {
++ int flushdelay = *(int *)val;
++ if (flushdelay < 2) { /* this value was taken from silclog.h (min delay) */
++ fprintf(stderr, "Error: line %lu: invalid flushdelay value, use "
++ "quicklogs if you want real-time logging.\n", line);
++ return SILC_CONFIG_ESILENT;
++ }
++ silc_log_flushdelay = (long) flushdelay;
++ }
++#define FETCH_LOGGING_CHAN(__chan__, __member__) \
++ else if (!strcmp(name, __chan__)) { \
++ if (!tmp) return SILC_CONFIG_OK; \
++ if (!tmp->file) { \
++ got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err; \
++ } \
++ config->__member__ = tmp; \
++ config->tmp = NULL; \
++ }
++ FETCH_LOGGING_CHAN("info", logging_info)
++ FETCH_LOGGING_CHAN("warnings", logging_warnings)
++ FETCH_LOGGING_CHAN("errors", logging_errors)
++ FETCH_LOGGING_CHAN("fatals", logging_fatals)
++#undef FETCH_LOGGING_CHAN
++ else if (!strcmp(name, "file")) {
++ if (!tmp) { /* FIXME: what the fuck is this? */
++ config->tmp = silc_calloc(1, sizeof(*tmp));
++ tmp = (SilcServerConfigSectionLogging *) config->tmp;
++ }
++ if (tmp->file) {
++ got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err;
++ }
++ tmp->file = strdup((char *) val);
++ }
++ else if (!strcmp(name, "size")) {
++ if (!tmp) {
++ config->tmp = silc_calloc(1, sizeof(*tmp));
++ tmp = (SilcServerConfigSectionLogging *) config->tmp;
++ }
++ tmp->maxsize = *(uint32 *) val;
++ }
++ else
++ return SILC_CONFIG_EINTERNAL;
++ return SILC_CONFIG_OK;
++
++ got_err:
++ silc_free(tmp->file);
++ silc_free(tmp);
++ config->tmp = NULL;
++ return got_errno;
++}
- /* Get whether we are initiator or not */
- ret = silc_config_get_token(line, &tmp);
- /* Get host */
- ret = silc_config_get_token(line, &config->routers->host);
-- if (ret < 0)
-- break;
- if (ret) {
- config->routers->initiator = atoi(tmp);
- if (config->routers->initiator != 0)
- config->routers->initiator = TRUE;
- silc_free(tmp);
- }
- // if (ret == 0)
- ///* Any host */
- // config->routers->host = strdup("*");
++SILC_CONFIG_CALLBACK(fetch_client)
++{
++ SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionClient);
++
++ SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)", type, name, context));
++ if (type == SILC_CONFIG_ARG_BLOCK) {
++ if (!tmp) /* empty sub-block? */
++ return SILC_CONFIG_OK;
++ if (tmp->auth_meth && !tmp->auth_data) {
++ fprintf(stderr, "\nError: line %lu: If you specify \"AuthMethod\" field "
++ "then you must also specify the \"AuthData\" field.\n", line);
++ got_errno = SILC_CONFIG_ESILENT;
++ goto got_err;
++ }
++ SILC_SERVER_CONFIG_LIST_APPENDTMP(config->clients);
++ config->tmp = NULL;
++ return SILC_CONFIG_OK;
++ }
++ /* if there isn't a temporary struct alloc one */
++ if (!tmp) {
++ config->tmp = silc_calloc(1, sizeof(*findtmp));
++ tmp = (SilcServerConfigSectionClient *) config->tmp;
++ }
- /* Get backup replace IP */
- ret = silc_config_get_token(line, &config->routers->backup_replace_ip);
- if (ret != -1)
- config->routers->backup_router = TRUE;
-
- if (config->routers->backup_router) {
- /* Get backup replace port */
- ret = silc_config_get_token(line, &tmp);
- if (ret != -1) {
- config->routers->backup_replace_port = atoi(tmp);
- silc_free(tmp);
- }
-
- /* Check whether the backup connection is local */
- ret = silc_config_get_token(line, &tmp);
- if (ret != -1) {
- config->routers->backup_local = atoi(tmp);
- if (config->routers->backup_local != 0)
- config->routers->backup_local = TRUE;
- silc_free(tmp);
- /* Get authentication method */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret) {
- if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
- strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
- fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
- config->filename, pc->linenum, tmp);
- break;
-- }
- }
++ /* Identify and save this value */
++ if (!strcmp(name, "host")) { /* any host (*) accepted */
++ if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
++ tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
++ }
++ /* get authentication method */
++ else if (!strcmp(name, "authmethod")) {
++ if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
++ tmp->auth_meth = SILC_AUTH_PASSWORD;
++ else if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
++ tmp->auth_meth = SILC_AUTH_PUBLIC_KEY;
++ else {
++ got_errno = SILC_CONFIG_EINVALIDTEXT; goto got_err;
++ }
++ }
++ else if (!strcmp(name, "authdata")) {
++ if (!my_parse_authdata(tmp->auth_meth, (char *) val, line,
++ &tmp->auth_data, &tmp->auth_data_len)) {
++ got_errno = SILC_CONFIG_ESILENT;
++ goto got_err; /* error outputted in my_parse_authdata */
++ }
++ }
++ else if (!strcmp(name, "port")) {
++ int port = *(int *)val;
++ if ((port <= 0) || (port > 65535)) {
++ fprintf(stderr, "Invalid port number!\n");
++ got_errno = SILC_CONFIG_ESILENT; goto got_err;
++ }
++ tmp->port = (uint16) port;
++ }
++ /* FIXME: Improvement: use a direct class struct pointer instead of num */
++ else if (!strcmp(name, "class")) {
++ /* XXX do nothing */
++ }
++ else
++ return SILC_CONFIG_EINTERNAL;
++ return SILC_CONFIG_OK;
++
++ got_err:
++ silc_free(tmp->host);
++ my_free_authdata(tmp->auth_meth, tmp->auth_data);
++ silc_free(tmp);
++ return got_errno;
++}
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
- if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
- config->routers->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
++SILC_CONFIG_CALLBACK(fetch_admin)
++{
++ SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionAdmin);
++
++ SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)", type, name, context));
++ if (type == SILC_CONFIG_ARG_BLOCK) {
++ /* check the temporary struct's fields */
++ if (!tmp) /* empty sub-block? */
++ return SILC_CONFIG_OK;
++ if (!tmp->auth_meth) {
++ got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err;
++ }
++ SILC_SERVER_CONFIG_LIST_APPENDTMP(config->admins);
++ config->tmp = NULL;
++ return SILC_CONFIG_OK;
++ }
++ /* if there isn't a temporary struct alloc one */
++ if (!tmp) {
++ config->tmp = silc_calloc(1, sizeof(*findtmp));
++ tmp = (SilcServerConfigSectionAdmin *) config->tmp;
++ }
- case SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION:
- if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
- config->routers->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
++ /* Identify and save this value */
++ if (!strcmp(name, "host")) { /* any host (*) accepted */
++ if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
++ tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
++ }
++ else if (!strcmp(name, "user")) {
++ if (tmp->user) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
++ tmp->user = (*(char *)val ? strdup((char *) val) : NULL);
++ }
++ else if (!strcmp(name, "nick")) {
++ if (tmp->nick) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
++ tmp->nick = (*(char *)val ? strdup((char *) val) : NULL);
++ }
++ /* get authentication method */
++ else if (!strcmp(name, "authmethod")) {
++ if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
++ tmp->auth_meth = SILC_AUTH_PASSWORD;
++ else if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
++ tmp->auth_meth = SILC_AUTH_PUBLIC_KEY;
++ else {
++ got_errno = SILC_CONFIG_EINVALIDTEXT; goto got_err;
++ }
++ }
++ else if (!strcmp(name, "authdata")) {
++ if (!my_parse_authdata(tmp->auth_meth, (char *) val, line,
++ &tmp->auth_data, &tmp->auth_data_len)) {
++ got_errno = SILC_CONFIG_ESILENT;
++ goto got_err; /* error outputted in my_parse_authdata */
++ }
++ }
++ else
++ return SILC_CONFIG_EINTERNAL;
++ return SILC_CONFIG_OK;
++
++ got_err:
++ silc_free(tmp->host);
++ silc_free(tmp->user);
++ silc_free(tmp->nick);
++ my_free_authdata(tmp->auth_meth, tmp->auth_data);
++ silc_free(tmp);
++ return got_errno;
++}
- SILC_SERVER_CONFIG_LIST_ALLOC(config->admins);
- silc_free(tmp);
- }
++SILC_CONFIG_CALLBACK(fetch_deny)
++{
++ SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionDeny);
++
++ SERVER_CONFIG_DEBUG(("Received DENY type=%d name=\"%s\" (val=%x)", type, name, context));
++ if (type == SILC_CONFIG_ARG_BLOCK) {
++ /* check the temporary struct's fields */
++ if (!tmp) /* empty sub-block? */
++ return SILC_CONFIG_OK;
++ if (!tmp->reason) {
++ got_errno = SILC_CONFIG_EMISSFIELDS;
++ goto got_err;
++ }
++ SILC_SERVER_CONFIG_LIST_APPENDTMP(config->denied);
++ config->tmp = NULL;
++ return SILC_CONFIG_OK;
++ }
++ /* if there isn't a temporary struct alloc one */
++ if (!tmp) {
++ config->tmp = silc_calloc(1, sizeof(*findtmp));
++ tmp = (SilcServerConfigSectionDeny *) config->tmp;
++ }
- /* Get host */
- ret = silc_config_get_token(line, &config->admins->host);
- /* Get authentication data */
- ret = silc_config_get_token(line, &config->routers->auth_data);
-- if (ret < 0)
-- break;
- if (ret == 0)
- /* Any host */
- config->admins->host = strdup("*");
++ /* Identify and save this value */
++ if (!strcmp(name, "host")) { /* any host (*) accepted */
++ if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
++ tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
++ }
++ else if (!strcmp(name, "port")) {
++ int port = *(int *)val;
++ if ((port <= 0) || (port > 65535)) {
++ fprintf(stderr, "Invalid port number!\n");
++ got_errno = SILC_CONFIG_ESILENT; goto got_err;
++ }
++ tmp->port = (uint16) port;
++ }
++ else if (!strcmp(name, "reason")) {
++ if (tmp->reason) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
++ tmp->reason = strdup((char *) val);
++ }
++ else
++ return SILC_CONFIG_EINTERNAL;
++ return SILC_CONFIG_OK;
++
++ got_err:
++ silc_free(tmp->host);
++ silc_free(tmp->reason);
++ silc_free(tmp);
++ return got_errno;
++}
- /* Get username */
- ret = silc_config_get_token(line, &config->admins->username);
- /* Get port */
- ret = silc_config_get_token(line, &tmp);
-- if (ret < 0)
-- break;
- if (ret == 0)
- /* Any username */
- config->admins->username = strdup("*");
- if (ret) {
- config->routers->port = atoi(tmp);
- silc_free(tmp);
- }
++SILC_CONFIG_CALLBACK(fetch_server)
++{
++ SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionServer);
++
++ SERVER_CONFIG_DEBUG(("Received SERVER type=%d name=\"%s\" (val=%x)", type, name, context));
++ if (type == SILC_CONFIG_ARG_BLOCK) {
++ /* check the temporary struct's fields */
++ if (!tmp) /* empty sub-block? */
++ return SILC_CONFIG_OK;
++ if (!tmp->auth_meth || !tmp->version) {
++ got_errno = SILC_CONFIG_EMISSFIELDS;
++ goto got_err;
++ }
++ /* the temporary struct is ok, append it to the list */
++ SILC_SERVER_CONFIG_LIST_APPENDTMP(config->servers);
++ config->tmp = NULL;
++ return SILC_CONFIG_OK;
++ }
++ /* if there isn't a temporary struct alloc one */
++ if (!tmp) {
++ config->tmp = silc_calloc(1, sizeof(*findtmp));
++ tmp = (SilcServerConfigSectionServer *) config->tmp;
++ }
- /* Get nickname */
- ret = silc_config_get_token(line, &config->admins->nickname);
- /* Get version */
- ret = silc_config_get_token(line, &config->routers->version);
-- if (ret < 0)
-- break;
- if (ret == 0)
- /* Any nickname */
- config->admins->nickname = strdup("*");
++ /* Identify and save this value */
++ if (!strcmp(name, "host")) { /* any host (*) accepted */
++ if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
++ tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
++ }
++ /* get authentication method */
++ else if (!strcmp(name, "authmethod")) {
++ if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
++ tmp->auth_meth = SILC_AUTH_PASSWORD;
++ else if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
++ tmp->auth_meth = SILC_AUTH_PUBLIC_KEY;
++ else {
++ got_errno = SILC_CONFIG_EINVALIDTEXT; goto got_err;
++ }
++ }
++ else if (!strcmp(name, "authdata")) {
++ if (!my_parse_authdata(tmp->auth_meth, (char *) val, line,
++ &tmp->auth_data, &tmp->auth_data_len)) {
++ got_errno = SILC_CONFIG_ESILENT;
++ goto got_err; /* error outputted in my_parse_authdata */
++ }
++ }
++ else if (!strcmp(name, "port")) {
++ int port = *(int *)val;
++ if ((port <= 0) || (port > 65535)) {
++ fprintf(stderr, "Invalid port number!\n");
++ got_errno = SILC_CONFIG_ESILENT; goto got_err;
++ }
++ tmp->port = (uint16) port;
++ }
++ else if (!strcmp(name, "versionid")) {
++ if (tmp->version) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
++ tmp->version = strdup((char *) val);
++ }
++ /* FIXME: Improvement: use a direct class struct pointer instead of num */
++ else if (!strcmp(name, "class")) {
++ /* XXX do nothing */
++ }
++ else if (!strcmp(name, "backup")) {
++ tmp->backup_router = *(bool *)val;
++ }
++ else
++ return SILC_CONFIG_EINTERNAL;
++ return SILC_CONFIG_OK;
++
++ got_err:
++ silc_free(tmp->host);
++ silc_free(tmp->version);
++ my_free_authdata(tmp->auth_meth, tmp->auth_data);
++ silc_free(tmp);
++ return got_errno;
++}
- /* Get authentication method */
- /* Get class number */
-- ret = silc_config_get_token(line, &tmp);
-- if (ret < 0)
-- break;
-- if (ret) {
- if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
- strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
- fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
- config->filename, pc->linenum, tmp);
- break;
- }
- config->routers->class = atoi(tmp);
- silc_free(tmp);
- }
++SILC_CONFIG_CALLBACK(fetch_router)
++{
++ SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionRouter);
++
++ SERVER_CONFIG_DEBUG(("Received ROUTER type=%d name=\"%s\" (val=%x)", type, name, context));
++ if (type == SILC_CONFIG_ARG_BLOCK) {
++ if (!tmp) /* empty sub-block? */
++ return SILC_CONFIG_OK;
++ if (!tmp->auth_meth || !tmp->version) {
++ got_errno = SILC_CONFIG_EMISSFIELDS;
++ goto got_err;
++ }
++ /* the temporary struct is ok, append it to the list */
++ SILC_SERVER_CONFIG_LIST_APPENDTMP(config->routers);
++ config->tmp = NULL;
++ return SILC_CONFIG_OK;
++ }
++ /* if there isn't a temporary struct alloc one */
++ if (!tmp) {
++ config->tmp = silc_calloc(1, sizeof(*findtmp));
++ tmp = (SilcServerConfigSectionRouter *) config->tmp;
++ }
- if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
- config->admins->auth_meth = SILC_AUTH_PASSWORD;
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
++ /* Identify and save this value */
++ if (!strcmp(name, "host")) {
++ if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
++ tmp->host = strdup((char *) val);
++ }
++ else if (!strcmp(name, "authmethod")) {
++ if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
++ tmp->auth_meth = SILC_AUTH_PASSWORD;
++ else if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
++ tmp->auth_meth = SILC_AUTH_PUBLIC_KEY;
++ else {
++ got_errno = SILC_CONFIG_EINVALIDTEXT; goto got_err;
++ }
++ }
++ else if (!strcmp(name, "authdata")) {
++ if (!my_parse_authdata(tmp->auth_meth, (char *) val, line,
++ &tmp->auth_data, &tmp->auth_data_len)) {
++ got_errno = SILC_CONFIG_ESILENT;
++ goto got_err; /* error outputted in my_parse_authdata */
++ }
++ }
++ else if (!strcmp(name, "port")) {
++ int port = *(int *)val;
++ if ((port <= 0) || (port > 65535)) {
++ fprintf(stderr, "Invalid port number!\n");
++ got_errno = SILC_CONFIG_ESILENT; goto got_err;
++ }
++ tmp->port = (uint16) port;
++ }
++ else if (!strcmp(name, "versionid")) {
++ if (tmp->version) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
++ tmp->version = strdup((char *) val);
++ }
++ /* FIXME: Improvement: use a direct class struct pointer instead of num */
++ else if (!strcmp(name, "class")) {
++ /* XXX do nothing */
++ }
++ else if (!strcmp(name, "initiator"))
++ tmp->initiator = *(bool *)val;
++ else if (!strcmp(name, "backuphost")) {
++ if (tmp->backup_replace_ip) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
++ tmp->backup_replace_ip = (*(char *)val ? strdup((char *) val) : strdup("*"));
++ }
++ else
++ return SILC_CONFIG_EINTERNAL;
++ return SILC_CONFIG_OK;
++
++ got_err:
++ silc_free(tmp->host);
++ silc_free(tmp->version);
++ silc_free(tmp->backup_replace_ip);
++ my_free_authdata(tmp->auth_meth, tmp->auth_data);
++ silc_free(tmp);
++ return got_errno;
++}
- if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
- config->admins->auth_meth = SILC_AUTH_PUBLIC_KEY;
- case SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION:
++/* known config options tables */
++static const SilcConfigTable table_general[] = {
++ { "modulepath", SILC_CONFIG_ARG_STRE, fetch_generic, NULL },
++ { 0, 0, 0, 0 }
++};
- silc_free(tmp);
- }
- SILC_SERVER_CONFIG_LIST_ALLOC(config->admins);
++static const SilcConfigTable table_cipher[] = {
++ { "name", SILC_CONFIG_ARG_STR, fetch_cipher, NULL },
++ { "module", SILC_CONFIG_ARG_STRE, fetch_cipher, NULL },
++ { "key_length", SILC_CONFIG_ARG_INT, fetch_cipher, NULL },
++ { "block_length", SILC_CONFIG_ARG_INT, fetch_cipher, NULL },
++ { 0, 0, 0, 0 }
++};
- /* Get authentication data */
- ret = silc_config_get_token(line, (char **)&config->admins->auth_data);
- /* Get host */
- ret = silc_config_get_token(line, &config->admins->host);
-- if (ret < 0)
-- break;
- if (ret == 0)
- /* Any host */
- config->admins->host = strdup("*");
++static const SilcConfigTable table_hash[] = {
++ { "name", SILC_CONFIG_ARG_STR, fetch_hash, NULL },
++ { "module", SILC_CONFIG_ARG_STRE, fetch_hash, NULL },
++ { "block_length", SILC_CONFIG_ARG_INT, fetch_hash, NULL },
++ { "digest_length", SILC_CONFIG_ARG_INT, fetch_hash, NULL },
++ { 0, 0, 0, 0 }
++};
- if (config->admins->auth_meth == SILC_AUTH_PASSWORD) {
- config->admins->auth_data_len = strlen(config->admins->auth_data);
- } else if (config->admins->auth_meth == SILC_AUTH_PUBLIC_KEY) {
- /* Get the public key */
- SilcPublicKey public_key;
-
- if (!silc_pkcs_load_public_key(config->admins->auth_data,
- &public_key, SILC_PKCS_FILE_PEM))
- if (!silc_pkcs_load_public_key(config->admins->auth_data,
- &public_key, SILC_PKCS_FILE_BIN)) {
- fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
- config->filename, pc->linenum,
- (char *)config->admins->auth_data);
- break;
- }
-
- silc_free(config->admins->auth_data);
- config->admins->auth_data = (void *)public_key;
- config->admins->auth_data_len = 0;
- }
- /* Get authentication method */
- ret = silc_config_get_token(line, &tmp);
- if (ret < 0)
- break;
- if (ret) {
- if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
- strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
- fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
- config->filename, pc->linenum, tmp);
- break;
- }
++static const SilcConfigTable table_hmac[] = {
++ { "name", SILC_CONFIG_ARG_STR, fetch_hmac, NULL },
++ { "hash", SILC_CONFIG_ARG_STR, fetch_hmac, NULL },
++ { "mac_length", SILC_CONFIG_ARG_INT, fetch_hmac, NULL },
++ { 0, 0, 0, 0 }
++};
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
- if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
- config->admins->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
++static const SilcConfigTable table_pkcs[] = {
++ { "name", SILC_CONFIG_ARG_STR, fetch_pkcs, NULL },
++ { 0, 0, 0, 0 }
++};
- case SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION:
- if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
- config->admins->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
++static const SilcConfigTable table_serverinfo[] = {
++ { "hostname", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL},
++ { "ip", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL},
++ { "port", SILC_CONFIG_ARG_INT, fetch_serverinfo, NULL},
++ { "servertype", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL},
++ { "location", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL},
++ { "admin", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL},
++ { "email", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL},
++ { "user", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL},
++ { "group", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL},
++ { "publickey", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL},
++ { "privatekey", SILC_CONFIG_ARG_STR, fetch_serverinfo, NULL},
++ { "motdfile", SILC_CONFIG_ARG_STRE, fetch_serverinfo, NULL},
++ { "pidfile", SILC_CONFIG_ARG_STRE, fetch_serverinfo, NULL},
++ { 0, 0, 0, 0 }
++};
- SILC_SERVER_CONFIG_LIST_ALLOC(config->denied);
- silc_free(tmp);
- }
++static const SilcConfigTable table_logging_c[] = {
++ { "file", SILC_CONFIG_ARG_STR, fetch_logging, NULL },
++ { "size", SILC_CONFIG_ARG_SIZE, fetch_logging, NULL },
++/*{ "quicklog", SILC_CONFIG_ARG_NONE, fetch_logging, NULL }, */
++ { 0, 0, 0, 0 }
++};
- /* Get host */
- ret = silc_config_get_token(line, &config->denied->host);
- /* Get authentication data */
- ret = silc_config_get_token(line, &config->admins->auth_data);
-- if (ret < 0)
-- break;
- if (ret == 0) {
- /* Any host */
- config->denied->host = strdup("*");
- fprintf(stderr, "warning: %s:%d: Denying all connections",
- config->filename, pc->linenum);
- }
++static const SilcConfigTable table_logging[] = {
++ { "quicklogs", SILC_CONFIG_ARG_TOGGLE, fetch_logging, NULL },
++ { "flushdelay", SILC_CONFIG_ARG_INT, fetch_logging, NULL },
++ { "info", SILC_CONFIG_ARG_BLOCK, fetch_logging, table_logging_c },
++ { "warnings", SILC_CONFIG_ARG_BLOCK, fetch_logging, table_logging_c },
++ { "errors", SILC_CONFIG_ARG_BLOCK, fetch_logging, table_logging_c },
++ { "fatals", SILC_CONFIG_ARG_BLOCK, fetch_logging, table_logging_c },
++ { 0, 0, 0, 0 }
++};
- /* Get port */
- ret = silc_config_get_token(line, &tmp);
- /* Get nickname */
- ret = silc_config_get_token(line, &config->admins->nickname);
-- if (ret < 0)
-- break;
- if (ret == 0) {
- /* Any port */
- config->denied->port = 0;
- } else {
- config->denied->port = atoi(tmp);
- silc_free(tmp);
- }
++/* still unsupported
++static const SilcConfigTable table_class[] = {
++ { "name", SILC_CONFIG_ARG_STR, fetch_class, NULL },
++ { "ping", SILC_CONFIG_ARG_INT, fetch_class, NULL },
++ { "connect", SILC_CONFIG_ARG_INT, fetch_class, NULL },
++ { "links", SILC_CONFIG_ARG_INT, fetch_class, NULL },
++ { 0, 0, 0, 0 }
++}; */
++
++static const SilcConfigTable table_client[] = {
++ { "host", SILC_CONFIG_ARG_STRE, fetch_client, NULL },
++ { "authmethod", SILC_CONFIG_ARG_STR, fetch_client, NULL },
++ { "authdata", SILC_CONFIG_ARG_STR, fetch_client, NULL },
++ { "port", SILC_CONFIG_ARG_INT, fetch_client, NULL },
++ { "class", SILC_CONFIG_ARG_STR, fetch_client, NULL },
++ { 0, 0, 0, 0 }
++};
- /* Get comment */
- ret = silc_config_get_token(line, &config->denied->comment);
- /* Get class number */
- ret = silc_config_get_token(line, &tmp);
-- if (ret < 0)
-- break;
- if (ret) {
- config->admins->class = atoi(tmp);
- silc_free(tmp);
- }
++static const SilcConfigTable table_admin[] = {
++ { "host", SILC_CONFIG_ARG_STRE, fetch_admin, NULL },
++ { "user", SILC_CONFIG_ARG_STRE, fetch_admin, NULL },
++ { "nick", SILC_CONFIG_ARG_STRE, fetch_admin, NULL },
++ { "authmethod", SILC_CONFIG_ARG_STR, fetch_admin, NULL },
++ { "authdata", SILC_CONFIG_ARG_STR, fetch_admin, NULL },
++ { "port", SILC_CONFIG_ARG_INT, fetch_admin, NULL },
++ { "class", SILC_CONFIG_ARG_STR, fetch_admin, NULL },
++ { 0, 0, 0, 0 }
++};
-- check = TRUE;
-- checkmask |= (1L << pc->section->type);
-- break;
++static const SilcConfigTable table_deny[] = {
++ { "host", SILC_CONFIG_ARG_STRE, fetch_deny, NULL },
++ { "port", SILC_CONFIG_ARG_INT, fetch_deny, NULL },
++ { "reason", SILC_CONFIG_ARG_STR, fetch_deny, NULL },
++ { 0, 0, 0, 0 }
++};
- case SILC_CONFIG_SERVER_SECTION_TYPE_MOTD:
- case SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION:
- /* Not implemented yet */
- check = TRUE;
- break;
++static const SilcConfigTable table_serverconn[] = {
++ { "host", SILC_CONFIG_ARG_STRE, fetch_server, NULL },
++ { "authmethod", SILC_CONFIG_ARG_STR, fetch_server, NULL },
++ { "authdata", SILC_CONFIG_ARG_STR, fetch_server, NULL },
++ { "port", SILC_CONFIG_ARG_INT, fetch_server, NULL },
++ { "versionid", SILC_CONFIG_ARG_STR, fetch_server, NULL },
++ { "class", SILC_CONFIG_ARG_STR, fetch_server, NULL },
++ { "backup", SILC_CONFIG_ARG_TOGGLE, fetch_server, NULL },
++ { 0, 0, 0, 0 }
++};
- if (!config->motd)
- config->motd = silc_calloc(1, sizeof(*config->motd));
- case SILC_CONFIG_SERVER_SECTION_TYPE_REDIRECT_CLIENT:
- /* Not implemented yet */
- check = TRUE;
- break;
++static const SilcConfigTable table_routerconn[] = {
++ { "host", SILC_CONFIG_ARG_STRE, fetch_router, NULL },
++ { "authmethod", SILC_CONFIG_ARG_STR, fetch_router, NULL },
++ { "authdata", SILC_CONFIG_ARG_STR, fetch_router, NULL },
++ { "port", SILC_CONFIG_ARG_INT, fetch_router, NULL },
++ { "versionid", SILC_CONFIG_ARG_STR, fetch_router, NULL },
++ { "class", SILC_CONFIG_ARG_STR, fetch_router, NULL },
++ { "initiator", SILC_CONFIG_ARG_TOGGLE, fetch_router, NULL },
++ { "backuphost", SILC_CONFIG_ARG_STRE, fetch_router, NULL },
++ { "backupport", SILC_CONFIG_ARG_INT, fetch_router, NULL },
++ { "localbackup", SILC_CONFIG_ARG_TOGGLE, fetch_router, NULL },
++ { 0, 0, 0, 0 }
++};
- /* Get motd file */
- ret = silc_config_get_token(line, &config->motd->motd_file);
- if (ret < 0)
- break;
- case SILC_CONFIG_SERVER_SECTION_TYPE_NONE:
- default:
- /* Error */
- break;
- }
++static const SilcConfigTable table_main[] = {
++ { "general", SILC_CONFIG_ARG_BLOCK, NULL, table_general },
++ { "cipher", SILC_CONFIG_ARG_BLOCK, fetch_cipher, table_cipher },
++ { "hash", SILC_CONFIG_ARG_BLOCK, fetch_hash, table_hash },
++ { "hmac", SILC_CONFIG_ARG_BLOCK, fetch_hmac, table_hmac },
++ { "pkcs", SILC_CONFIG_ARG_BLOCK, fetch_pkcs, table_pkcs },
++ { "serverinfo", SILC_CONFIG_ARG_BLOCK, fetch_serverinfo, table_serverinfo },
++ { "logging", SILC_CONFIG_ARG_BLOCK, NULL, table_logging },
++/*{ "class", SILC_CONFIG_ARG_BLOCK, fetch_class, table_class }, */
++ { "client", SILC_CONFIG_ARG_BLOCK, fetch_client, table_client },
++ { "admin", SILC_CONFIG_ARG_BLOCK, fetch_admin, table_admin },
++ { "deny", SILC_CONFIG_ARG_BLOCK, fetch_deny, table_deny },
++ { "serverconnection", SILC_CONFIG_ARG_BLOCK, fetch_server, table_serverconn },
++ { "routerconnection", SILC_CONFIG_ARG_BLOCK, fetch_router, table_routerconn },
++ { 0, 0, 0, 0 }
++};
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- /* Check for error */
- if (check == FALSE) {
- /* Line could not be parsed */
- fprintf(stderr, "%s:%d: Parse error\n", config->filename, pc->linenum);
-- break;
++/* Allocates a new configuration object, opens configuration file and
++ * parses it. The parsed data is returned to the newly allocated
++ * configuration object. */
+
- case SILC_CONFIG_SERVER_SECTION_TYPE_PID:
-
- if (!config->pidfile)
- config->pidfile = silc_calloc(1, sizeof(*config->pidfile));
-
- ret = silc_config_get_token(line, &config->pidfile->pid_file);
- if (ret < 0)
- break;
-
- check = TRUE;
- checkmask |= (1L << pc->section->type);
- break;
-
- case SILC_CONFIG_SERVER_SECTION_TYPE_NONE:
- default:
- /* Error */
- break;
- }
++SilcServerConfig silc_server_config_alloc(char *filename)
++{
++ SilcServerConfig config;
++ SilcConfigEntity ent;
++ SilcConfigFile *file;
++ int ret;
++ SILC_LOG_DEBUG(("Loading config data from `%s'", filename));
+
- /* Check for error */
- if (check == FALSE) {
- /* Line could not be parsed */
- fprintf(stderr, "%s:%d: Parse error\n", config->filename, pc->linenum);
- break;
++ /* alloc a config object */
++ config = (SilcServerConfig) silc_calloc(1, sizeof(*config));
++ /* obtain a config file object */
++ file = silc_config_open(filename);
++ if (!file) {
++ fprintf(stderr, "\nError: can't open config file `%s'\n", filename);
++ return NULL;
++ }
++ /* obtain a SilcConfig entity, we can use it to start the parsing */
++ ent = silc_config_init(file);
++ /* load the known configuration options, give our empty object as context */
++ silc_config_register_table(ent, table_main, (void *) config);
++ /* enter the main parsing loop. When this returns, we have the parsing
++ * result and the object filled (or partially, in case of errors). */
++ ret = silc_config_main(ent);
++ SILC_LOG_DEBUG(("Parser returned [ret=%d]: %s", ret, silc_config_strerror(ret)));
++
++ /* Check if the parser returned errors */
++ if (ret) {
++ /* handle this special error return which asks to quietly return */
++ if (ret != SILC_CONFIG_ESILENT) {
++ char *linebuf, *filename = silc_config_get_filename(file);
++ uint32 line = silc_config_get_line(file);
++ fprintf(stderr, "\nError while parsing config file: %s.\n",
++ silc_config_strerror(ret));
++ linebuf = silc_config_read_line(file, line);
++ fprintf(stderr, " file %s line %lu: %s\n\n", filename, line, linebuf);
++ silc_free(linebuf);
}
-
- pc = pc->next;
++ return NULL;
+ }
++ /* close (destroy) the file object */
++ silc_config_close(file);
- pc = pc->next;
- /* XXXX */
- // silc_free(pc->prev);
- // pc->prev = NULL;
- }
-
-- if (check == FALSE)
- return FALSE;
- return FALSE;;
--
-- /* Check that all mandatory sections really were found. If not, the server
-- cannot function and we return error. */
- ret = silc_server_config_check_sections(checkmask);
- ret = silc_config_server_check_sections(checkmask);
-- if (ret == FALSE) {
-- /* XXX */
--
-- }
--
-- /* Before returning all the lists in the config object must be set
-- to their first values (the last value is first here). */
-- while (config->cipher && config->cipher->prev)
-- config->cipher = config->cipher->prev;
-- while (config->pkcs && config->pkcs->prev)
-- config->pkcs = config->pkcs->prev;
-- while (config->hash_func && config->hash_func->prev)
-- config->hash_func = config->hash_func->prev;
- while (config->hmac && config->hmac->prev)
- config->hmac = config->hmac->prev;
-- while (config->listen_port && config->listen_port->prev)
-- config->listen_port = config->listen_port->prev;
-- while (config->logging && config->logging->prev)
-- config->logging = config->logging->prev;
-- while (config->conn_class && config->conn_class->prev)
-- config->conn_class = config->conn_class->prev;
-- while (config->clients && config->clients->prev)
-- config->clients = config->clients->prev;
-- while (config->servers && config->servers->prev)
-- config->servers = config->servers->prev;
- while (config->admins && config->admins->prev)
- config->admins = config->admins->prev;
-- while (config->routers && config->routers->prev)
-- config->routers = config->routers->prev;
--
-- SILC_LOG_DEBUG(("Done"));
--
-- return TRUE;
++ /* XXX FIXME: check for missing mandatory fields */
++ if (!config->server_info) {
++ fprintf(stderr, "\nError: Missing mandatory block `server_info'\n");
++ return NULL;
++ }
++ return config;
}
--/* This function checks that the mask sent as argument includes all the
-- sections that are mandatory in SILC server. */
++/* ... */
- int silc_server_config_check_sections(uint32 checkmask)
-int silc_config_server_check_sections(unsigned int checkmask)
++void silc_server_config_destroy(SilcServerConfig config)
{
-- if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO))) {
--
-- return FALSE;
++ void *tmp;
++ silc_free(config->module_path);
++
++ /* Destroy Logging channels */
++ if (config->logging_info)
++ silc_free(config->logging_info->file);
++ if (config->logging_warnings)
++ silc_free(config->logging_warnings->file);
++ if (config->logging_errors)
++ silc_free(config->logging_errors->file);
++ if (config->logging_fatals)
++ silc_free(config->logging_fatals->file);
++
++ /* Destroy the ServerInfo struct */
++ if (config->server_info) {
++ register SilcServerConfigSectionServerInfo *si = config->server_info;
++ silc_free(si->server_name);
++ silc_free(si->server_ip);
++ silc_free(si->server_type);
++ silc_free(si->location);
++ silc_free(si->admin);
++ silc_free(si->email);
++ silc_free(si->user);
++ silc_free(si->group);
++ silc_free(si->motd_file);
++ silc_free(si->pid_file);
}
-- if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO))) {
--
-- return FALSE;
++
++ /* Now let's destroy the lists */
++
++ SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionCipher,
++ config->cipher)
++ silc_free(di->name);
++ silc_free(di->module);
++ silc_free(di);
}
-- if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT))) {
--
-- return FALSE;
++ SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionHash, config->hash)
++ silc_free(di->name);
++ silc_free(di->module);
++ silc_free(di);
}
- if (!(checkmask &
- (1L << SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION))) {
- if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION))) {
--
-- return FALSE;
++ SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionHmac, config->hmac)
++ silc_free(di->name);
++ silc_free(di->hash);
++ silc_free(di);
}
-- if (!(checkmask
-- & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION))) {
--
-- return FALSE;
++ SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionPkcs, config->pkcs)
++ silc_free(di->name);
++ silc_free(di);
}
- if (!(checkmask
- if (!(checkmask
-- & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION))) {
-
-
-- return FALSE;
++ SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionClient,
++ config->clients)
++ silc_free(di->host);
++ my_free_authdata(di->auth_meth, di->auth_data);
++ silc_free(di);
}
--
-- return TRUE;
--}
--
--/* Sets log files where log messages is saved by the server. */
--
- void silc_server_config_setlogfiles(SilcServerConfig config, SilcSchedule sked)
-void silc_config_server_setlogfiles(SilcConfigServer config)
--{
- long tmp;
- SilcServerConfigSectionLogging *log;
- SilcConfigServerSectionLogging *log;
- char *info, *warning, *error, *fatal;
- unsigned int info_size, warning_size, error_size, fatal_size;
--
-- SILC_LOG_DEBUG(("Setting configured log file names"));
-
- /* Set default files before checking configuration */
- info = SILC_LOG_FILE_INFO;
- warning = SILC_LOG_FILE_WARNING;
- error = SILC_LOG_FILE_ERROR;
- fatal = SILC_LOG_FILE_FATAL;
- info_size = 0;
- warning_size = 0;
- error_size = 0;
- fatal_size = 0;
-
-- log = config->logging;
- while (log) {
- /* Logging Files */
- if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_INFO))
- silc_log_set_file(SILC_LOG_INFO, log->filename, log->maxsize, sked);
- if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_WARNING))
- silc_log_set_file(SILC_LOG_WARNING, log->filename, log->maxsize, sked);
- if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_ERROR))
- silc_log_set_file(SILC_LOG_ERROR, log->filename, log->maxsize, sked);
- if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_FATAL))
- silc_log_set_file(SILC_LOG_FATAL, log->filename, log->maxsize, sked);
- /* Logging Options */
- if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LO_QUICK)) {
- if (!strcasecmp(log->filename, "yes") ||
- !strcasecmp(log->filename, "on"))
- silc_log_quick = TRUE;
- while(log) {
- if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_INFO)) {
- info = log->filename;
- info_size = log->maxsize;
-- }
- if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LO_FDELAY)) {
- tmp = atol(log->filename);
- if (tmp > 0)
- silc_log_flushdelay = tmp;
- else {
- fprintf(stderr, "config: invalid flushdelay value, use quicklogs if "
- "you want real-time logging.\n");
- exit(1);
- }
- if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_WARNING)) {
- warning = log->filename;
- warning_size = log->maxsize;
- }
- if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_ERROR)) {
- error = log->filename;
- error_size = log->maxsize;
- }
- if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_FATAL)) {
- fatal = log->filename;
- fatal_size = log->maxsize;
-- }
--
-- log = log->next;
++ SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionAdmin, config->admins)
++ silc_free(di->host);
++ silc_free(di->user);
++ silc_free(di->nick);
++ my_free_authdata(di->auth_meth, di->auth_data);
++ silc_free(di);
++ }
++ SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionDeny, config->denied)
++ silc_free(di->host);
++ silc_free(di->reason);
++ silc_free(di);
++ }
++ SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionServer,
++ config->servers)
++ silc_free(di->host);
++ silc_free(di->version);
++ my_free_authdata(di->auth_meth, di->auth_data);
++ silc_free(di);
++ }
++ SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionRouter,
++ config->routers)
++ silc_free(di->host);
++ silc_free(di->version);
++ silc_free(di->backup_replace_ip);
++ my_free_authdata(di->auth_meth, di->auth_data);
++ silc_free(di);
}
-
- silc_log_set_files(info, info_size, warning, warning_size,
- error, error_size, fatal, fatal_size);
}
/* Registers configured ciphers. These can then be allocated by the
server when needed. */
- bool silc_server_config_register_ciphers(SilcServerConfig config)
-void silc_config_server_register_ciphers(SilcConfigServer config)
++bool silc_server_config_register_ciphers(SilcServer server)
{
- SilcServerConfigSectionAlg *alg;
- SilcConfigServerSectionAlg *alg;
-- SilcServer server = (SilcServer)config->server;
++ SilcServerConfig config = server->config;
++ SilcServerConfigSectionCipher *cipher = config->cipher;
++ char *module_path = config->module_path;
SILC_LOG_DEBUG(("Registering configured ciphers"));
- if (!config->cipher)
- alg = config->cipher;
- while(alg) {
-
- if (!alg->sim_name) {
- /* Crypto module is supposed to be built in. Nothing to be done
- here except to test that the cipher really is built in. */
- SilcCipher tmp = NULL;
++ if (!cipher) /* any cipher in the config file? */
+ return FALSE;
- alg = config->cipher;
- while(alg) {
-
- if (!alg->sim_name) {
- if (silc_cipher_alloc(alg->alg_name, &tmp) == FALSE) {
- SILC_LOG_ERROR(("Unsupported cipher `%s'", alg->alg_name));
++ while (cipher) {
++ /* if there isn't a module_path OR there isn't a module sim name try to
++ * use buil-in functions */
++ if (!module_path || !cipher->module) {
+ int i;
-
+ for (i = 0; silc_default_ciphers[i].name; i++)
- if (!strcmp(silc_default_ciphers[i].name, alg->alg_name)) {
++ if (!strcmp(silc_default_ciphers[i].name, cipher->name)) {
+ silc_cipher_register(&silc_default_ciphers[i]);
+ break;
+ }
-
- if (!silc_cipher_is_supported(alg->alg_name)) {
- SILC_LOG_ERROR(("Unknown cipher `%s'", alg->alg_name));
++ if (!silc_cipher_is_supported(cipher->name)) {
++ SILC_LOG_ERROR(("Unknown cipher `%s'", cipher->name));
silc_server_stop(server);
exit(1);
}
- silc_cipher_free(tmp);
-
--#ifdef SILC_SIM
} else {
++#ifdef SILC_SIM
/* Load (try at least) the crypto SIM module */
-- SilcCipherObject cipher;
++ char buf[1023], *alg_name;
++ SilcCipherObject cipher_obj;
SilcSimContext *sim;
- char *alg_name;
-- memset(&cipher, 0, sizeof(cipher));
-- cipher.name = alg->alg_name;
-- cipher.block_len = alg->block_len;
-- cipher.key_len = alg->key_len * 8;
++ memset(&cipher_obj, 0, sizeof(cipher_obj));
++ cipher_obj.name = cipher->name;
++ cipher_obj.block_len = cipher->block_length;
++ cipher_obj.key_len = cipher->key_length * 8;
++ /* build the libname */
++ snprintf(buf, sizeof(buf), "%s/%s", config->module_path,
++ cipher->module);
sim = silc_sim_alloc();
sim->type = SILC_SIM_CIPHER;
-- sim->libname = alg->sim_name;
++ sim->libname = buf;
- alg_name = strdup(alg->alg_name);
- if ((silc_sim_load(sim))) {
- cipher.set_key =
- silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
++ alg_name = strdup(cipher->name);
+ if (strchr(alg_name, '-'))
+ *strchr(alg_name, '-') = '\0';
+
- if ((silc_sim_load(sim))) {
- cipher.set_key =
- silc_sim_getsym(sim, silc_sim_symname(alg_name,
++ if (silc_sim_load(sim)) {
++ cipher_obj.set_key =
++ silc_sim_getsym(sim, silc_sim_symname(alg_name,
SILC_CIPHER_SIM_SET_KEY));
-- SILC_LOG_DEBUG(("set_key=%p", cipher.set_key));
-- cipher.set_key_with_string =
- silc_sim_getsym(sim, silc_sim_symname(alg_name,
- silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
++ SILC_LOG_DEBUG(("set_key=%p", cipher_obj.set_key));
++ cipher_obj.set_key_with_string =
++ silc_sim_getsym(sim, silc_sim_symname(alg_name,
SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
-- SILC_LOG_DEBUG(("set_key_with_string=%p", cipher.set_key_with_string));
-- cipher.encrypt =
- silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
++ SILC_LOG_DEBUG(("set_key_with_string=%p", cipher_obj.set_key_with_string));
++ cipher_obj.encrypt =
+ silc_sim_getsym(sim, silc_sim_symname(alg_name,
SILC_CIPHER_SIM_ENCRYPT_CBC));
-- SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher.encrypt));
-- cipher.decrypt =
- silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
++ SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher_obj.encrypt));
++ cipher_obj.decrypt =
+ silc_sim_getsym(sim, silc_sim_symname(alg_name,
SILC_CIPHER_SIM_DECRYPT_CBC));
-- SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher.decrypt));
-- cipher.context_len =
- silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
++ SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher_obj.decrypt));
++ cipher_obj.context_len =
+ silc_sim_getsym(sim, silc_sim_symname(alg_name,
SILC_CIPHER_SIM_CONTEXT_LEN));
-- SILC_LOG_DEBUG(("context_len=%p", cipher.context_len));
++ SILC_LOG_DEBUG(("context_len=%p", cipher_obj.context_len));
- /* Put the SIM to the table of all SIM's in server */
- server->sim = silc_realloc(server->sim,
- sizeof(*server->sim) *
- (server->sim_count + 1));
- server->sim[server->sim_count] = sim;
- server->sim_count++;
+ /* Put the SIM to the list of all SIM's in server */
+ silc_dlist_add(server->sim, sim);
+
+ silc_free(alg_name);
} else {
SILC_LOG_ERROR(("Error configuring ciphers"));
silc_server_stop(server);
}
/* Register the cipher */
-- silc_cipher_register(&cipher);
--#endif
-- }
--
-- alg = alg->next;
-- }
-
- return TRUE;
--}
--
--/* Registers configured PKCS's. */
-/* XXX: This really doesn't do anything now since we have statically
- registered our PKCS's. This should be implemented when PKCS works
- as SIM's. This checks now only that the PKCS user requested is
- really out there. */
--
- bool silc_server_config_register_pkcs(SilcServerConfig config)
-void silc_config_server_register_pkcs(SilcConfigServer config)
--{
- SilcServerConfigSectionAlg *alg = config->pkcs;
- SilcConfigServerSectionAlg *alg = config->pkcs;
-- SilcServer server = (SilcServer)config->server;
- SilcPKCS tmp = NULL;
--
-- SILC_LOG_DEBUG(("Registering configured PKCS"));
-
- if (!config->pkcs)
- return FALSE;
--
-- while(alg) {
- int i;
-
- for (i = 0; silc_default_pkcs[i].name; i++)
- if (!strcmp(silc_default_pkcs[i].name, alg->alg_name)) {
- silc_pkcs_register(&silc_default_pkcs[i]);
- break;
- }
-
- if (!silc_pkcs_is_supported(alg->alg_name)) {
- SILC_LOG_ERROR(("Unknown PKCS `%s'", alg->alg_name));
-
- if (silc_pkcs_alloc(alg->alg_name, &tmp) == FALSE) {
- SILC_LOG_ERROR(("Unsupported PKCS `%s'", alg->alg_name));
++ silc_cipher_register(&cipher_obj);
++#else
++ SILC_LOG_ERROR(("Dynamic module support not compiled, "
++ "can't load modules!"));
silc_server_stop(server);
exit(1);
++#endif
}
-
- alg = alg->next;
- }
- silc_free(tmp);
++ cipher = cipher->next;
++ } /* while */
- alg = alg->next;
- }
+ return TRUE;
}
/* Registers configured hash functions. These can then be allocated by the
server when needed. */
- bool silc_server_config_register_hashfuncs(SilcServerConfig config)
-void silc_config_server_register_hashfuncs(SilcConfigServer config)
++bool silc_server_config_register_hashfuncs(SilcServer server)
{
- SilcServerConfigSectionAlg *alg;
- SilcConfigServerSectionAlg *alg;
-- SilcServer server = (SilcServer)config->server;
++ SilcServerConfig config = server->config;
++ SilcServerConfigSectionHash *hash = config->hash;
++ char *module_path = config->module_path;
SILC_LOG_DEBUG(("Registering configured hash functions"));
- if (!config->hash_func)
- alg = config->hash_func;
- while(alg) {
-
- if (!alg->sim_name) {
- /* Hash module is supposed to be built in. Nothing to be done
- here except to test that the hash function really is built in. */
- SilcHash tmp = NULL;
++ if (!hash) /* any hash func in the config file? */
+ return FALSE;
- alg = config->hash_func;
- while(alg) {
-
- if (!alg->sim_name) {
- if (silc_hash_alloc(alg->alg_name, &tmp) == FALSE) {
- SILC_LOG_ERROR(("Unsupported hash function `%s'", alg->alg_name));
++ while (hash) {
++ /* if there isn't a module_path OR there isn't a module sim name try to
++ * use buil-in functions */
++ if (!module_path || !hash->module) {
+ int i;
-
+ for (i = 0; silc_default_hash[i].name; i++)
- if (!strcmp(silc_default_hash[i].name, alg->alg_name)) {
++ if (!strcmp(silc_default_hash[i].name, hash->name)) {
+ silc_hash_register(&silc_default_hash[i]);
+ break;
+ }
-
- if (!silc_hash_is_supported(alg->alg_name)) {
- SILC_LOG_ERROR(("Unknown hash funtion `%s'", alg->alg_name));
++ if (!silc_hash_is_supported(hash->name)) {
++ SILC_LOG_ERROR(("Unknown hash funtion `%s'", hash->name));
silc_server_stop(server);
exit(1);
}
- silc_free(tmp);
--
--#ifdef SILC_SIM
} else {
++#ifdef SILC_SIM
/* Load (try at least) the hash SIM module */
-- SilcHashObject hash;
++ SilcHashObject hash_obj;
SilcSimContext *sim;
-- memset(&hash, 0, sizeof(hash));
-- hash.name = alg->alg_name;
-- hash.block_len = alg->block_len;
-- hash.hash_len = alg->key_len;
++ memset(&hash_obj, 0, sizeof(hash_obj));
++ hash_obj.name = hash->name;
++ hash_obj.block_len = hash->block_length;
++ hash_obj.hash_len = hash->digest_length;
sim = silc_sim_alloc();
sim->type = SILC_SIM_HASH;
-- sim->libname = alg->sim_name;
++ sim->libname = hash->module;
if ((silc_sim_load(sim))) {
-- hash.init =
-- silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
++ hash_obj.init =
++ silc_sim_getsym(sim, silc_sim_symname(hash->name,
SILC_HASH_SIM_INIT));
-- SILC_LOG_DEBUG(("init=%p", hash.init));
-- hash.update =
-- silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
++ SILC_LOG_DEBUG(("init=%p", hash_obj.init));
++ hash_obj.update =
++ silc_sim_getsym(sim, silc_sim_symname(hash->name,
SILC_HASH_SIM_UPDATE));
-- SILC_LOG_DEBUG(("update=%p", hash.update));
-- hash.final =
-- silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
++ SILC_LOG_DEBUG(("update=%p", hash_obj.update));
++ hash_obj.final =
++ silc_sim_getsym(sim, silc_sim_symname(hash->name,
SILC_HASH_SIM_FINAL));
-- SILC_LOG_DEBUG(("final=%p", hash.final));
-- hash.context_len =
-- silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
++ SILC_LOG_DEBUG(("final=%p", hash_obj.final));
++ hash_obj.context_len =
++ silc_sim_getsym(sim, silc_sim_symname(hash->name,
SILC_HASH_SIM_CONTEXT_LEN));
-- SILC_LOG_DEBUG(("context_len=%p", hash.context_len));
++ SILC_LOG_DEBUG(("context_len=%p", hash_obj.context_len));
/* Put the SIM to the table of all SIM's in server */
- server->sim = silc_realloc(server->sim,
- sizeof(*server->sim) *
- (server->sim_count + 1));
- server->sim[server->sim_count] = sim;
- server->sim_count++;
+ silc_dlist_add(server->sim, sim);
} else {
SILC_LOG_ERROR(("Error configuring hash functions"));
silc_server_stop(server);
exit(1);
}
- /* Register the cipher */
- silc_hash_register(&hash);
+ /* Register the hash function */
- silc_hash_register(&hash);
++ silc_hash_register(&hash_obj);
++#else
++ SILC_LOG_ERROR(("Dynamic module support not compiled, "
++ "can't load modules!"));
++ silc_server_stop(server);
++ exit(1);
#endif
}
-
- alg = alg->next;
- }
++ hash = hash->next;
++ } /* while */
- alg = alg->next;
- }
+ return TRUE;
}
-/* Returns client authentication information from server configuration
- by host (name or ip). */
+/* Registers configure HMACs. These can then be allocated by the server
+ when needed. */
- bool silc_server_config_register_hmacs(SilcServerConfig config)
-SilcConfigServerSectionClientConnection *
-silc_config_server_find_client_conn(SilcConfigServer config,
- char *host, int port)
++bool silc_server_config_register_hmacs(SilcServer server)
{
- SilcServerConfigSectionAlg *alg;
- SilcServer server = (SilcServer)config->server;
- int i;
- SilcConfigServerSectionClientConnection *client = NULL;
++ SilcServerConfig config = server->config;
++ SilcServerConfigSectionHmac *hmac = config->hmac;
+
+ SILC_LOG_DEBUG(("Registering configured HMACs"));
+
- if (!config->hmac)
++ if (!hmac)
+ return FALSE;
+
- alg = config->hmac;
- while(alg) {
- SilcHmacObject hmac;
-
- if (!silc_hash_is_supported(alg->sim_name)) {
- SILC_LOG_ERROR(("Unknown hash function `%s'", alg->sim_name));
++ while (hmac) {
++ SilcHmacObject hmac_obj;
++ if (!silc_hash_is_supported(hmac->hash)) {
++ SILC_LOG_ERROR(("Unknown hash function `%s'", hmac->hash));
+ silc_server_stop(server);
+ exit(1);
+ }
-
+ /* Register the HMAC */
- memset(&hmac, 0, sizeof(hmac));
- hmac.name = alg->alg_name;
- hmac.len = alg->key_len;
- silc_hmac_register(&hmac);
++ memset(&hmac_obj, 0, sizeof(hmac_obj));
++ hmac_obj.name = hmac->name;
++ hmac_obj.len = hmac->mac_length;
++ silc_hmac_register(&hmac_obj);
+
- alg = alg->next;
- }
++ hmac = hmac->next;
++ } /* while */
+
+ return TRUE;
+}
+
- /* Returns client authentication information from server configuration
- by host (name or ip). If `port' is non-null then both name or IP and
- the port must match. */
++/* Registers configured PKCS's. */
+
- SilcServerConfigSectionClientConnection *
- silc_server_config_find_client_conn(SilcServerConfig config,
- char *host, int port)
++bool silc_server_config_register_pkcs(SilcServer server)
+{
- int i;
- SilcServerConfigSectionClientConnection *client = NULL;
- bool match = FALSE;
++ SilcServerConfig config = server->config;
++ SilcServerConfigSectionPkcs *pkcs = config->pkcs;
+
- if (!host)
- return NULL;
++ SILC_LOG_DEBUG(("Registering configured PKCS"));
++
++ if (!pkcs)
++ return FALSE;
++
++ while (pkcs) {
++ int i;
++ for (i = 0; silc_default_pkcs[i].name; i++)
++ if (!strcmp(silc_default_pkcs[i].name, pkcs->name)) {
++ silc_pkcs_register(&silc_default_pkcs[i]);
++ break;
++ }
++ if (!silc_pkcs_is_supported(pkcs->name)) {
++ SILC_LOG_ERROR(("Unknown PKCS `%s'", pkcs->name));
++ silc_server_stop(server);
++ exit(1);
++ }
++ pkcs = pkcs->next;
++ } /* while */
++
++ return TRUE;
++}
++
++/* Sets log files where log messages are saved by the server logger. */
++
++void silc_server_config_setlogfiles(SilcServerConfig config,
++ SilcSchedule sked)
++{
++ SilcServerConfigSectionLogging *this;
++
++ SILC_LOG_DEBUG(("Setting configured log file names"));
+
- if (!config->clients)
++ if ((this = config->logging_info))
++ silc_log_set_file(SILC_LOG_INFO, this->file, this->maxsize, sked);
++ if ((this = config->logging_warnings))
++ silc_log_set_file(SILC_LOG_WARNING, this->file, this->maxsize, sked);
++ if ((this = config->logging_errors))
++ silc_log_set_file(SILC_LOG_ERROR, this->file, this->maxsize, sked);
++ if ((this = config->logging_fatals))
++ silc_log_set_file(SILC_LOG_FATAL, this->file, this->maxsize, sked);
++}
++
++/* Returns client authentication information from configuration file by host
++ (name or ip) */
++
++SilcServerConfigSectionClient *
++silc_server_config_find_client(SilcServerConfig config, char *host, int port)
++{
++ SilcServerConfigSectionClient *client;
+
++ if (!config || !port) {
++ SILC_LOG_WARNING(("Bogus: config_find_client(config=0x%08x, "
++ "host=0x%08x \"%s\", port=%hu)",
++ (uint32) config, (uint32) host, host, port));
++ return NULL;
++ }
+ if (!host)
return NULL;
- client = config->clients;
- if (!config->clients)
- return NULL;
++ for (client = config->clients; client; client = client->next) {
++ if (client->host && !silc_string_compare(client->host, host))
++ continue;
++ if (client->port && (client->port != port))
++ continue;
++ break;
++ }
++ /* if none matched, then client is already NULL */
++ return client;
++}
- for (i = 0; client; i++) {
- if (silc_string_compare(client->host, host))
- match = TRUE;
- client = config->clients;
++/* Returns admin connection configuration by host, username and/or
++ nickname. */
- if (port && client->port && client->port != port)
- match = FALSE;
- for (i = 0; client; i++) {
- if (silc_string_compare(client->host, host))
- break;
- client = client->next;
++SilcServerConfigSectionAdmin *
++silc_server_config_find_admin(SilcServerConfig config,
++ char *host, char *user, char *nick)
++{
++ SilcServerConfigSectionAdmin *admin;
+
- if (match)
- break;
++ /* make sure we have a value for the matching parameters */
++ if (!host)
++ host = "*";
++ if (!user)
++ user = "*";
++ if (!nick)
++ nick = "*";
+
- client = client->next;
++ for (admin = config->admins; admin; admin = admin->next) {
++ if (admin->host && !silc_string_compare(admin->host, host))
++ continue;
++ if (admin->user && !silc_string_compare(admin->user, user))
++ continue;
++ if (admin->nick && !silc_string_compare(admin->nick, nick))
++ continue;
++ /* no checks failed -> this entry matches */
++ break;
}
- if (!client)
++ /* if none matched, then admin is already NULL */
++ return admin;
++}
+
- if (!client)
++/* Returns the denied connection configuration entry by host and port. */
+
++SilcServerConfigSectionDeny *
++silc_server_config_find_denied(SilcServerConfig config,
++ char *host, uint16 port)
++{
++ SilcServerConfigSectionDeny *deny;
++
++ /* make sure we have a value for the matching parameters */
++ if (!config || !port) {
++ SILC_LOG_WARNING(("Bogus: config_find_denied(config=0x%08x, "
++ "host=0x%08x \"%s\", port=%hu)",
++ (uint32) config, (uint32) host, host, port));
++ return NULL;
++ }
++ if (!host)
return NULL;
-- return client;
++ for (deny = config->denied; deny; deny = deny->next) {
++ if (deny->host && !silc_string_compare(deny->host, host))
++ continue;
++ break;
++ }
++ /* if none matched, then deny is already NULL */
++ return deny;
}
--/* Returns server connection info from server configuartion by host
- (name or ip). */
++/* Returns server connection info from server configuartion by host
+ (name or ip). If `port' is non-null then both name or IP and the port
+ must match. */
- SilcServerConfigSectionServerConnection *
- silc_server_config_find_server_conn(SilcServerConfig config,
-SilcConfigServerSectionServerConnection *
-silc_config_server_find_server_conn(SilcConfigServer config,
++SilcServerConfigSectionServer *
++silc_server_config_find_server_conn(SilcServerConfig config,
char *host, int port)
{
int i;
- SilcServerConfigSectionServerConnection *serv = NULL;
- SilcConfigServerSectionServerConnection *serv = NULL;
++ SilcServerConfigSectionServer *serv = NULL;
+ bool match = FALSE;
if (!host)
return NULL;
return serv;
}
--/* Returns router connection info from server configuartion by
++/* Returns router connection info from server configuration by
host (name or ip). */
- SilcServerConfigSectionServerConnection *
- silc_server_config_find_router_conn(SilcServerConfig config,
-SilcConfigServerSectionServerConnection *
-silc_config_server_find_router_conn(SilcConfigServer config,
++SilcServerConfigSectionRouter *
++silc_server_config_find_router_conn(SilcServerConfig config,
char *host, int port)
{
int i;
- SilcServerConfigSectionServerConnection *serv = NULL;
- SilcConfigServerSectionServerConnection *serv = NULL;
++ SilcServerConfigSectionRouter *serv = NULL;
+ bool match = FALSE;
if (!host)
return NULL;
return serv;
}
- /* Returns TRUE if configuartion for a router connection that we are
-/* Prints out example configuration file with default built in
- configuration values. */
++/* Returns TRUE if configuration for a router connection that we are
+ initiating exists. */
-void silc_config_server_print()
+bool silc_server_config_is_primary_route(SilcServerConfig config)
{
- char *buf;
-
- buf = "\
-#\n\
-# Automatically generated example SILCd configuration file with default\n\
-# built in values. Use this as a guide to configure your SILCd configuration\n\
-# file for your system. For detailed description of different configuration\n\
-# sections refer to silcd(8) manual page.\n\
-#\n";
- /*
-#<Cipher>
-#+blowfish
-#+twofish
-#+rc5
-#+rc6
-#+3des
-
-#<HashFunction>
-#+md5
-#+sha1
-
-<ServerInfo>
-+lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:1333
-
-<AdminInfo>
-+Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
-
-<ListenPort>
-+10.2.1.6:10.2.1.6:1333
-
-<Logging>
-+infologfile:silcd.log:10000
-#+warninglogfile:/var/log/silcd_warning.log:10000
-#+errorlogfile:ERROR.log:10000
-#+fatallogfile:/var/log/silcd_error.log:
+ int i;
- SilcServerConfigSectionServerConnection *serv = NULL;
++ SilcServerConfigSectionRouter *serv = NULL;
+ bool found = FALSE;
-<ConnectionClass>
- +1:100:100:100
- +2:200:300:400
+ serv = config->routers;
+ for (i = 0; serv; i++) {
+ if (serv->initiator == TRUE && serv->backup_router == FALSE) {
+ found = TRUE;
+ break;
+ }
-<ClientAuth>
-+10.2.1.199:priikone:333:1
+ serv = serv->next;
+ }
-<AdminAuth>
-+10.2.1.199:priikone:priikone:1
+ return found;
+}
-<ServerConnection>
+/* Returns our primary connection configuration or NULL if we do not
+ have primary router configured. */
- SilcServerConfigSectionServerConnection *
-<RouterConnection>
++SilcServerConfigSectionRouter *
+silc_server_config_get_primary_router(SilcServerConfig config)
+{
+ int i;
- SilcServerConfigSectionServerConnection *serv = NULL;
++ SilcServerConfigSectionRouter *serv = NULL;
-<DenyConnection>
-<RedirectClient>
- */
+ serv = config->routers;
+ for (i = 0; serv; i++) {
+ if (serv->initiator == TRUE && serv->backup_router == FALSE)
+ return serv;
+ serv = serv->next;
+ }
- fprintf(stdout, "%s\n", buf);
+ return NULL;
}
-
- /* Returns Admin connection configuration by host, username and/or
- nickname. */
-
- SilcServerConfigSectionAdminConnection *
- silc_server_config_find_admin(SilcServerConfig config,
- char *host, char *username, char *nickname)
- {
- SilcServerConfigSectionAdminConnection *admin = NULL;
- int i;
-
- if (!config->admins)
- return NULL;
-
- if (!host)
- host = "*";
- if (!username)
- username = "*";
- if (!nickname)
- nickname = "*";
-
- admin = config->admins;
- for (i = 0; admin; i++) {
- if (silc_string_compare(admin->host, host) &&
- silc_string_compare(admin->username, username) &&
- silc_string_compare(admin->nickname, nickname))
- break;
-
- admin = admin->next;
- }
-
- if (!admin)
- return NULL;
-
- return admin;
- }
-
- /* Returns the Denied connection configuration by host and port. */
-
- SilcServerConfigSectionDenyConnection *
- silc_server_config_denied_conn(SilcServerConfig config, char *host,
- int port)
- {
- int i;
- SilcServerConfigSectionDenyConnection *deny = NULL;
- bool match = FALSE;
-
- if (!host)
- return NULL;
-
- if (!config->denied)
- return NULL;
-
- deny = config->denied;
- for (i = 0; deny; i++) {
- if (silc_string_compare(deny->host, host))
- match = TRUE;
-
- if (port && deny->port && deny->port != port)
- match = FALSE;
-
- if (match)
- break;
-
- deny = deny->next;
- }
-
- if (!deny)
- return NULL;
-
- return deny;
- }
serverconfig.h
-- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
++ Author: Johnny Mnemonic <johnny@themnemonic.org>
-- Copyright (C) 1997 - 2000 Pekka Riikonen
++ Copyright (C) 1997 - 2002 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; either version 2 of the License, or
(at your option) any later version.
--
++
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
#ifndef SERVERCONFIG_H
#define SERVERCONFIG_H
--/* Holds information of configured algorithms */
- typedef struct SilcServerConfigSectionAlgStruct {
-typedef struct SilcConfigServerSectionAlgStruct {
-- char *alg_name;
-- char *sim_name;
- uint32 block_len;
- uint32 key_len;
- struct SilcServerConfigSectionAlgStruct *next;
- struct SilcServerConfigSectionAlgStruct *prev;
- unsigned int block_len;
- unsigned int key_len;
- struct SilcConfigServerSectionAlgStruct *next;
- struct SilcConfigServerSectionAlgStruct *prev;
--#define SILC_CONFIG_SERVER_MODNAME "builtin"
- } SilcServerConfigSectionAlg;
-
- /* Holds server keys from config file */
- typedef struct {
- SilcPublicKey public_key;
- SilcPrivateKey private_key;
- } SilcServerConfigSectionServerKeys;
-} SilcConfigServerSectionAlg;
--
--/* Holds server information from config file */
--typedef struct {
++typedef struct SilcServerConfigSectionCipherStruct {
++ char *name;
++ char *module;
++ uint32 key_length;
++ uint32 block_length;
++ struct SilcServerConfigSectionCipherStruct *next;
++} SilcServerConfigSectionCipher;
++
++typedef struct SilcServerConfigSectionHashStruct {
++ char *name;
++ char *module;
++ uint32 block_length;
++ uint32 digest_length;
++ struct SilcServerConfigSectionHashStruct *next;
++} SilcServerConfigSectionHash;
++
++typedef struct SilcServerConfigSectionHmacStruct {
++ char *name;
++ char *hash;
++ uint32 mac_length;
++ struct SilcServerConfigSectionHmacStruct *next;
++} SilcServerConfigSectionHmac;
++
++typedef struct SilcServerConfigSectionPkcsStruct {
++ char *name;
++ struct SilcServerConfigSectionPkcsStruct *next;
++} SilcServerConfigSectionPkcs;
++
++typedef struct SilcServerConfigSectionServerInfoStruct {
char *server_name;
char *server_ip;
-- char *location;
- unsigned short port;
-} SilcConfigServerSectionServerInfo;
-
-/* Holds server's administrative information from config file */
-typedef struct {
- char *server_type;
- char *admin_name;
- char *admin_email;
-} SilcConfigServerSectionAdminInfo;
-
-/* Holds all the ports the server is listenning on */
-typedef struct SilcConfigServerSectionListenPortStruct {
- char *host;
- char *remote_ip;
- unsigned short port;
- struct SilcConfigServerSectionListenPortStruct *next;
- struct SilcConfigServerSectionListenPortStruct *prev;
-} SilcConfigServerSectionListenPort;
-
-/* Holds all the configured log files. */
-typedef struct SilcConfigServerSectionLoggingStruct {
- char *logtype;
- char *filename;
- unsigned int maxsize;
- struct SilcConfigServerSectionLoggingStruct *next;
- struct SilcConfigServerSectionLoggingStruct *prev;
-
-/* Allowed <Logging> section types */
-#define SILC_CONFIG_SERVER_LF_INFO "infologfile"
-#define SILC_CONFIG_SERVER_LF_WARNING "warninglogfile"
-#define SILC_CONFIG_SERVER_LF_ERROR "errorlogfile"
-#define SILC_CONFIG_SERVER_LF_FATAL "fatalogfile"
-} SilcConfigServerSectionLogging;
+ uint16 port;
++ char *server_type; /* E.g. "Test Server" */
++ char *location; /* geographic location */
++ char *admin; /* admin full name */
++ char *email; /* admin's email address */
++ char *user; /* userid the server should be runned at */
++ char *group; /* ditto, but about groupid */
++ SilcPublicKey public_key;
++ SilcPrivateKey private_key;
++ char *motd_file; /* path to text motd file (reading only) */
++ char *pid_file; /* path to the pid file (for reading and writing) */
+} SilcServerConfigSectionServerInfo;
+
- /* Holds server's administrative information from config file */
- typedef struct {
- char *location;
- char *server_type;
- char *admin_name;
- char *admin_email;
- } SilcServerConfigSectionAdminInfo;
-
- /* Holds all the ports the server is listenning on */
- typedef struct SilcServerConfigSectionListenPortStruct {
- char *local_ip;
- char *listener_ip;
- uint16 port;
- struct SilcServerConfigSectionListenPortStruct *next;
- struct SilcServerConfigSectionListenPortStruct *prev;
- } SilcServerConfigSectionListenPort;
-
- /* Holds server's execution identity, or the user and group which
- to change from root when server starts */
- typedef struct {
- char *user;
- char *group;
- } SilcServerConfigSectionIdentity;
-
- /* Holds all the configured log files. */
+typedef struct SilcServerConfigSectionLoggingStruct {
- char *logtype;
- char *filename;
++ char *file;
+ uint32 maxsize;
- struct SilcServerConfigSectionLoggingStruct *next;
- struct SilcServerConfigSectionLoggingStruct *prev;
-
- /* Allowed <Logging> section types */
- #define SILC_CONFIG_SERVER_LF_INFO "infologfile"
- #define SILC_CONFIG_SERVER_LF_WARNING "warninglogfile"
- #define SILC_CONFIG_SERVER_LF_ERROR "errorlogfile"
- #define SILC_CONFIG_SERVER_LF_FATAL "fatallogfile"
- #define SILC_CONFIG_SERVER_LO_QUICK "quicklogs"
- #define SILC_CONFIG_SERVER_LO_FDELAY "flushdelay"
+} SilcServerConfigSectionLogging;
/* Holds all configured connection classes */
- typedef struct SilcServerConfigSectionConnectionClassStruct {
-typedef struct SilcConfigServerSectionConnectionClassStruct {
- unsigned int class;
- unsigned int ping_freq;
- unsigned int connect_freq;
- unsigned int max_links;
- struct SilcConfigServerSectionConnectionClassStruct *next;
- struct SilcConfigServerSectionConnectionClassStruct *prev;
-} SilcConfigServerSectionConnectionClass;
-
-#define SILC_CONFIG_SERVER_AUTH_METH_PASSWD "passwd"
-#define SILC_CONFIG_SERVER_AUTH_METH_PUBKEY "pubkey"
++/* typedef struct SilcServerConfigSectionClassStruct {
+ uint32 class;
+ uint32 ping_freq;
+ uint32 connect_freq;
+ uint32 max_links;
- struct SilcServerConfigSectionConnectionClassStruct *next;
- struct SilcServerConfigSectionConnectionClassStruct *prev;
- } SilcServerConfigSectionConnectionClass;
-
- #define SILC_CONFIG_SERVER_AUTH_METH_PASSWD "passwd"
- #define SILC_CONFIG_SERVER_AUTH_METH_PUBKEY "pubkey"
++ struct SilcServerConfigSectionClassStruct *next;
++} SilcServerConfigSectionClass; */
/* Holds all client authentication data from config file */
- typedef struct SilcServerConfigSectionClientConnectionStruct {
-typedef struct SilcConfigServerSectionClientConnectionStruct {
++typedef struct SilcServerConfigSectionClientStruct {
char *host;
- int auth_meth;
- char *auth_data;
- unsigned short port;
- unsigned int class;
- struct SilcConfigServerSectionClientConnectionStruct *next;
- struct SilcConfigServerSectionClientConnectionStruct *prev;
-} SilcConfigServerSectionClientConnection;
-
-/* Hols all server's administrators authentication data from config file */
-typedef struct SilcConfigServerSectionAdminConnectionStruct {
+ SilcAuthMethod auth_meth;
+ void *auth_data;
+ uint32 auth_data_len;
+ uint16 port;
+ uint32 class;
- struct SilcServerConfigSectionClientConnectionStruct *next;
- struct SilcServerConfigSectionClientConnectionStruct *prev;
- } SilcServerConfigSectionClientConnection;
++ struct SilcServerConfigSectionClientStruct *next;
++} SilcServerConfigSectionClient;
++
++/* Holds all server's administrators authentication data from config file */
++typedef struct SilcServerConfigSectionAdminStruct {
+ char *host;
- int auth_meth;
- char *auth_data;
- char *nickname;
- unsigned int class;
- struct SilcConfigServerSectionAdminConnectionStruct *next;
- struct SilcConfigServerSectionAdminConnectionStruct *prev;
-} SilcConfigServerSectionAdminConnection;
-
-/* Holds all configured server/router connections from config file */
-typedef struct SilcConfigServerSectionServerConnectionStruct {
- char *host;
- int auth_meth;
- char *auth_data;
- unsigned short port;
- char *version;
- unsigned int class;
- struct SilcConfigServerSectionServerConnectionStruct *next;
- struct SilcConfigServerSectionServerConnectionStruct *prev;
-} SilcConfigServerSectionServerConnection;
++ char *user;
++ char *nick;
++ SilcAuthMethod auth_meth;
++ void *auth_data;
++ uint32 auth_data_len;
++ struct SilcServerConfigSectionAdminStruct *next;
++} SilcServerConfigSectionAdmin;
+
+ /* Holds all configured denied connections from config file */
-typedef struct {
++typedef struct SilcServerConfigSectionDenyStruct {
+ char *host;
- char *time;
- char *comment;
- unsigned short port;
-} SilcConfigServerSectionDenyConnection;
++ uint16 port;
++ char *reason;
++ struct SilcServerConfigSectionDenyStruct *next;
++} SilcServerConfigSectionDeny;
- /* Hols all server's administrators authentication data from config file */
- typedef struct SilcServerConfigSectionAdminConnectionStruct {
-/* Holds all client redirections from config file */
-typedef struct {
++/* Holds all configured server connections from config file */
++typedef struct SilcServerConfigSectionServerStruct {
char *host;
- char *username;
- char *nickname;
- unsigned short port;
-} SilcConfigServerSectionRedirectClient;
-
-/*
- SILC Server Config object.
-
- This object holds all the data parsed from the SILC server configuration
- file. This is mainly used at the initialization of the server.
+ SilcAuthMethod auth_meth;
+ void *auth_data;
+ uint32 auth_data_len;
- struct SilcServerConfigSectionAdminConnectionStruct *next;
- struct SilcServerConfigSectionAdminConnectionStruct *prev;
- } SilcServerConfigSectionAdminConnection;
++ uint16 port;
++ char *version;
++ uint32 class;
++ bool backup_router;
++ struct SilcServerConfigSectionServerStruct *next;
++} SilcServerConfigSectionServer;
- /* Holds all configured server/router connections from config file */
- typedef struct SilcServerConfigSectionServerConnectionStruct {
-*/
-typedef struct {
- /* Pointer back to the server */
- void *server;
-
- /* Filename of the configuration file */
- char *filename;
-
- /* Configuration sections */
- SilcConfigServerSectionAlg *cipher;
- SilcConfigServerSectionAlg *pkcs;
- SilcConfigServerSectionAlg *hash_func;
- SilcConfigServerSectionServerInfo *server_info;
- SilcConfigServerSectionAdminInfo *admin_info;
- SilcConfigServerSectionListenPort *listen_port;
- SilcConfigServerSectionLogging *logging;
- SilcConfigServerSectionConnectionClass *conn_class;
- SilcConfigServerSectionClientConnection *clients;
- SilcConfigServerSectionServerConnection *servers;
- SilcConfigServerSectionServerConnection *routers;
- SilcConfigServerSectionAdminConnection *admins;
- SilcConfigServerSectionDenyConnection *denied;
- SilcConfigServerSectionRedirectClient *redirect;
-} SilcConfigServerObject;
-
-typedef SilcConfigServerObject *SilcConfigServer;
-
-/* Configuration section type enumerations. */
-typedef enum {
- SILC_CONFIG_SERVER_SECTION_TYPE_NONE = 0,
- SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER,
- SILC_CONFIG_SERVER_SECTION_TYPE_PKCS,
- SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION,
- SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO,
- SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO,
- SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT,
- SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING,
- SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS,
- SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION,
- SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION,
- SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION,
- SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION,
- SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION,
- SILC_CONFIG_SERVER_SECTION_TYPE_REDIRECT_CLIENT,
-} SilcConfigServerSectionType;
-
-/* SILC Configuration Section structure. */
++/* Holds all configured router connections from config file */
++typedef struct SilcServerConfigSectionRouterStruct {
+ char *host;
+ SilcAuthMethod auth_meth;
+ void *auth_data;
+ uint32 auth_data_len;
+ uint16 port;
+ char *version;
+ uint32 class;
+ bool initiator;
+ bool backup_router;
+ char *backup_replace_ip;
+ uint16 backup_replace_port;
+ bool backup_local;
- struct SilcServerConfigSectionServerConnectionStruct *next;
- struct SilcServerConfigSectionServerConnectionStruct *prev;
- } SilcServerConfigSectionServerConnection;
-
- /* Holds all configured denied connections from config file */
- typedef struct SilcServerConfigSectionDenyConnectionStruct {
- char *host;
- char *comment;
- uint16 port;
- struct SilcServerConfigSectionDenyConnectionStruct *next;
- struct SilcServerConfigSectionDenyConnectionStruct *prev;
- } SilcServerConfigSectionDenyConnection;
-
- /* Holds motd file */
- typedef struct {
- char *motd_file;
- } SilcServerConfigSectionMotd;
-
- /* holds pid file */
- typedef struct {
- char *pid_file;
- } SilcServerConfigSectionPid;
-
- /*
- SILC Server Config object.
-
- This object holds all the data parsed from the SILC server configuration
- file. This is mainly used at the initialization of the server.
++ struct SilcServerConfigSectionRouterStruct *next;
++} SilcServerConfigSectionRouter;
+
- */
++/* define the SilcServerConfig object */
typedef struct {
- /* Pointer back to the server */
- void *server;
- const char *section;
- SilcConfigServerSectionType type;
- unsigned int maxfields;
-} SilcConfigServerSection;
--
- /* Filename of the configuration file */
- char *filename;
-/* LIst of all possible config sections in SILC server. */
-extern SilcConfigServerSection silc_config_server_sections[];
--
- /* Configuration sections */
- SilcServerConfigSectionAlg *cipher;
- SilcServerConfigSectionAlg *pkcs;
- SilcServerConfigSectionAlg *hash_func;
- SilcServerConfigSectionAlg *hmac;
- SilcServerConfigSectionServerKeys *server_keys;
-/* Structure used in parsing the configuration lines. The line is read
- from a file to this structure before parsing it further. */
-typedef struct SilcConfigServerParseStruct {
- SilcBuffer line;
- unsigned int linenum;
- SilcConfigServerSection *section;
- struct SilcConfigServerParseStruct *next;
- struct SilcConfigServerParseStruct *prev;
-} *SilcConfigServerParse;
-
-/* Macros */
-
-/* Allocates list entries for configuration sections. Used by all
- config sections as this is common. */
-#define SILC_SERVER_CONFIG_LIST_ALLOC(x) \
-do { \
- if (!(x)) { \
- (x) = silc_calloc(1, sizeof(*(x))); \
- (x)->next = NULL; \
- (x)->prev = NULL; \
- } else { \
- if (!(x)->next) { \
- (x)->next = silc_calloc(1, sizeof(*(x)->next)); \
- (x)->next->next = NULL; \
- (x)->next->prev = (x); \
- (x) = (x)->next; \
- } \
- } \
-} while(0)
++ void *tmp;
++ char *module_path;
++
++ SilcServerConfigSectionCipher *cipher;
++ SilcServerConfigSectionHash *hash;
++ SilcServerConfigSectionHmac *hmac;
++ SilcServerConfigSectionPkcs *pkcs;
++ SilcServerConfigSectionLogging *logging_info;
++ SilcServerConfigSectionLogging *logging_warnings;
++ SilcServerConfigSectionLogging *logging_errors;
++ SilcServerConfigSectionLogging *logging_fatals;
+ SilcServerConfigSectionServerInfo *server_info;
- SilcServerConfigSectionAdminInfo *admin_info;
- SilcServerConfigSectionListenPort *listen_port;
- SilcServerConfigSectionIdentity *identity;
- SilcServerConfigSectionLogging *logging;
- SilcServerConfigSectionConnectionClass *conn_class;
- SilcServerConfigSectionClientConnection *clients;
- SilcServerConfigSectionServerConnection *servers;
- SilcServerConfigSectionServerConnection *routers;
- SilcServerConfigSectionAdminConnection *admins;
- SilcServerConfigSectionDenyConnection *denied;
- SilcServerConfigSectionMotd *motd;
- SilcServerConfigSectionPid *pidfile;
- } SilcServerConfigObject;
-
- typedef SilcServerConfigObject *SilcServerConfig;
++/*SilcServerConfigSectionClass *conn_class; */
++ SilcServerConfigSectionClient *clients;
++ SilcServerConfigSectionAdmin *admins;
++ SilcServerConfigSectionDeny *denied;
++ SilcServerConfigSectionServer *servers;
++ SilcServerConfigSectionRouter *routers;
++} *SilcServerConfig;
- /* Configuration section type enumerations. */
- typedef enum {
- SILC_CONFIG_SERVER_SECTION_TYPE_NONE = 0,
- SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER,
- SILC_CONFIG_SERVER_SECTION_TYPE_PKCS,
- SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION,
- SILC_CONFIG_SERVER_SECTION_TYPE_HMAC,
- SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_KEYS,
- SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO,
- SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO,
- SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT,
- SILC_CONFIG_SERVER_SECTION_TYPE_IDENTITY,
- SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING,
- SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS,
- SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION,
- SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION,
- SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION,
- SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION,
- SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION,
- SILC_CONFIG_SERVER_SECTION_TYPE_MOTD,
- SILC_CONFIG_SERVER_SECTION_TYPE_PID,
- } SilcServerConfigSectionType;
+ /* Prototypes */
-SilcConfigServer silc_config_server_alloc(char *filename);
-void silc_config_server_free(SilcConfigServer config);
-int silc_config_server_parse(SilcConfigServer config, SilcBuffer buffer,
- SilcConfigServerParse *return_config);
-int silc_config_server_parse_lines(SilcConfigServer config,
- SilcConfigServerParse parse_config);
-int silc_config_server_check_sections(unsigned int checkmask);
-void silc_config_server_setlogfiles(SilcConfigServer config);
-void silc_config_server_register_ciphers(SilcConfigServer config);
-void silc_config_server_register_pkcs(SilcConfigServer config);
-void silc_config_server_register_hashfuncs(SilcConfigServer config);
-SilcConfigServerSectionClientConnection *
-silc_config_server_find_client_conn(SilcConfigServer config,
- char *host, int port);
-SilcConfigServerSectionServerConnection *
-silc_config_server_find_server_conn(SilcConfigServer config,
+
- /* SILC Configuration Section structure. */
- typedef struct {
- const char *section;
- SilcServerConfigSectionType type;
- int maxfields;
- } SilcServerConfigSection;
++/* basic config operations */
++SilcServerConfig silc_server_config_alloc(char *filename);
++void silc_server_config_destroy(SilcServerConfig config);
+
- /* LIst of all possible config sections in SILC server. */
- extern SilcServerConfigSection silc_server_config_sections[];
++/* algorithm registering and reset functions */
++bool silc_server_config_register_ciphers(SilcServer server);
++bool silc_server_config_register_hashfuncs(SilcServer server);
++bool silc_server_config_register_hmacs(SilcServer server);
++bool silc_server_config_register_pkcs(SilcServer server);
++void silc_server_config_setlogfiles(SilcServerConfig config, SilcSchedule sked);
+
- /* Structure used in parsing the configuration lines. The line is read
- from a file to this structure before parsing it further. */
- typedef struct SilcServerConfigParseStruct {
- SilcBuffer line;
- int linenum;
- SilcServerConfigSection *section;
- struct SilcServerConfigParseStruct *next;
- struct SilcServerConfigParseStruct *prev;
- } *SilcServerConfigParse;
++/* run-time config access functions */
++SilcServerConfigSectionClient *
++silc_server_config_find_client(SilcServerConfig config, char *host, int port);
+
- /* Macros */
++SilcServerConfigSectionAdmin *
++silc_server_config_find_admin(SilcServerConfig config,
++ char *host, char *user, char *nick);
+
- /* Allocates list entries for configuration sections. Used by all
- config sections as this is common. */
- #define SILC_SERVER_CONFIG_LIST_ALLOC(x) \
- do { \
- if (!(x)) { \
- (x) = silc_calloc(1, sizeof(*(x))); \
- (x)->next = NULL; \
- (x)->prev = NULL; \
- } else { \
- if (!(x)->next) { \
- (x)->next = silc_calloc(1, sizeof(*(x)->next)); \
- (x)->next->next = NULL; \
- (x)->next->prev = (x); \
- (x) = (x)->next; \
- } \
- } \
- } while(0)
++SilcServerConfigSectionDeny *
++silc_server_config_find_denied(SilcServerConfig config,
++ char *host, uint16 port);
+
- /* Prototypes */
- SilcServerConfig silc_server_config_alloc(char *filename);
- void silc_server_config_free(SilcServerConfig config);
- int silc_server_config_parse(SilcServerConfig config, SilcBuffer buffer,
- SilcServerConfigParse *return_config);
- int silc_server_config_parse_lines(SilcServerConfig config,
- SilcServerConfigParse parse_config);
- int silc_server_config_check_sections(uint32 checkmask);
- void silc_server_config_setlogfiles(SilcServerConfig config, SilcSchedule sked);
- bool silc_server_config_register_ciphers(SilcServerConfig config);
- bool silc_server_config_register_pkcs(SilcServerConfig config);
- bool silc_server_config_register_hashfuncs(SilcServerConfig config);
- bool silc_server_config_register_hmacs(SilcServerConfig config);
- SilcServerConfigSectionClientConnection *
- silc_server_config_find_client_conn(SilcServerConfig config,
- char *host, int port);
- SilcServerConfigSectionServerConnection *
- silc_server_config_find_server_conn(SilcServerConfig config,
++/* Prototypes - OLD */
++SilcServerConfigSectionServer *
++silc_server_config_find_server_conn(SilcServerConfig config,
char *host, int port);
- SilcServerConfigSectionServerConnection *
- silc_server_config_find_router_conn(SilcServerConfig config,
-SilcConfigServerSectionServerConnection *
-silc_config_server_find_router_conn(SilcConfigServer config,
++SilcServerConfigSectionRouter *
++silc_server_config_find_router_conn(SilcServerConfig config,
char *host, int port);
-void silc_config_server_print();
+bool silc_server_config_is_primary_route(SilcServerConfig config);
- SilcServerConfigSectionServerConnection *
++SilcServerConfigSectionRouter *
+silc_server_config_get_primary_router(SilcServerConfig config);
- SilcServerConfigSectionAdminConnection *
- silc_server_config_find_admin(SilcServerConfig config,
- char *host, char *username, char *nickname);
- SilcServerConfigSectionDenyConnection *
- silc_server_config_denied_conn(SilcServerConfig config, char *host,
- int port);
--#endif
++#endif /* !SERVERCONFIG_H */
exit(0);
}
- static void silc_checkpid(SilcServer silcd)
+/* Dies if a *valid* pid file exists already */
+
- if (silcd->config->pidfile && silcd->config->pidfile->pid_file) {
++static void silc_server_checkpid(SilcServer silcd)
+{
- buf = silc_file_readfile(silcd->config->pidfile->pid_file, &buf_len);
++ if (silcd->config->server_info->pid_file) {
+ int oldpid;
+ char *buf;
+ uint32 buf_len;
+
+ SILC_LOG_DEBUG(("Checking for another silcd running"));
- silcd->config->pidfile->pid_file);
++ buf = silc_file_readfile(silcd->config->server_info->pid_file, &buf_len);
+ if (!buf)
+ return;
+ oldpid = atoi(buf);
+ silc_free(buf);
+ if (oldpid <= 0)
+ return;
+ kill(oldpid, SIGCHLD); /* this signal does nothing, check if alive */
+ if (errno != ESRCH) {
+ fprintf(stderr, "\nI detected another daemon running with the same pid file.\n");
+ fprintf(stderr, "Please change the config file, or erase the %s\n",
++ silcd->config->server_info->pid_file);
+ exit(1);
+ }
+ }
+}
+
+static void got_hup(int z)
+{
+ /* First, reset all log files (they might have been deleted) */
+ silc_log_reset_all();
+ silc_log_flush_all();
+}
+
+static void stop_server(int z)
+{
+ /* Stop scheduler, the program will stop eventually after noticing
+ that the scheduler is down. */
+ silc_schedule_stop(silcd->schedule);
+}
+
int main(int argc, char **argv)
{
- int ret;
- int opt, option_index;
+ int ret, opt, option_index;
char *config_file = NULL;
- SilcServer silcd;
+ bool foreground = FALSE;
+ struct sigaction sa;
/* Parse command line arguments */
if (argc > 1) {
if (silcd->config == NULL)
goto fail;
- silc_checkpid(silcd);
+ /* Check for another silcd running */
++ silc_server_checkpid(silcd);
+
/* Initialize the server */
ret = silc_server_init(silcd);
if (ret == FALSE)
goto fail;
-
+
+ /* Ignore SIGPIPE */
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGPIPE, &sa, NULL);
+ sa.sa_handler = got_hup;
+ sigaction(SIGHUP, &sa, NULL);
+ sa.sa_handler = stop_server;
+ sigaction(SIGTERM, &sa, NULL);
+ sa.sa_handler = stop_server;
+ sigaction(SIGINT, &sa, NULL);
+
+ /* Before running the server, fork to background. */
+ if (!foreground)
+ silc_server_daemonise(silcd);
+
+ /* If set, write pid to file */
- if (silcd->config->pidfile && silcd->config->pidfile->pid_file) {
- char buf[10];
- unlink(silcd->config->pidfile->pid_file);
++ if (silcd->config->server_info->pid_file) {
++ char buf[10], *pidfile = silcd->config->server_info->pid_file;
++ unlink(pidfile);
+ snprintf(buf, sizeof(buf) - 1, "%d\n", getpid());
- silc_file_writefile(silcd->config->pidfile->pid_file, buf, strlen(buf));
++ silc_file_writefile(pidfile, buf, strlen(buf));
+ }
+
+ /* Drop root. */
+ silc_server_drop(silcd);
+
/* Run the server. When this returns the server has been stopped
and we will exit. */
silc_server_run(silcd);
--- /dev/null
- # configuration possibilities and may not actually give any sensible
+#
+# Example configuration file. Note that this attempts to present various
- # Configured ciphers.
++# configuration possibilities and may not actually give any sensible
+# configuration. For real life example see the examples/ directory.
+#
+
+#
- # Format: <name>:<module path>:<key length>:<block length>
- #
- # If the cipher is builtin the <module path> maybe omitted.
- #
- [Cipher]
- aes-256-cbc:@MODULESDIR@/aes.sim.so:32:16
- aes-192-cbc:@MODULESDIR@/aes.sim.so:24:16
- aes-128-cbc:@MODULESDIR@/aes.sim.so:16:16
- twofish-256-cbc:@MODULESDIR@/twofish.sim.so:32:16
- twofish-192-cbc:@MODULESDIR@/twofish.sim.so:24:16
- twofish-128-cbc:@MODULESDIR@/twofish.sim.so:16:16
- mars-256-cbc:@MODULESDIR@/mars.sim.so:32:16
- mars-192-cbc:@MODULESDIR@/mars.sim.so:24:16
- mars-128-cbc:@MODULESDIR@/mars.sim.so:16:16
- none:@MODULESDIR@/none.sim.so:0:0
++# General configuration options
+#
- # Configured hash functions.
- #
- # Format: <name>:<module path>:<block length>:<digest length>
- #
- # If the hash function is builtin the <module path> maybe omitted.
++General {
++ # This is the default path where to search modules
++ # You can comment it out to use builtin modules globally.
++ ModulePath = "@MODULESDIR@";
++};
+
+#
- [Hash]
- sha1::64:20
- md5::64:16
++# Configured ciphers
++#
++# The "Module" option can be either absolute or relative to the "ModulePath"
++# option.
++# If commented out forces using of built-in modules.
++#
++cipher {
++ name = "aes-256-cbc";
++ module = "aes.sim.so";
++ key_length = 32;
++ block_length = 16;
++};
++cipher {
++ name = "aes-192-cbc";
++ module = "aes.sim.so";
++ key_length = 24;
++ block_length = 16;
++};
++cipher {
++ name = "aes-128-cbc";
++ module = "aes.sim.so";
++ key_length = 16;
++ block_length = 16;
++};
++cipher {
++ name = "twofish-256-cbc";
++ module = "twofish.sim.so";
++ key_length = 32;
++ block_length = 16;
++};
++cipher {
++ name = "twofish-192-cbc";
++ module = "twofish.sim.so";
++ key_length = 24;
++ block_length = 16;
++};
++cipher {
++ name = "twofish-128-cbc";
++ module = "twofish.sim.so";
++ key_length = 16;
++ block_length = 16;
++};
++cipher {
++ name = "mars-256-cbc";
++ module = "mars.sim.so";
++ key_length = 32;
++ block_length = 16;
++};
++cipher {
++ name = "mars-192-cbc";
++ module = "mars.sim.so";
++ key_length = 24;
++ block_length = 16;
++};
++cipher {
++ name = "mars-128-cbc";
++ module = "mars.sim.so";
++ key_length = 16;
++ block_length = 16;
++};
++cipher {
++ name = "none";
++ module = "none.sim.so";
++};
++
+#
- # configured to the [hash] section.
- #
- # Format: <name>:<hash name>:<mac length>
- #
- [hmac]
- hmac-sha1-96:sha1:12
- hmac-md5-96:md5:12
- hmac-sha1:sha1:20
- hmac-md5:md5:16
++# Configured hash functions
++#
++hash {
++ name = "sha1";
++ block_length = 64;
++ digest_length = 20;
++};
++hash {
++ name = "md5";
++ block_length = 64;
++ digest_length = 16;
++};
+
+#
+# Configured HMAC functions. The hash function used in the HMAC must
- # Configured PKCS.
++# be configured in the hash section.
++#
++hmac {
++ name = "hmac-sha1-96";
++ hash = "sha1";
++ mac_length = 12;
++};
++hmac {
++ name = "hmac-md5-96";
++ hash = "md5";
++ mac_length = 12;
++};
++hmac {
++ name = "hmac-sha1";
++ hash = "sha1";
++ mac_length = 20;
++};
++hmac {
++ name = "hmac-md5";
++ hash = "md5";
++ mac_length = 16;
++};
+
+#
- # Format: <name>
- #
- [PKCS]
- rsa
++# Configured PKCS
+#
- # Run SILC server as specific user and group. The server must be initially
- # run as root.
- #
- # Format: <user>:<group>
++PKCS { name = "rsa"; };
+
+#
- [Identity]
- nobody:nobody
++# Server information
+#
- #
- # Server's administrative information.
- #
- # Format: <location>:<server type>:<admin's name>:<admin's email address>
- #
- [AdminInfo]
- Kuopio, Finland:Test Server:Pekka Riikonen:priikone@poseidon.pspt.fi
++ServerInfo {
++ #
++ # Server FQDN and IP address
++ #
++ hostname = "lassi.kuo.fi.ssh.com";
++ ip = "10.2.1.6";
++ port = 706;
+
- #
- # Server information.
- #
- # Format: +<server FQDN>:<server IP>:<geographic location>:<port>
- #
- [ServerInfo]
- lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:706
++ #
++ # ServerType field specifies the purpose of this server
++ # This is only a descriptive field.
++ #
++ ServerType = "Test Server";
+
- #
- # Server keys
- #
- # Format: +<public key>:<private key>
- #
- [ServerKeys]
- @ETCDIR@/silcd.pub:@ETCDIR@/silcd.prv
++ #
++ # Geographic location
++ #
++ Location = "Kuopio, Finland";
+
- #
- # Listenning ports.
- #
- # Format: <local IP>:<Listener IP>:<port>
- #
- [ListenPort]
- 10.2.1.6:10.2.1.6:706
++ #
++ # Full admin name
++ #
++ Admin = "Pekka Riikonen";
+
- # This section is used to set various logging files, their paths
- # and maximum sizes. There are only four defined channels allowed for
- # defining (see list below).
++ #
++ # Admin's email address
++ #
++ EMail = "priikone@poseidon.pspt.fi";
++
++ #
++ # Run SILC server as specific user and group. The server must be initially
++ # run as root.
++ #
++ User = "nobody";
++ Group = "nobody";
++
++ #
++ # Public and private keys
++ #
++ PublicKey = "@ETCDIR@/silcd.pub";
++ PrivateKey = "@ETCDIR@/silcd.prv";
++
++ #
++ # Motd file
++ #
++ # Specifies the text file displayed on client connection
++ #
++ #MotdFile = "@ETCDIR@/motd.txt";
++
++ #
++ # Pid file
++ #
++ PidFile = "@PIDFILE@";
++};
+
+#
+# Log files.
+#
- # are printed on the less important ones, thus setting the logging file
- # for "infologfile" will ensure logging for all channels, while setting
- # logging file for "errorlogfile" will ensure logging for channels
- # "error" and "fatal" only.
- # If a message can't find a valid output file it will be discarded, thus,
- # if you unset all files you will completely disable server logging (and
- # this is NOT recommended).
- # If maximum size is given, the logfile will be rotated to a logfile with
- # the ".old" extension added. Older logfiles are flushed.
- # There are also two options, quicklogs and flushdelay. Their values
- # must be enclosed in colons (:), see the format below.
- #
- # Format: quicklogs:<yes/no>:
- # flushdelay:<seconds>:
- # infologfile:<path>:<max byte size>
- # warninglogile:<path>:<max byte size>
- # errorlogile:<path>:<max byte size>
- # fatallogile:<path>:<max byte size>
- #
- [Logging]
- quicklogs:no:
- flushdelay:300:
- infologfile:@LOGSDIR@/silcd.log:50000
- warninglogfile:@LOGSDIR@/silcd_warnings.log:50000
- #errorlogfile:@LOGSDIR@/silcd_errors.log:50000
- #fatallogfile:@LOGSDIR@/silcd_fatals.log:
-
- #
- # Connection classes.
- #
- # This section is used to define connection classes. These can be
- # used to optimize the server and the connections.#
++# This section is used to set various logging files, their paths, maximum
++# sizes and logging options.
++# There are only four defined channels allowed for defining (see below).
+# The log channels have an importance value, and most important channels
- # Format: <class number>:<ping freq>:<connect freq>:<max links>
++# are redirected on the less important ones, thus setting a valid logging
++# file for "infologfile" will ensure logging for all channels, while setting
++# logging file for "errorlogfile" will ensure logging for channels "error"
++# and "fatal"
++#
++Logging {
++ #
++ # If QuickLogs is true, then the logging files will be updated
++ # real-time. This causes a bit more CPU and HDD activity, but
++ # reduces memory usage. (if unsure say true).
++ #
++ QuickLogs = false;
++
++ #
++ # (Only if QuickLogs is false)
++ # FlushDelay tells log files update delay in case you have chosen
++ # buffering output.
++ #
++ FlushDelay = 180;
++
++ Info {
++ File = "@LOGSDIR@/silcd.log";
++ Size = "50k";
++ };
++ Warnings {
++ File = "@LOGSDIR@/silcd_warnings.log";
++ Size = "50k";
++ };
++ Errors {
++ File = "@LOGSDIR@/silcd_errors.log";
++ Size = "50k";
++ };
++ Fatals {
++ File = "@LOGSDIR@/silcd_fatals.log";
++ Size = "50k";
++ };
++};
++
+#
- [ConnectionClass]
- 1:100:100:100
- 2:200:300:400
++# Connection classes (UNSUPPORTED)
+#
- # Format: <remote host>:<auth method>:<auth data>:<port>:<class>
++# This section is used to define connection classes. These can be
++# used to optimize the server and the connections.
++#
++#Class {
++# Name = "norm";
++# Ping = 100;
++# Connect = 100;
++# Links = 100;
++#};
+
+#
+# Configured client connections.
+#
- # The <auth data> is either passphrase or file path to the public key
- # file.
++# All fields except Class are optional. Omitted fields are assumed
++# to be generic (e.g. if the "Host" field is omitted all hosts will match
++# this client class).
++#
++#Client {
++# Host = "127.0.0.1";
++# Port = 706;
++# Class = "local";
++#};
++Client {
++ Port = 706;
++ Class = "norm";
++};
++
+#
- [ClientConnection]
- :::706:1
++# Configured server administrator connections
+#
- # Configured server administrator connections
++# The fields "Host", "User", and "Nick", are optional but you are encouraged
++# in using them to better identify your admins.
++# "AuthMethod" and "AuthData" fields are mandatory. The "AuthMethod" field
++# can be either the special string "passwd" or "pubkey" to identify the type
++# of data specified by "AuthData".
++#
++Admin {
++ Host = "10.2.1.199";
++ User = "priikone";
++ Nick = "pekka";
++ AuthMethod = "passwd";
++ AuthData = "verysecret";
++};
+
+#
- # Format: <host>:<username>:<nickname>:<auth method>:<auth data>
++# Denied connections
+#
- # The <auth data> is either passphrase or file path to the public key
- # file.
++# These connections are denied to connect to our server.
+#
- [AdminConnection]
- 10.2.1.199:priikone:pekka:passwd:veryscret
++# The "Reason" field is mandatory, while the "Host" and "Port" fields can be
++# omitted to match everything.
+#
- # If server connections are configured it means that our server is
- # router server. Normal server must not configure server connections.
- # Thus, if your server is not router do not configure this section. If
++#Deny {
++# Host = "10.2.1.99";
++# Port = 706;
++# Reason = "Go away spammer";
++#};
++#Deny {
++# Host = "10.3.*";
++# Reason = "You are not welcome.";
++#};
+
+#
+# Configured server connections.
+#
- # Format: <remote host>:<auth method>:<auth data>:<port>:
- # <version ID>:<class>:<backup connection>
- #
- # The <auth data> is either passphrase or file path to the public key
- # file. If the connection is backup connection then set the <backup
- # connection> to value 1. For normal connections set it 0. If it is
- # set to value 1 then this server will be backup router.
- #
- [ServerConnection]
- 10.2.1.7:passwd:veryscret:706:1:1:0
- 10.2.1.17:passwd:veryscret13:706:1:1:1 # backup connection, that host
- # will use this server as backup
- # router.
++# If server connections are configured it means that this server is
++# router server. Normal servers must not configure server connections.
++# Thus, if this server is not router do not configure this section. If
+# your server is router, this must be configured.
+#
- # Configured router connections.
++# The "AuthData" option is either passphrase or file path to the public key
++# file. If the connection is backup connection then set the "Backup" option
++# to true. For normal connections set it false. If it is
++# set to true then this server will be backup router.
++#
++ServerConnection {
++ Host = "10.2.1.7";
++ AuthMethod = passwd;
++ AuthData = "verysecret";
++ Port = 706;
++ VersionID = 1;
++ Class = "norm";
++ Backup = false;
++};
+
+#
- # For normal server only one entry maybe configured to this section. It
- # must be the router this server will be connected to. For router server,
- # this sections includes all configured router connections. The first
++# Configured router connections
+#
- # Format: <remote host>:<auth method>:<auth data>:<port>:<version ID>:
- # <class>:<initiator>:<backup replace IP>:<backup replace port>:
- # <local backup>
++# For normal servers only one entry maybe configured to this section. It
++# must be the router this server will be connected to. For router servers,
++# this section includes all configured router connections. The first
+# configured connection is the primary route.
+#
- # The <auth data> is either passphrase or file path to the public key
- # file. If you are the initiator of the connection then set the <initiator>
- # to value 1. If you are the responder of the connection (waiting for
- # incoming connection) then set it to 0.
- #
- # If the connection is backup router connection then set the <backup
- # replace IP> to the IP address of the router that the backup router will
++# The "AuthData" option is either passphrase or file path to the public key
++# file. If you are the initiator of the connection then set the "Initiator"
++# option to true. If you are the responder of the connection (waiting for
++# incoming connection) then set it to false.
+#
- # <backup replace port>. For normal connection leave both empty. If this
- # backup router is in our cell then set the <local backup> to value 1.
- # If the backup router is in other cell then set it to value 0.
- #
- [RouterConnection]
- #10.2.1.100:passwd:veryverysecret:706:1:1:1
- #10.2.100.131:pubkey:/path/to/the/publickey:706:1:1:1
- #10.2.100.100:pubkey:/path/to/the/publickey:706:1:1:0:10.2.1.6:706:1
-
- #
- # Denied connections.
- #
- # These connections are denied to connect our server.
- #
- # Format: <remote host>:<port>:<comment>
- #
- [DenyConnection]
- #10.2.1.99:0:Your connection has been denied
-
- #
- # Message Of The Day
- #
- # specify the text file containing the motd:
- #
- #[motd]
- #@ETCDIR@/motd.txt
-
- #
- # Pid File
- #
- # specify the pidfile where it will be written:
- #
- [pid]
- @PIDFILE@
++# If the connection is backup router connection then set the "BackupHost"
++# option to the IP address of the router that the backup router will
+# replace if it becomes unavailable. Set also the router's port to the
++# "BackupPort" option. For normal connection leave both commented. If this
++# backup router is in our cell then set the "LocalBackup" option to true.
++# If the backup router is in other cell then set it to false.
++#
++RouterConnection {
++ Host = "10.2.1.100";
++ AuthMethod = passwd;
++ AuthData = "verysecret";
++ Port = 706;
++ VersionID = 1;
++ Class = "norm";
++ Initiator = true;
++ #BackupHost = "10.2.1.6";
++ #BackupPort = 706;
++ #LocalBackup = true;
++};
--- /dev/null
- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+/*
+
+ silcconfig.c
+
- Copyright (C) 1997 - 2000 Pekka Riikonen
++ Author: Johnny Mnemonic <johnny@themnemonic.org>
+
-
++ Copyright (C) 1997 - 2002 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; either version 2 of the License, or
+ (at your option) any later version.
- /* Opens and reads a configuration file to a buffer. The read data is
- returned to the ret_buffer argument. */
++
+ 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 "silcincludes.h"
+
- void silc_config_open(char *filename, SilcBuffer *ret_buffer)
++/* limit debug logging verbosity */
++#if 0
++#define SILC_CONFIG_DEBUG(fmt) SILC_LOG_DEBUG(fmt)
++#else
++#define SILC_CONFIG_DEBUG(fmt)
++#endif
++
++/* this is the option struct and currently it is only used internally to
++ * the module and other structs. */
++typedef struct SilcConfigOptionStruct {
++ char *name; /* *lowercase* name of the option */
++ SilcConfigType type; /* important: the type of the returned value */
++ SilcConfigCallback cb; /* the value handler */
++ const SilcConfigTable *subtable; /* used if type is SILC_CONFIG_ARG_BLOCK */
++ void *context; /* context passed to the callback function */
++ struct SilcConfigOptionStruct *next;
++} SilcConfigOption;
++
++/* unique for each config file (and included ones) */
++struct SilcConfigFileObject {
++ char *filename; /* the original filename opened */
++ int level; /* parsing level, how many nested silc_config_main we have */
++ char *base; /* this is a fixed pointer to the base location */
++ char *p; /* the Parser poitner */
++ uint32 len; /* fixed length of the whole file */
++ uint32 line; /* current parsing line, strictly linked to p */
++ bool included; /* wether this file is main or included */
++};
++
++/* We need the entity to base our block-style parsing on */
++struct SilcConfigEntityObject {
++ SilcConfigOption *opts; /* known options list */
++ SilcConfigFile *file; /* parsing file object */
++};
++
++/* access error descriptions only with silc_config_strerror() */
++static char *errorstrs[] = {
++ "-OK", /* SILC_CONFIG_OK */
++ "-SILENT", /* SILC_CONFIG_ESILENT */
++ "Invalid syntax", /* SILC_CONFIG_EGENERIC */
++ "Internal error! Please report this bug", /* SILC_CONFIG_EINTERNAL */
++ "Can't open specified file", /* SILC_CONFIG_ECANTOPEN */
++ "Expected open-brace '{'", /* SILC_CONFIG_EOPENBRACE */
++ "Missing close-brace '}'", /* SILC_CONFIG_ECLOSEBRACE */
++ "Invalid data type", /* SILC_CONFIG_ETYPE */
++ "Unknown option", /* SILC_CONFIG_EBADOPTION */
++ "Invalid text", /* SILC_CONFIG_EINVALIDTEXT */
++ "Double option specification", /* SILC_CONFIG_EDOUBLE */
++ "Expected data but not found", /* SILC_CONFIG_EEXPECTED */
++ "Expected '='", /* SILC_CONFIG_EEXPECTEDEQUAL */
++ "Unexpected data", /* SILC_CONFIG_EUNEXPECTED */
++ "Missing needed fields", /* SILC_CONFIG_EMISSFIELDS */
++ "Missing ';'", /* SILC_CONFIG_EMISSCOLON */
++};
++
++/* return string describing SilcConfig's error code */
++char *silc_config_strerror(int errnum)
++{
++ if ((errnum < 0) || (errnum >= sizeof(errorstrs)/sizeof(*errorstrs)) ||
++ (errorstrs[errnum] == NULL)) {
++ char *defret = "-INVALIDERROR";
++ return defret;
++ }
++ return errorstrs[errnum];
++}
++
++/* Begin of internal SilcConfig's text util functions */
++
++/* Points the first non-space character */
++static void my_trim_spaces(SilcConfigFile *file)
++{
++ register char *r = file->p;
++ while (isspace(*r))
++ if (*r++ == '\n') file->line++;
++ file->p = r;
++}
++/* Skips the current line until newline (lf or cr) */
++static void my_skip_line(SilcConfigFile *file)
++{
++ register char *r = file->p;
++ while (*r && (*r != '\n') && (*r != '\r')) r++;
++ file->p = (*r ? r + 1 : r);
++ file->line++;
++}
++/* Obtains a text token from the current position until first separator.
++ * a separator is any non alphanumeric character nor "_" or "-" */
++static char *my_next_token(SilcConfigFile *file, char *to)
++{
++ register char *o;
++ my_trim_spaces(file);
++ o = file->p;
++ while (isalnum(*o) || (*o == '_') || (*o == '-'))
++ *to++ = *o++;
++ *to = '\0';
++ file->p = o;
++ return to;
++}
++/* Obtains a string from the current position. The only difference from
++ * next_token() is that quoted-strings are also accepted */
++static char *my_get_string(SilcConfigFile *file, char *to)
++{
++ char *o;
++ my_trim_spaces(file);
++ o = file->p;
++ if (*o == '"') {
++ char *quot = strchr(++o, '"');
++ int len = quot - o;
++ if (!quot) { /* XXX FIXME: gotta do something here */
++ printf("Bullshit, missing matching \"");
++ exit(1);
++ }
++ if (len <= 0)
++ *to = '\0';
++ else {
++ strncpy(to, o, len);
++ to[len] = '\0';
++ }
++ /* update stream pointer */
++ file->p = quot + 1;
++ return to;
++ }
++ /* we don't need quote parsing, fall-back to token extractor */
++ my_next_token(file, to);
++ return to;
++};
++/* Skips all comment lines and spaces lines until first useful character */
++static void my_skip_comments(SilcConfigFile *file)
++{
++ while (1) {
++ my_trim_spaces(file);
++ if (*file->p != '#') return;
++ my_skip_line(file);
++ }
++}
++
++/* End of internal text functions
++ * Next section contains SilcConfig internal config utils */
+
- buffer = silc_file_readfile(filename, &filelen);
- if (buffer == NULL)
- return;
++/* find an option in the list by name and returns its pointer */
++static SilcConfigOption *silc_config_find_option(SilcConfigEntity ent,
++ const char *name)
++{
++ SilcConfigOption *tmp;
++ for (tmp = ent->opts; tmp; tmp = tmp->next) {
++ if (!strcasecmp(tmp->name, name))
++ return tmp;
++ }
++ return NULL;
++}
++/* ... */
++static void *silc_config_marshall(SilcConfigType type, const char *val)
++{
++ void *pt;
++ int val_int;
++ bool val_bool;
++ char *val_tmp;
++ uint32 val_size;
++
++ switch (type) {
++ case SILC_CONFIG_ARG_TOGGLE:
++ if (!strcasecmp(val, "yes") || !strcasecmp(val, "true") ||
++ !strcasecmp(val, "on") || !strcasecmp(val, "1")) {
++ val_bool = TRUE;
++ }
++ else if (!strcasecmp(val, "no") || !strcasecmp(val, "false") ||
++ !strcasecmp(val, "off") || !strcasecmp(val, "0")) {
++ val_bool = FALSE;
++ }
++ else
++ return NULL;
++ pt = silc_calloc(1, sizeof(val_bool));
++ *(bool *)pt = (bool) val_bool;
++ return pt;
++ case SILC_CONFIG_ARG_INT:
++ val_int = (int) strtol(val, &val_tmp, 0);
++ if (*val_tmp) /* error converting string */
++ return NULL;
++ pt = silc_calloc(1, sizeof(val_int));
++ *(int *)pt = val_int;
++ return pt;
++ case SILC_CONFIG_ARG_SIZE:
++ val_size = (uint32) strtol(val, &val_tmp, 0);
++ if (val == val_tmp)
++ return NULL; /* really wrong, there must be at least one digit */
++ /* Search for a designator */
++ switch (tolower(val_tmp[0])) {
++ case '\0': /* None */
++ break;
++ case 'k': /* Kilobytes */
++ val_size *= (uint32) 1024;
++ break;
++ case 'm': /* Megabytes */
++ val_size *= (uint32) (1024 * 1024);
++ break;
++ case 'g':
++ val_size *= (uint32) (1024 * 1024 * 1024);
++ break;
++ default:
++ return NULL;
++ }
++ /* the string must die here */
++ if (val_tmp[1])
++ return NULL;
++ pt = silc_calloc(1, sizeof(val_size));
++ *(uint32 *)pt = val_size;
++ return pt;
++ case SILC_CONFIG_ARG_STR: /* the only difference between STR and STRE is */
++ if (!val[0]) /* that STR cannot be empty, while STRE can. */
++ return NULL;
++ case SILC_CONFIG_ARG_STRE:
++ pt = (void *) strdup(val);
++ return pt;
++ /* following types are not supposed to have a return value */
++ case SILC_CONFIG_ARG_BLOCK:
++ case SILC_CONFIG_ARG_NONE:
++ return NULL;
++ default:
++ return NULL;
++ }
++
++ return NULL;
++}
++
++/* End of internal functions */
++
++
++/* Tries to open the config file and returns a valid SilcConfigFile object
++ * or NULL if failed */
++
++SilcConfigFile *silc_config_open(char *configfile)
+{
+ char *buffer;
+ uint32 filelen;
++ SilcConfigFile *ret;
+
- /* Buffer don't have EOF, but we'll need it. */
- buffer[filelen] = EOF;
++ if (!(buffer = silc_file_readfile(configfile, &filelen)))
++ return NULL;
+
- *ret_buffer = silc_buffer_alloc(filelen + 1);
- silc_buffer_pull_tail(*ret_buffer, filelen + 1);
- silc_buffer_put(*ret_buffer, buffer, filelen + 1);
++ ret = (SilcConfigFile *) silc_calloc(1, sizeof(*ret));
++ ret->filename = strdup(configfile);
++ ret->base = ret->p = buffer;
++ ret->len = filelen;
++ ret->line = 1; /* line count, start from first line */
++ return ret;
++}
+
- SILC_LOG_DEBUG(("Config file `%s' opened", filename));
++/* Frees a file object */
+
- /* Returns next token from a buffer to the dest argument. Returns the
- length of the token. This is used to take tokens from a configuration
- line. */
++void silc_config_close(SilcConfigFile *file)
++{
++ if (file) {
++ /* XXX FIXME: this check could probably be removed later */
++ uint32 my_len = (uint32) (strchr(file->base, EOF) - file->base);
++ SILC_CONFIG_DEBUG(("file=0x%x name=\"%s\" level=%d line=%lu", (uint32) file,
++ file->filename, file->level, file->line));
++ if (my_len != file->len) {
++ fprintf(stderr, "FATAL ERROR: saved len and current len does not match!\n");
++ abort();
++ }
++ silc_free(file->filename);
++ memset(file->base, 'F', file->len);
++ silc_free(file->base);
++ memset(file, 'F', sizeof(*file));
++ silc_free(file);
++ }
+}
+
- int silc_config_get_token(SilcBuffer buffer, char **dest)
++/* initializes a SilcConfigEntity pointer allocation */
++
++SilcConfigEntity silc_config_init(SilcConfigFile *file)
++{
++ SilcConfigEntity ret;
++ if (!file)
++ return NULL;
++ SILC_CONFIG_DEBUG(("Allocating new config entity"));
++ ret = (SilcConfigEntity) silc_calloc(1, sizeof(*ret));
++ ret->file = file;
++ return ret;
++};
++
++/* Returns the original filename of the object file */
+
- if (strchr(buffer->data, ':')) {
- len = strcspn(buffer->data, ":");
- if (len) {
- *dest = silc_calloc(len + 1, sizeof(char));
- memcpy(*dest, buffer->data, len);
- }
- silc_buffer_pull(buffer, len + 1);
- return len;
++char *silc_config_get_filename(SilcConfigFile *file)
+{
++ if (file)
++ return file->filename;
++ return NULL;
++}
++
++/* Returns the current line that file parsing arrived at */
++
++uint32 silc_config_get_line(SilcConfigFile *file)
++{
++ if (file)
++ return file->line;
++ return 0;
++}
++
++/* Returns a pointer to the beginning of the requested line. If the line
++ * was not found, NULL is returned */
++
++char *silc_config_read_line(SilcConfigFile *file, uint32 line)
++{
++ register char *p;
+ int len;
++ char *ret, *endbuf;
+
- return -1;
++ if (!file || (line <= 0))
++ return NULL;
++ for (p = file->base; *p && (*p != EOF); p++) {
++ if (line <= 1)
++ goto found;
++ if (*p == '\n')
++ line--;
+ }
++ return NULL;
+
- /* Returns number of tokens in a buffer. */
++ found:
++ if ((endbuf = strchr(p, '\n'))) {
++ len = endbuf - p;
++ ret = silc_calloc(len, sizeof(*ret));
++ strncpy(ret, p, len);
++ ret[len] = '\0';
++ }
++ else {
++ ret = silc_calloc(strlen(p), sizeof(*ret));
++ strcpy(ret, p);
++ }
++ return ret;
+}
+
- int silc_config_check_num_token(SilcBuffer buffer)
++/* Convenience function to read the current parsed line */
+
- int len, len2, num;
++char *silc_config_read_current_line(SilcConfigFile *file)
+{
- if (strchr(buffer->data, ':')) {
- len = 0;
- num = 0;
- while (strchr(buffer->data + len, ':')) {
- num++;
- len2 = strcspn(buffer->data + len, ":") + 1;
- len += len2;
++ return silc_config_read_line(file, file->line);
++}
++
++/* (Private) destroy a SilcConfigEntity */
+
- return num;
++static void silc_config_destroy(SilcConfigEntity ent)
++{
++ SilcConfigOption *oldopt, *nextopt;
++ SILC_CONFIG_DEBUG(("Freeing config entity [ent=0x%x] [opts=0x%x]",
++ (uint32) ent, (uint32) ent->opts));
++ for (oldopt = ent->opts; oldopt; oldopt = nextopt) {
++ nextopt = oldopt->next;
++ memset(oldopt->name, 'F', strlen(oldopt->name) + 1);
++ silc_free(oldopt->name);
++ memset(oldopt, 'F', sizeof(*oldopt));
++ silc_free(oldopt);
++ }
++ memset(ent, 'F', sizeof(*ent));
++ silc_free(ent);
++}
++
++/* Registers a new option in the specified entity */
++
++void silc_config_register(SilcConfigEntity ent, const char *name,
++ SilcConfigType type, SilcConfigCallback cb,
++ const SilcConfigTable *subtable, void *context)
++{
++ SilcConfigOption *newopt;
++ SILC_CONFIG_DEBUG(("Register new option=\"%s\" type=%u cb=0x%08x context=0x%08x",
++ name, type, (uint32) cb, (uint32) context));
++
++ if (!ent || !name)
++ return;
++ /* if we are registering a block, make sure there is a specified sub-table */
++ if ((type == SILC_CONFIG_ARG_BLOCK) && !subtable)
++ return;
++ /* refuse special tag */
++ if (!strcasecmp(name, "include"))
++ return;
++ if (silc_config_find_option(ent, name)) {
++ fprintf(stderr, "Internal Error: Option double registered\n");
++ abort();
++ }
++
++ /* allocate and append the new option */
++ newopt = (SilcConfigOption *) silc_calloc(1, sizeof(*newopt));
++ newopt->name = strdup(name);
++ newopt->type = type;
++ newopt->cb = cb;
++ newopt->subtable = subtable;
++ newopt->context = context;
++
++ if (!ent->opts)
++ ent->opts = newopt;
++ else {
++ SilcConfigOption *tmp;
++ for (tmp = ent->opts; tmp->next; tmp = tmp->next);
++ tmp->next = newopt;
++ }
++}
++
++/* Register a new option table in the specified config entity */
++
++void silc_config_register_table(SilcConfigEntity ent,
++ const SilcConfigTable table[], void *context)
++{
++ int i;
++ if (!ent || !table) return;
++ SILC_CONFIG_DEBUG(("Registering table"));
++ /* FIXME: some potability checks needed */
++ for (i = 0; table[i].name; i++) {
++ silc_config_register(ent, table[i].name, table[i].type,
++ table[i].callback, table[i].subtable, context);
++ }
++}
++
++/* ... */
++
++static int silc_config_main_internal(SilcConfigEntity ent)
++{
++ SilcConfigFile *file = ent->file;
++ char **p = &file->p;
++
++ /* loop throught statements */
++ while (1) {
++ char buf[255];
++ SilcConfigOption *thisopt;
++
++ /* makes it pointing to the next interesting char */
++ my_skip_comments(file);
++ /* got eof? */
++ if (**p == '\0' || **p == EOF) {
++ if (file->level > 1) /* cannot get eof in a sub-level! */
++ return SILC_CONFIG_EEXPECTED;
++ goto finish;
++ }
++ /* check if we completed this (sub) section (it doesn't matter if this
++ * is the main section) */
++ if (**p == '}') {
++ if (file->level < 2) /* can't be! must be at least one sub-block */
++ return SILC_CONFIG_EUNEXPECTED;
++ (*p)++;
++ goto finish;
++ }
++ //SILC_LOG_HEXDUMP(("Preparing lookup at line=%lu", file->line), *p, 16);
++
++ /* obtain the keyword */
++ my_next_token(file, buf);
++ SILC_CONFIG_DEBUG(("Looking up keyword=\"%s\" [line=%lu]", buf, file->line));
++
++ /* handle special directive */
++ if (!strcasecmp(buf, "include")) {
++ int ret;
++ SilcConfigFile *inc_file;
++ SilcConfigEntity inc_ent;
++
++ my_trim_spaces(file); /* prepare next char */
++
++ /* Now trying to include the specified file. The included file will
++ * be allowed to include sub-files but it will preserve the block-level
++ * of the including block. Note that the included file won't be allowed
++ * to raise the block level of the including block. */
++
++ my_get_string(file, buf); /* get the filename */
++ SILC_LOG_DEBUG(("Including file \"%s\"", buf));
++ /* before getting on, check if this row is REALLY complete */
++ if (*(*p)++ != ';')
++ return SILC_CONFIG_EMISSCOLON;
++
++ /* open the file and start the parsing */
++ inc_file = silc_config_open(buf);
++ if (!inc_file) /* does it point a valid filename? */
++ return SILC_CONFIG_ECANTOPEN;
++ inc_file->included = TRUE;
++
++ /* create a new entity and hack it to use the same options */
++ inc_ent = silc_config_init(inc_file);
++ inc_ent->opts = ent->opts;
++ ret = silc_config_main(inc_ent);
++
++ /* Cleanup.
++ * If the included file returned an error, the application will probably
++ * want to output some kind of error message. Because of this, we can't
++ * destroy THIS file object. The hack works this way: The application
++ * expects to destroy the originally created object file, so we'll swap
++ * the original file with the included file. */
++ if (ret) {
++ SilcConfigFile tmp_file;
++ SILC_CONFIG_DEBUG(("SWAPPING FILE OBJECTS"));
++ memcpy(&tmp_file, inc_file, sizeof(tmp_file));
++ memcpy(inc_file, file, sizeof(tmp_file));
++ silc_config_close(inc_file);
++ memcpy(file, &tmp_file, sizeof(tmp_file));
++ return ret;
++ }
++ /* otherwise if no errors encoured, continue normally */
++ silc_config_close(inc_file);
++ continue; /* this one is handled */
+ }
+
- return 0;
++ /* we have a registered option (it can also be a sub-block) */
++ thisopt = silc_config_find_option(ent, buf);
++ if (!thisopt)
++ return SILC_CONFIG_EBADOPTION;
++
++ my_trim_spaces(file); /* prepare next char */
++
++ /* option type is a block? */
++ if (thisopt->type == SILC_CONFIG_ARG_BLOCK) {
++ int ret;
++ SilcConfigEntity sub_ent;
++
++ SILC_CONFIG_DEBUG(("Entering sub-block"));
++ if (*(*p)++ != '{')
++ return SILC_CONFIG_EOPENBRACE;
++ /* build the new entity for this sub-block */
++ sub_ent = silc_config_init(ent->file);
++ /* use the previous specified table to describe this block's options */
++ silc_config_register_table(sub_ent, thisopt->subtable, thisopt->context);
++ /* run this block! */
++ ret = silc_config_main(sub_ent);
++ SILC_CONFIG_DEBUG(("Returned from sub-block [ret=%d]", ret));
++
++ if (ret) /* now check the result */
++ return ret;
++
++ /* now call block clean-up callback (if any) */
++ if (thisopt->cb) {
++ SILC_CONFIG_DEBUG(("Now calling clean-up callback (if any)"));
++ thisopt->cb(thisopt->type, thisopt->name, file->line,
++ NULL, thisopt->context);
++ }
++ /* Do we want ';' to be mandatory after close brace? */
++ if (*(*p)++ != ';')
++ return SILC_CONFIG_EMISSCOLON;
++ }
++ else if (thisopt->type == SILC_CONFIG_ARG_NONE) {
++ /* before getting on, check if this row is REALLY complete */
++ if (*(*p)++ != ';')
++ return SILC_CONFIG_EMISSCOLON;
++ SILC_CONFIG_DEBUG(("Triggering callback for none"));
++ if (thisopt->cb) {
++ thisopt->cb(thisopt->type, thisopt->name, file->line,
++ NULL, thisopt->context);
++ }
++ }
++ else {
++ void *pt;
++ int ret;
++
++ if (*(*p)++ != '=')
++ return SILC_CONFIG_EEXPECTEDEQUAL;
++
++ my_get_string(file, buf); /* get the option argument */
++ SILC_CONFIG_DEBUG(("With argument=\"%s\"", buf));
++
++ /* before getting on, check if this row is REALLY complete */
++ if (*(*p)++ != ';')
++ return SILC_CONFIG_EMISSCOLON;
++
++ /* convert the option argument to the right format */
++ pt = silc_config_marshall(thisopt->type, buf);
++ if (!pt)
++ return SILC_CONFIG_EINVALIDTEXT;
++ if (thisopt->cb) {
++ ret = thisopt->cb(thisopt->type, thisopt->name, file->line,
++ pt, thisopt->context);
++ if (ret) {
++ SILC_CONFIG_DEBUG(("Callback refused the value [ret=%d]", ret));
++ return ret;
++ }
++ }
++ silc_free(pt);
++ }
++ continue;
++
++ finish:
++ break;
+ }
+
++ return SILC_CONFIG_OK;
++}
++
++/* ... */
++
++int silc_config_main(SilcConfigEntity ent)
++{
++ SilcConfigFile *file = ent->file;
++ int ret;
++
++ /* don't silently accept a NULL entity */
++ if (!ent) {
++ ret = SILC_CONFIG_EGENERIC;
++ goto main_cleanup;
++ }
++
++ /* call the real main and store the result */
++ file->level++;
++ SILC_CONFIG_DEBUG(("[Lev=%d] Entering config parsing core", file->level));
++ ret = silc_config_main_internal(ent);
++ SILC_CONFIG_DEBUG(("[Lev=%d] Quitting main [ret=%d]", file->level, ret));
++ if (!file->level) /* when swap happens, we could close a file twice */
++ goto main_end;
++ file->level--;
++
++ /* If this file was included don't destroy the options set because it is
++ * the same of the including block. Although if this entity is in a
++ * sub-block created inside the included file, this options set must be
++ * destroyed. */
++ main_cleanup:
++ if ((file->level != 0) || (file->included != TRUE))
++ silc_config_destroy(ent);
++
++ main_end:
++ return ret;
+}
--- /dev/null
- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+/*
+
+ silcconfig.h
+
- Copyright (C) 1997 - 2000 Pekka Riikonen
++ Author: Johnny Mnemonic <johnny@themnemonic.org>
+
-
++ Copyright (C) 1997 - 2002 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; either version 2 of the License, or
+ (at your option) any later version.
- void silc_config_open(char *filename, SilcBuffer *ret_buffer);
- int silc_config_get_token(SilcBuffer buffer, char **dest);
- int silc_config_check_num_token(SilcBuffer);
++
+ 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.
+
+*/
+
++/****h* silcutil/SilcConfigAPI
++ *
++ * DESCRIPTION
++ *
++ * The SILC Config util library is based on two main objects, SilcConfigFile
++ * (or File object) and SilcConfigEntity (or Entity). The File objects are
++ * structs directly corresponding to the real files in the filesystem, while
++ * Entities are a little more abstract.
++ * An Entity is composed by delimited area on a File object (it can take the
++ * whole File object or just part of it), plus a group of known options.
++ *
++ * In order to parse this file, first you need to create a File object with
++ * the silc_config_open() function, and then you need to create the Entity
++ * with the silc_config_init() function.
++ * Now you can use the newly created Entity to register a group of expected
++ * known options and sub-blocks, and then you can call the main parsing loop
++ * with the silc_config_main() function.
++ * When silc_config_main() will return, if some error encoured the object file
++ * will point to the file that caused this error (this can be different from
++ * the originally opened file if it contained `Include' directives). If no
++ * errors encoured then the File objects will still point to the original
++ * file.
++ * While silc_config_main() will take care of destroying Entities before
++ * returning, you need to take care that the File object you created is freed
++ * with the silc_config_close() function.
++ *
++ * The SILC Config library won't take care about storing the values contained
++ * in the config file. You must take care about it with the callback
++ * functions.
++ *
++ * The config file syntax is pretty straightforward. All lines starting
++ * with `#' will be skipped, while sub-blocks are delimited by braces (see
++ * the example below).
++ * Options with argument must have the `=' character between the option
++ * name and the value. Simple words and numbers does not require quoting.
++ * There is a special built-in directive "Include" which allows you to include
++ * another config file in the point the directive is. You can also Include
++ * inside a sub-block body, in this case when parsing the included config file
++ * it will be assumed that we are within this block, and the included file
++ * won't be allowed to close his root block.
++ *
++ * Example:
++ *
++ * cipher {
++ * name = aes-256-cbc;
++ * module = "aes.sim.so";
++ * key_length = 32; # usually the default is just fine
++ * block_length = 16;
++ * };
++ * Include "/etc/silc/hash_funcs.conf";
++ *
++ ***/
++
+#ifndef SILCCONFIG_H
+#define SILCCONFIG_H
+
++/****d* silcutil/SilcConfigAPI/errno
++ *
++ * NAME
++ *
++ * enum { ... } - describe a SILC Config error
++ *
++ * DESCRIPTION
++ *
++ * The virtual integer `errno' is returned by the silc_config_main()
++ * function and indicates what went wrong.
++ * You can convert it to the corresponding error string with the function
++ * silc_config_strerror().
++ *
++ * SOURCE
++ */
++enum {
++ SILC_CONFIG_OK, /* OK */
++ SILC_CONFIG_ESILENT, /* Error defined by callback function */
++ SILC_CONFIG_EGENERIC, /* Invalid syntax */
++ SILC_CONFIG_EINTERNAL, /* Internal Error (caused by developer) */
++ SILC_CONFIG_ECANTOPEN, /* Can't open specified file */
++ SILC_CONFIG_EOPENBRACE, /* Expected open-brace '{' */
++ SILC_CONFIG_ECLOSEBRACE, /* Missing close-brace '}' */
++ SILC_CONFIG_ETYPE, /* Invalid data type */
++ SILC_CONFIG_EBADOPTION, /* Unknown option */
++ SILC_CONFIG_EINVALIDTEXT, /* Invalid text */
++ SILC_CONFIG_EDOUBLE, /* Double option specification */
++ SILC_CONFIG_EEXPECTED, /* Expected data but not found */
++ SILC_CONFIG_EEXPECTEDEQUAL, /* Expected '=' */
++ SILC_CONFIG_EUNEXPECTED, /* Unexpected data */
++ SILC_CONFIG_EMISSFIELDS, /* Missing needed fields */
++ SILC_CONFIG_EMISSCOLON, /* Missing ';' */
++};
++/***/
++
++/****d* silcutil/SilcConfigAPI/SilcConfigType
++ *
++ * NAME
++ *
++ * typedef enum { ... } SilcConfigType;
++ *
++ * DESCRIPTION
++ *
++ * This identifies the parameter type that an option has. This parameter
++ * is very important because the callback's *val pointer points to a
++ * memory location containing the previously specified data type.
++ * For example, if you specified an option with an integer parameter
++ * callback's *val will be a pointer to an integer.
++ *
++ * SOURCE
++ */
++typedef enum {
++ SILC_CONFIG_ARG_TOGGLE, /* TOGGLE on,off; yes,no; true, false; */
++ SILC_CONFIG_ARG_INT, /* callback wants an integer */
++ SILC_CONFIG_ARG_STR, /* callback expects \0-terminated str */
++ SILC_CONFIG_ARG_STRE, /* same as above, but can also be empty */
++ SILC_CONFIG_ARG_BLOCK, /* this is a sub-block */
++ SILC_CONFIG_ARG_SIZE, /* like int, but accepts suffixes kMG */
++ SILC_CONFIG_ARG_NONE, /* does not expect any args */
++} SilcConfigType;
++/***/
++
++/****f* silcutil/SilcConfigAPI/SilcConfigCallback
++ *
++ * SYNOPSIS
++ *
++ * typedef int (*SilcConfigCallback)(SilcConfigType type, const char *name,
++ * uint32 line, void *val, void *context);
++ * DESCRIPTION
++ *
++ * This is the callback prototype for the options handler. The pointer
++ * `val' points to a location of type described by `type'. `name' points
++ * to a null-terminated string with the name of the option which triggered
++ * this callback, that is stated at line `line'. `context' is the
++ * user-specified context provided when this option was registered.
++ *
++ ***/
++typedef int (*SilcConfigCallback)(SilcConfigType type, const char *name,
++ uint32 line, void *val, void *context);
++
++/****s* silcutil/SilcConfigAPI/SilcConfigTable
++ *
++ * SYNOPSIS
++ *
++ * typedef struct { ... } SilcConfigTable;
++ *
++ * DESCRIPTION
++ *
++ * SILC Config table defines an easy and quick way of registering options
++ * in an entity. The function silc_config_register_table() will take as
++ * argument a SilcConfigTable array terminated by a NULL struct, it is
++ * important thus, that the `name' field of the terminating struct is set
++ * to NULL.
++ *
++ * char *name
++ *
++ * The option name lowercase. The matching is always case-insensitive,
++ * but for convention the option specification must always be lowercase.
++ *
++ * SilcConfigType type
++ *
++ * This specifies what kind of parameter this option expects. The
++ * special cases SILC_CONFIG_ARG_BLOCK tells SILC Config that this is
++ * not a normal option but the name of a sub-block of the current
++ * block (there is no limit to the number of nested blocks allowed).
++ *
++ * SilcConfigCallback callback
++ *
++ * Normally this is the value handler of the current option. If this
++ * field is set to NULL then the value is silently discarded. Useful
++ * for example to support deprecated options.
++ *
++ * SilcConfigTable *subtable
++ *
++ * If the `type' field is set to SILC_CONFIG_ARG_BLOCK, then this field
++ * must point to a valid sub-table NULL-terminated array. If `type' is
++ * something else, this valued is unused.
++ *
++ ***/
++typedef struct SilcConfigTableStruct {
++ char *name;
++ SilcConfigType type;
++ SilcConfigCallback callback;
++ const struct SilcConfigTableStruct *subtable;
++} SilcConfigTable;
++
++/****s* silcutil/SilcConfigAPI/SilcConfigFile
++ *
++ * SYNOPSIS
++ *
++ * typedef struct { ... } SilcConfigFile;
++ *
++ * DESCRIPTION
++ *
++ * A File object holds the data contained in a previously loaded file by
++ * the silc_config_open() function.
++ * This is an internally allocated struct and must be used only with the
++ * helper functions.
++ *
++ ***/
++typedef struct SilcConfigFileObject SilcConfigFile;
++
++/****s* silcutil/SilcConfigAPI/SilcConfigEntity
++ *
++ * SYNOPSIS
++ *
++ * typedef struct { ... } SilcConfigEntity;
++ *
++ * DESCRIPTION
++ *
++ * The SILC Config is based on config entities. An entity contains the
++ * SilcConfigFile object we are parsing and the registered options.
++ *
++ ***/
++typedef struct SilcConfigEntityObject *SilcConfigEntity;
++
++/* Macros */
++
++/****d* silcutil/SilcConfigAPI/SILC_CONFIG_CALLBACK
++ *
++ * NAME
++ *
++ * #define SILC_CONFIG_CALLBACK ...
++ *
++ * DESCRIPTION
++ *
++ * Generic macro to define SilcConfigCallback functions. This defines a
++ * static function with name `func' as a config callback function.
++ *
++ * SOURCE
++ */
++#define SILC_CONFIG_CALLBACK(func) \
++static int func(SilcConfigType type, const char *name, \
++ uint32 line, void *val, void *context)
++/***/
++
+/* Prototypes */
- #endif
+
++/****f* silcutil/SilcConfigAPI/silc_config_open
++ *
++ * SYNOPSIS
++ *
++ * SilcConfigFile *silc_config_open(char *configfile);
++ *
++ * DESCRIPTION
++ *
++ * Tries to open the config file `configfile' and returns a valid File
++ * object on success, or NULL on failure.
++ * An File object created this way must be destroyed with the function
++ * silc_config_close().
++ *
++ ***/
++SilcConfigFile *silc_config_open(char *configfile);
++
++/****f* silcutil/SilcConfigAPI/silc_config_close
++ *
++ * SYNOPSIS
++ *
++ * void silc_config_close(SilcConfigFile *file);
++ *
++ * DESCRIPTION
++ *
++ * Closes and frees the File object `file', which must have been returned
++ * by a previous call to silc_config_open(). Otherwise, or if
++ * this function has already been called before for the same File object,
++ * undefined behaviour occurs.
++ * If `file' is NULL, no operation is performed.
++ *
++ ***/
++void silc_config_close(SilcConfigFile *file);
++
++/****f* silcutil/SilcConfigAPI/silc_config_init
++ *
++ * SYNOPSIS
++ *
++ * SilcConfigEntity silc_config_init(SilcConfigFile *file);
++ *
++ * DESCRIPTION
++ *
++ * Creates an Entity pointing to the valid File object `file', which must
++ * be returned by a previous call to silc_config_open(), otherwise NULL
++ * is returned.
++ * Entities will be automatically destroyed after the call to the
++ * silc_config_main() function, because of this no uninit functions are
++ * provided.
++ *
++ ***/
++SilcConfigEntity silc_config_init(SilcConfigFile *file);
++
++/****f* silcutil/SilcConfigAPI/silc_config_strerror
++ *
++ * SYNOPSIS
++ *
++ * char *silc_config_strerror(int errnum);
++ *
++ * DESCRIPTION
++ *
++ * The silc_config_strerror() function returns a string describing the
++ * error code passed in the argument `errnum'.
++ *
++ ***/
++char *silc_config_strerror(int errnum);
++
++/****f* silcutil/SilcConfigAPI/silc_config_get_filename
++ *
++ * SYNOPSIS
++ *
++ * char *silc_config_get_filename(SilcConfigFile *file);
++ *
++ * DESCRIPTION
++ *
++ * Returns the original filename of the object file.
++ * The returned pointer points to internally allocated storage and must
++ * not be freed, modified or stored.
++ *
++ ***/
++char *silc_config_get_filename(SilcConfigFile *file);
++
++/****f* silcutil/SilcConfigAPI/silc_config_get_line
++ *
++ * SYNOPSIS
++ *
++ * uint32 silc_config_get_line(SilcConfigFile *file);
++ *
++ * DESCRIPTION
++ *
++ * Returns the current line that file parsing arrived at.
++ *
++ ***/
++uint32 silc_config_get_line(SilcConfigFile *file);
++
++/****f* silcutil/SilcConfigAPI/silc_config_read_line
++ *
++ * SYNOPSIS
++ *
++ * char *silc_config_read_line(SilcConfigFile *file, uint32 line);
++ *
++ * DESCRIPTION
++ *
++ * Returns a dynamically allocated null-terminated buffer containing the
++ * line `line' of `file'.
++ * The returned pointer must be freed when it's not needed any longer.
++ *
++ * SEE ALSO
++ * silc_config_read_current_line
++ *
++ ***/
++char *silc_config_read_line(SilcConfigFile *file, uint32 line);
++
++/****f* silcutil/SilcConfigAPI/silc_config_read_current_line
++ *
++ * SYNOPSIS
++ *
++ * char *silc_config_read_current_line(SilcConfigFile *file);
++ *
++ * DESCRIPTION
++ *
++ * Returns a dynamically allocated buffer containing the line that the
++ * parser stopped at. This is a convenience function for
++ * silc_config_read_line.
++ * The returned pointer must be freed when it's not needed any longer.
++ *
++ ***/
++char *silc_config_read_current_line(SilcConfigFile *file);
++
++/****f* silcutil/SilcConfigAPI/silc_config_register
++ *
++ * SYNOPSIS
++ *
++ * void silc_config_register(SilcConfigEntity ent, const char *name,
++ * SilcConfigType type, SilcConfigCallback cb,
++ * const SilcConfigTable *subtable,
++ * void *context);
++ *
++ * DESCRIPTION
++ *
++ * Register option `name' in the entity `ent'. If `cb' is not NULL, it
++ * will be called with the *val pointer pointing to an internally
++ * allocated storage of type described by `type'.
++ * If `type' is SILC_CONFIG_ARG_BLOCK, then `subtable' must be a valid
++ * pointer to a SilcConfigTable array specified the options in the
++ * sub-block.
++ *
++ * SEE ALSO
++ * silc_config_register_table
++ *
++ ***/
++void silc_config_register(SilcConfigEntity ent, const char *name,
++ SilcConfigType type, SilcConfigCallback cb,
++ const SilcConfigTable *subtable, void *context);
++
++/****f* silcutil/SilcConfigAPI/silc_config_register_table
++ *
++ * SYNOPSIS
++ *
++ * void silc_config_register_table(SilcConfigEntity ent,
++ * const SilcConfigTable table[],
++ * void *context);
++ *
++ * DESCRIPTION
++ *
++ * Register the tableset of options `table' automatically in the entity
++ * `ent'. If defined in the table, the callback functions will be called
++ * all with the same context `context'.
++ * The `table' array must be terminated with an entry with the name field
++ * set to NULL.
++ *
++ * SEE ALSO
++ * SilcConfigTable
++ *
++ ***/
++void silc_config_register_table(SilcConfigEntity ent,
++ const SilcConfigTable table[], void *context);
++
++/****f* silcutil/SilcConfigAPI/silc_config_main
++ *
++ * SYNOPSIS
++ *
++ * int silc_config_main(SilcConfigEntity ent);
++ *
++ * DESCRIPTION
++ *
++ * Enter the main parsing loop. When this function returns the parsing
++ * is finished in the current block (and sub-blocks).
++ * When this function exits, the entity is already destroyed, because
++ * of this you should set it to NULL right after the function call.
++ *
++ ***/
++int silc_config_main(SilcConfigEntity ent);
++
++#endif /* !SILCCONFIG_H */
--- /dev/null
- * See the source code for SILC coding conventions about how choosing
+/*
+
+ silclog.h
+
+ Author: Johnny Mnemonic <johnny@themnemonic.org>
+
+ Copyright (C) 1997 - 2002 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; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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.
+
+*/
+
+/****h* silcutil/SilcLogAPI
+ *
+ * DESCRIPTION
+ *
+ * The SILC logging APIs provide a powerful and easy-to-use interface to
+ * the logging system and debugging output.
+ *
+ ***/
+
+#ifndef SILCLOG_H
+#define SILCLOG_H
+
+/****d* silcutil/SilcLogAPI/SilcLogType
+ *
+ * NAME
+ *
+ * typedef enum { ... } SilcLogType;
+ *
+ * DESCRIPTION
+ *
+ * This is the main logging channel id. There are currently four known
+ * logging channels (plus the debugging output channel), and they are
+ * ordered by importance.
- /* Total logging channels */
++ * See the source code for SILC coding conventions about how to choose
+ * the right output channel.
+ *
+ * SOURCE
+ */
+typedef enum {
+ /* Generic info channel file */
+ SILC_LOG_INFO,
+
+ /* This should be used for warnings and non critical failures */
+ SILC_LOG_WARNING,
+
+ /* Generic error and critical failures messages */
+ SILC_LOG_ERROR,
+
+ /* Fatal messages (usually situations that will lead to a program crash */
+ SILC_LOG_FATAL,
+
- * print a formatted hexdump to stderr, and is commonly what you would it
- * like to be. `file', `function', and `line' are the corresponding
++ /* Total number logging channels */
+ SILC_LOG_MAX
+} SilcLogType;
+/***/
+
+/****f* silcutil/SilcLogAPI/SilcLogCb
+ *
+ * SYNOPSIS
+ *
+ * typedef bool (*SilcLogCb)(SilcLogType type, char *message,
+ * void *context);
+ *
+ * DESCRIPTION
+ *
+ * The logging custom callback function. The `type' is the channel ID
+ * that triggered the event, which allows you to use the same callback
+ * function for multiple logging channels.
+ * The `message' parameter points to a null-terminated buffer containing
+ * the received message, while `context' is the caller-specified context.
+ * The message must not be modified or freed by the callback function.
+ *
+ * SEE ALSO
+ * silc_log_set_callback
+ *
+ ***/
+typedef bool (*SilcLogCb)(SilcLogType type, char *message, void *context);
+
+/****f* silcutil/SilcLogAPI/SilcLogDebugCb
+ *
+ * SYNOPSIS
+ *
+ * typedef bool (*SilcLogDebugCb)(char *file, char *function, int line,
+ * char *message, void *context);
+ *
+ * DESCRIPTION
+ *
+ * The debug logging callback function. The default behaviour is to
+ * output messages to stderr. `file', `function', and `line' are the
+ * corresponding offsets in the source files. `message' points to a
+ * null-terminated buffer containing the debugging message, and `context'
+ * is the caller-specified context.
+ * The message must not be modified or freed by the callback function.
+ * If the function returns TRUE, SilcLog will assume the message as handled
+ * and won't run its default handler.
+ *
+ * SEE ALSO
+ * silc_debug, silc_log_set_debug_callbacks
+ *
+ ***/
+typedef bool (*SilcLogDebugCb)(char *file, char *function, int line,
+ char *message, void *context);
+
+/****f* silcutil/SilcLogAPI/SilcLogHexdumpCb
+ *
+ * SYNOPSIS
+ *
+ * typedef bool (*SilcDebugHexdumpCb)(char *file, char *function, int line,
+ * unsigned char *data, uint32 data_len,
+ * char *message, void *context;
+ *
+ * DESCRIPTION
+ *
+ * The hexdump logging callback function. The default behaviour is to
- * The standard behaviour is the same as SILC_LOG_INFO, but this macro
- * also depends on the global debugging macro SILC_DEBUG.
- * Undefining the global SILC_DEBUG define causes these functions to be
- * defined to an empty value, thus removing all logging calls from the
- * compiled program.
- *
- * SEE ALSO
- * SILC_LOG_INFO
++ * print a formatted hexdump to stderr, and is commonly what you would
++ * like it to be. `file', `function', and `line' are the corresponding
+ * offsets in the source files. `data' is the begin of the buffer that
+ * should be hexdumped, which is `data_len' bytes long.
+ * The `message' parameter points to a null-terminated buffer containing
+ * the received message, while `context' is the caller-specified context.
+ * The message must not be modified or freed by the callback function.
+ * If the function returns TRUE, SilcLog will assume the message as handled
+ * and won't run its default handler.
+ *
+ * SEE ALSO
+ * silc_debug_hexdump, silc_log_set_debug_callbacks
+ *
+ ***/
+typedef bool (*SilcLogHexdumpCb)(char *file, char *function, int line,
+ unsigned char *data, uint32 data_len,
+ char *message, void *context);
+
+/* Global Variables */
+
+/****v* silcutil/SilcLogAPI/silc_log_quick
+ *
+ * NAME
+ *
+ * bool silc_log_quick -- enable/disable fast logging output
+ *
+ * DESCRIPTION
+ *
+ * SilcLog makes use of libc stream buffering output, which means that it
+ * saves HD activity by buffering the logging messages and writing them
+ * all together every some minutes (default is 5 minutes).
+ * Setting this variable to TRUE will force SilcLog to write messages to the
+ * filesystem as soon as they are received. This increases the CPU activity
+ * notably on bigger servers, but reduces memory usage.
+ * If you want to change the logging style on-the-fly, make sure to call
+ * silc_log_flush_all() after setting this variable to TRUE.
+ *
+ ***/
+extern DLLAPI bool silc_log_quick;
+
+/****v* silcutil/SilcLogAPI/silc_log_flushdelay
+ *
+ * NAME
+ *
+ * long silc_log_flushdelay -- flushing time delay
+ *
+ * DESCRIPTION
+ *
+ * Sets the logfiles flushing delay in seconds. As for now, changing this
+ * value AFTER logfiles initialization won't take effect until previous
+ * delay time will expire; for example if you change from 300 seconds to
+ * 60 seconds you will have to wait up to 300 seconds for this change to
+ * take effect.
+ * This value must be greater than 2 seconds.
+ *
+ ***/
+extern DLLAPI long silc_log_flushdelay;
+
+/****v* silcutil/SilcLogAPI/silc_debug
+ *
+ * NAME
+ *
+ * bool silc_debug -- enable/disable debugging output
+ *
+ * DESCRIPTION
+ *
+ * If silc_debug is set to FALSE, debugging functions won't procude any
+ * output. This is useful when for example you compile in the debugging
+ * support but at a certain point you want to send the program in the
+ * background.
+ *
+ * SEE ALSO
+ * SILC_LOG_DEBUG
+ *
+ ***/
+extern DLLAPI bool silc_debug;
+
+/****v* silcutil/SilcLogAPI/silc_debug_hexdump
+ *
+ * NAME
+ *
+ * bool silc_debug_hexdump -- enable/disable debugging output
+ *
+ * DESCRIPTION
+ *
+ * If silc_debug_hexdump is set to FALSE, debugging functions won't produce
+ * any output. This is useful when for example you compile in the debugging
+ * support but at a certain point you want to send the program in the
+ * background.
+ *
+ * SEE ALSO
+ * SILC_LOG_HEXDUMP
+ *
+ ***/
+extern DLLAPI bool silc_debug_hexdump;
+
+/* Macros */
+
+#ifdef WIN32
+#define __FUNCTION__ ""
+#endif
+
+/****d* silcutil/SilcLogAPI/SILC_LOG_INFO
+ *
+ * NAME
+ *
+ * #define SILC_LOG_INFO(...)
+ *
+ * DESCRIPTION
+ *
+ * This macro is a wrapper to the main logging function.
+ * It supports variable argument list formatting, and *automatically*
+ * appends newline at the end of the string.
+ *
+ * NOTES
+ *
+ * This macro requires double parenthesis to ensure that the VA list
+ * formatting would work correctly.
+ *
+ * EXAMPLE
+ *
+ * SILC_LOG_INFO(("Today i feel %s", core->mood));
+ *
+ * SOURCE
+ */
+#define SILC_LOG_INFO(fmt) silc_log_output(SILC_LOG_INFO, silc_format fmt)
+/***/
+
+/****d* silcutil/SilcLogAPI/SILC_LOG_WARNING
+ *
+ * NAME
+ *
+ * #define SILC_LOG_WARNING(...)
+ *
+ * DESCRIPTION
+ *
+ * Wrapper to the WARNING logging channel.
+ * Please see the SILC_LOG_INFO macro.
+ *
+ * SEE ALSO
+ * SILC_LOG_INFO
+ *
+ * SOURCE
+ */
+#define SILC_LOG_WARNING(fmt) silc_log_output(SILC_LOG_WARNING, silc_format fmt)
+/***/
+
+/****d* silcutil/SilcLogAPI/SILC_LOG_ERROR
+ *
+ * NAME
+ *
+ * #define SILC_LOG_ERROR(...)
+ *
+ * DESCRIPTION
+ *
+ * Wrapper to the ERROR logging channel.
+ * Please see the SILC_LOG_INFO macro.
+ *
+ * SEE ALSO
+ * SILC_LOG_INFO
+ *
+ * SOURCE
+ */
+#define SILC_LOG_ERROR(fmt) silc_log_output(SILC_LOG_ERROR, silc_format fmt)
+/***/
+
+/****d* silcutil/SilcLogAPI/SILC_LOG_FATAL
+ *
+ * NAME
+ *
+ * #define SILC_LOG_FATAL(...)
+ *
+ * DESCRIPTION
+ *
+ * Wrapper to the FATAL logging channel.
+ * Please see the SILC_LOG_INFO macro.
+ *
+ * SEE ALSO
+ * SILC_LOG_INFO
+ *
+ * SOURCE
+ */
+#define SILC_LOG_FATAL(fmt) silc_log_output(SILC_LOG_FATAL, silc_format fmt)
+/***/
+
+/****d* silcutil/SilcLogAPI/SILC_LOG_DEBUG
+ *
+ * NAME
+ *
+ * #define SILC_LOG_DEBUG(...)
+ *
+ * DESCRIPTION
+ *
+ * This is a special wrapper to the debugging output (usually stderr).
- * The second parameter is a (char *) pointer to the beginning of the
- * memory section that should be hexdumped, and the third parameter is
- * the length of this memory section.
- * This macro is also affected by the global variable silc_debug_hexdump.
++ * The standard behaviour is the same as SILC_LOG_INFO, with the difference
++ * that this macro also depends on the global define SILC_DEBUG.
++ * Undefining SILC_DEBUG causes these functions to be defined to an empty
++ * value, thus removing all debug logging calls from the compiled
++ * application.
++ * This macro is also affected by the global variable silc_debug.
+ *
+ * SOURCE
+ */
+#ifdef SILC_DEBUG
+#define SILC_LOG_DEBUG(fmt) silc_log_output_debug(__FILE__, \
+ __FUNCTION__, \
+ __LINE__, \
+ silc_format fmt)
+#else
+#define SILC_LOG_DEBUG(fmt)
+#endif /* SILC_DEBUG */
+/***/
+
+/****d* silcutil/SilcLogAPI/SILC_LOG_HEXDUMP
+ *
+ * NAME
+ *
+ * #define SILC_LOG_HEXDUMP(...)
+ *
+ * DESCRIPTION
+ *
+ * This is a special wrapper to the hexdump output function. This macro
+ * behaves slightly differently from other logging wrappers.
+ * The first parameter, is composed by a group of parameters delimited by
+ * parenthesis.
- * defined to an empty value, thus removing all logging calls from the
- * compiled program.
++ * The second parameter is a `char *' pointer pointing to the beginning
++ * of the memory section that should be hexdumped, and the third parameter
++ * is the length of this memory section.
+ * Undefining the global SILC_DEBUG define causes these functions to be
- * must not be freed, modified or stored.
++ * defined to an empty value, thus removing all debug logging calls from
++ * the compiled application.
++ * This macro is also affected by the global variable silc_debug_hexdump.
+ *
+ * EXAMPLE
+ *
+ * SILC_LOG_HEXDUMP(("Outgoing packet [%d], len %d", pckt->seq, pckt->len),
+ * pckt->data, pckt->datalen);
+ *
+ * SOURCE
+ */
+#ifdef SILC_DEBUG
+#define SILC_LOG_HEXDUMP(fmt, data, len) silc_log_output_hexdump(__FILE__, \
+ __FUNCTION__, \
+ __LINE__, \
+ (data), (len), \
+ silc_format fmt)
+#else
+#define SILC_LOG_HEXDUMP(fmt, data, len)
+#endif /* SILC_DEBUG */
+/***/
+
+/* Prototypes */
+
+/****f* silcutil/SilcLogAPI/silc_log_output
+ *
+ * SYNOPSIS
+ *
+ * void silc_log_output(SilcLogType type, char *string);
+ *
+ * DESCRIPTION
+ *
+ * This is the main function for logging output. Please note that you
+ * should rather use one of the logging wrapper macros.
+ * If you really want to use this function, its usage is quite simple.
+ * The `type' parameter identifies the channel to use, while the `string'
+ * parameter must be a dynamic allocated (null-terminated) buffer, because
+ * it will be freed at the end of this function, for internal reasons.
+ * If there are registered callbacks for the specified type, this function
+ * will first trigger those callbacks. The callback functions must NOT
+ * free or modify the original buffer.
+ *
+ * SEE ALSO
+ * SILC_LOG_INFO, SILC_LOG_WARNING, SILC_LOG_ERROR, SILC_LOG_FATAL
+ *
+ ***/
+void silc_log_output(SilcLogType type, char *string);
+
+/****f* silcutil/SilcLogAPI/silc_log_get_file
+ *
+ * SYNOPSIS
+ *
+ * char *silc_log_get_file(SilcLogType type);
+ *
+ * DESCRIPTION
+ *
+ * Returns the current logging file for the channel `type'.
+ * If there has been an error during the opening of this channel, NULL
+ * is returned, even if the file has been previously set with
+ * silc_log_set_file().
+ * The returned pointer points to internally allocated storage and must
- * SilcLogCb, silc_log_reset_callbacks
++ * not be freed, modified or stored.
+ *
+ ***/
+char *silc_log_get_file(SilcLogType type);
+
+/****f* silcutil/SilcLogAPI/silc_log_set_file
+ *
+ * SYNOPSIS
+ *
+ * bool silc_log_set_file(SilcLogType type, char *filename, uint32 maxsize,
+ * SilcSchedule scheduler);
+ *
+ * DESCRIPTION
+ *
+ * Sets `filename', which can be maximum `maxsize' bytes long, as the new
+ * logging file for the channel `type'. If you specify an illegal filename
+ * a warning message is printed and FALSE is returned. In this case
+ * logging settings are not changed.
+ * You can disable logging for a channel by specifying NULL filename, the
+ * maxsize in this case is not important.
+ * The `scheduler' parameter is needed by the internal logging to allow
+ * buffered output and thus to save HD activity.
+ *
+ ***/
+bool silc_log_set_file(SilcLogType type, char *filename, uint32 maxsize,
+ SilcSchedule scheduler);
+
+/****f* silcutil/SilcLogAPI/silc_log_set_callback
+ *
+ * SYNOPSIS
+ *
+ * void silc_log_set_callback(SilcLogType type, SilcLogCb cb,
+ * void *context);
+ *
+ * DESCRIPTION
+ *
+ * Set `cb' as the default callback function for the logging channel
+ * `type'. When SilcLog receives a message for this channel, it will
+ * trigger the callback function. If the callback function returns TRUE
+ * SilcLog will assume the input as handled and won't run its default
+ * handler.
+ * You can disable/remove a callback by setting it to NULL or calling the
+ * function silc_log_reset_callbacks.
+ * If set, the callback function must be in the form described by
+ * SilcLogCb.
+ *
+ * SEE ALSO
++ * silc_log_reset_callbacks
+ *
+ ***/
+void silc_log_set_callback(SilcLogType type, SilcLogCb cb, void *context);
+
+/****f* silcutil/SilcLogAPI/silc_log_reset_callbacks
+ *
+ * SYNOPSIS
+ *
+ * void silc_log_reset_callbacks();
+ *
+ * DESCRIPTION
+ *
+ * Removes all logging callbacks for normal channels. This function does
+ * NOT remove callbacks for debugging channels (debug and hexdump), you
+ * rather need to call silc_log_set_debug_callbacks() with NULL callbacks.
+ *
+ ***/
+void silc_log_reset_callbacks();
+
+/****f* silcutil/SilcLogAPI/silc_log_flush_all
+ *
+ * SYNOPSIS
+ *
+ * void silc_log_flush_all();
+ *
+ * DESCRIPTION
+ *
+ * Forces flushing for all logging channels. This should be called for
+ * example after receiving special signals.
+ *
+ * SEE ALSO
+ * silc_log_quick
+ *
+ ***/
+void silc_log_flush_all();
+
+/****f* silcutil/SilcLogAPI/silc_log_reset_all
+ *
+ * SYNOPSIS
+ *
+ * void silc_log_reset_all();
+ *
+ * DESCRIPTION
+ *
+ * Forces all logging channels to close and reopen their streams. Useful
+ * for example after a SIGHUP signal.
+ * Please note that this function could cause some warning messages if
+ * some logging channel points to an illegal filename.
+ *
+ ***/
+void silc_log_reset_all();
+
+/****f* silcutil/SilcLogAPI/silc_log_output_debug
+ *
+ * SYNOPSIS
+ *
+ * void silc_log_output_debug(char *file, char *function,
+ * int line, char *string);
+ *
+ * DESCRIPTION
+ *
+ * This is the main function for debug output. Please note that you should
+ * rather use the wrapper macro SILC_LOG_DEBUG.
+ * If you want to use it anyway, the `file', `function', and `line' are the
+ * corresponding offsets in the source files, while `string' must be a
+ * dynamic allocated (null-terminated) buffer.
+ *
+ ***/
+void silc_log_output_debug(char *file, char *function,
+ int line, char *string);
+
+/****f* silcutil/SilcLogAPI/silc_log_output_hexdump
+ *
+ * SYNOPSIS
+ *
+ * void silc_log_output_hexdump(char *file, char *function,
+ * int line, void *data_in,
+ * uint32 len, char *string);
+ *
+ * DESCRIPTION
+ *
+ * This is the main function for hexdump output. Please note that you
+ * should rather use the wrapper macro SILC_LOG_HEXDUMP.
+ * If you want to use it anyway, the `file', `function', and `line' are the
+ * corresponding offsets in the source files, `data_in' is the beginning
+ * of the buffer you wish to hexdump, which is `len' bytes long.
+ * `string' must be a dynamic allocated (null-terminated) buffer.
+ *
+ ***/
+void silc_log_output_hexdump(char *file, char *function,
+ int line, void *data_in,
+ uint32 len, char *string);
+
+/****f* silcutil/SilcLogAPI/silc_log_set_debug_callbacks
+ *
+ * SYNOPSIS
+ *
+ * void silc_log_set_debug_callbacks(SilcLogDebugCb debug_cb,
+ * void *debug_context,
+ * SilcLogHexdumpCb hexdump_cb,
+ * void *hexdump_context);
+ *
+ * DESCRIPTION
+ *
+ * Sets `debug_cb' as the the default callback function for the debug
+ * output, that will be called with the `debug_context' parameter.
+ * When SilcLog receives a debug message, it will trigger the callback
+ * function. If the callback function returns TRUE SilcLog will assume
+ * the input as handled and won't run its default handler.
+ * `hexdump_cb' and `hexdump_context' works the same way, except that they
+ * are referred to SILC_LOG_HEXDUMP requests.
+ * You can disable/remove a callback by setting it to NULL.
+ * If set, each callback function must be either in the form described by
+ * SilcLogDebugCb or SilcLogHexdumpCb.
+ *
+ * SEE ALSO
+ * SilcLogDebugCb, SilcLogHexdumpCb
+ *
+ ***/
+void silc_log_set_debug_callbacks(SilcLogDebugCb debug_cb,
+ void *debug_context,
+ SilcLogHexdumpCb hexdump_cb,
+ void *hexdump_context);
+
+/****f* silcutil/SilcLogAPI/silc_log_set_debug_string
+ *
+ * SYNOPSIS
+ *
+ * void silc_log_set_debug_string(const char *debug_string);
+ *
+ * DESCRIPTION
+ *
+ * Sets `debug_string' as the regexp string for filtering debugging
+ * output. The string is copied and it can be modified/destroyed after
+ * this function call.
+ *
+ ***/
+void silc_log_set_debug_string(const char *debug_string);
+
+#endif /* !SILCLOG_H */