From: Giovanni Giacobbi Date: Wed, 13 Feb 2002 11:56:01 +0000 (+0000) Subject: New silcconfig library and server parser. Merged silc-newconfig-final.patch. X-Git-Tag: silc.client.0.8.1~72 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=d47a87b03b846e2333ef57b2c0d81f1644992964 New silcconfig library and server parser. Merged silc-newconfig-final.patch. --- d47a87b03b846e2333ef57b2c0d81f1644992964 diff --cc CHANGES index 65d6f219,00000000..f3617b11 mode 100644,000000..100644 --- a/CHANGES +++ b/CHANGES @@@ -1,7005 -1,0 +1,7018 @@@ ++Wed Feb 13 12:46:25 CET 2002 Johnny Mnemonic ++ ++ * 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 + + * 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 + + * Merged new irssi from irssi.org's CVS, the version 0.7.99. + +Sat Feb 9 14:54:33 EET 2002 Pekka Riikonen + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Fixed a crash in server related to channel announcements. + Affected file silcd/server.c. + +Mon Jan 28 17:49:42 EET 2002 Pekka Riikonen + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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:: and flushdelay::. Affected files + lib/silcutil/silclog.[ch], silcd/serverconfig.[ch]. + +Sun Jan 6 12:49:40 EET 2002 Pekka Riikonen + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Added doc/examples installation target in Makefile.am.pre. + A patch by salo. + +Tue Dec 4 17:43:19 EET 2001 Pekka Riikonen + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 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 + + * 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 ' + + * 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 ' + + * 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 ' + + * 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 ' + + * 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 + + * 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 + + * 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 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * __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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Upgraded dotconf 1.0.2 to 1.0.6 in lib/dotconf. + +Tue Oct 23 13:51:19 EEST 2001 Pekka Riikonen + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Better checks for non-printable chars in nick added. + Affected file silcd/command.c. + +Thu Oct 18 09:18:58 EDT 2001 Pekka Riikonen + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Created SFTP client and server test programs in the + lib/silcsftp/tests directory. + +Wed Oct 3 23:31:42 EDT 2001 Pekka Riikonen + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Fixed MSVC++ project files and added missing files to + Makefiles under win32/. + +Wed Jul 25 18:43:54 EEST 2001 Pekka Riikonen + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * /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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * make install generates new server keys only if there is not + keys already. + +Mon Jun 18 18:49:07 EEST 2001 Pekka Riikonen + + * 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 + + * 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 + + * Fixed GETKEY crash, it crashed if the command did not succseed. + +Tue Jun 12 21:36:18 EEST 2001 Pekka Riikonen + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Fixed silc_xxx_get_supported to not crash at some circumstances. + +Sun May 20 13:45:58 EEST 2001 Pekka Riikonen + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Merged dotconf version 1.0.2 into lib/dotconf. + +Sun May 13 19:32:09 EEST 2001 Pekka Riikonen + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Fixed the version checking in the server. Affected file is + silcd/protocol.c. + +Thu Apr 19 19:52:46 EEST 2001 Pekka Riikonen + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Fixed the make install. + +Tue Apr 10 16:20:34 EEST 2001 Pekka Riikonen + + * 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 + + * 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 + + * 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 + + * Made preliminary `make install' work. + +Thu Apr 5 17:42:30 EEST 2001 Pekka Riikonen + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 to 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 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 and 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 argument + (if it chooses to do so) since the CHANNEL_KEY packet will + force the channel key change anyway. The 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 [] 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 + + * 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 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 + + * Update TODO. Todo in commands in the server. + +Tue Mar 20 15:45:14 EET 2001 Pekka Riikonen + + * 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 + + * Added one new argument 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 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 + + * 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 + + * 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 + + * Added dist-bzip hook to the Makefile.am to make bzip2 + compressed distributions. + +Mon Mar 12 18:43:38 EET 2001 Pekka Riikonen + + * 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 + + * 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 + + * 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 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 + + * 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 + + * 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 + + * 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 + + * 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 [] option from CMODE command as the cipher + name decides the key length, nowadays. See the defined ciphers + from the protocol specification. + + * Added [] option to the CMODE command to define the HMAC + for the channel. Added SILC_CMODE_HMAC channel mode. + + * Added [] 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Updated parts of the protocol specification to keep it up + to date. + +Thu Feb 22 15:08:20 EET 2001 Pekka Riikonen + + * 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 . + 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * The client entry's userinfo pointer must be always valid. + Otherwise the [] 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 [] 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 [] 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 [] 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Minor typo fixes on command reply handling on server. + +Tue Nov 28 11:05:39 EET 2000 Pekka Riikonen + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Changed client librarys channel->clients table to SilcList and + changed code accordingly. + +Thu Nov 2 16:28:01 EET 2000 Pekka Riikonen + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Added GMP 3.1 into math library. + +Sun Aug 20 21:27:26 EEST 2000 Pekka Riikonen + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Added SOCKS4 and SOCKS5 support to SILC client. SOCKS5 + was tested. SOCKS4 was not but should work anyway. diff --cc apps/silcd/command.c index 3b3a8b5c,b9a0cc63..b4d5bcee --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@@ -956,3789 -429,183 +956,3789 @@@ silc_server_command_whois_process(SilcS 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) { + 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>", - server->config->admin_info->location, - server->config->admin_info->server_type, - server->config->admin_info->admin_name, - server->config->admin_info->admin_email); ++ 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); + - if (server->config && server->config->motd && - server->config->motd->motd_file) { ++ if (server->config && server->config->server_info && ++ server->config->server_info->motd_file) { + /* Send motd */ - motd = silc_file_readfile(server->config->motd->motd_file, &motd_len); ++ 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) { + 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_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; diff --cc apps/silcd/packet_receive.c index d1f6db8a,00000000..2f3aa2f7 mode 100644,000000..100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@@ -1,2605 -1,0 +1,2605 @@@ +/* + + packet_receive.c + + Author: Pekka Riikonen + + 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) +{ - SilcServerConfigSectionClientConnection *client = NULL; ++ 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_conn(server->config, ++ 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); +} diff --cc apps/silcd/packet_send.c index 2c8786c3,00000000..d2d21517 mode 100644,000000..100644 --- a/apps/silcd/packet_send.c +++ b/apps/silcd/packet_send.c @@@ -1,1890 -1,0 +1,1891 @@@ +/* + + packet_send.c + + Author: Pekka Riikonen + + 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) +{ - char *motd; ++ char *motd, *motd_file = NULL; + uint32 motd_len; + - if (server->config && server->config->motd && - server->config->motd->motd_file) { ++ if (server->config) ++ motd_file = server->config->server_info->motd_file; + - motd = silc_file_readfile(server->config->motd->motd_file, &motd_len); ++ 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); + } +} diff --cc apps/silcd/protocol.c index d5a287d5,60d49170..a7a1b707 --- a/apps/silcd/protocol.c +++ b/apps/silcd/protocol.c @@@ -906,7 -477,16 +906,7 @@@ SILC_TASK_CALLBACK(silc_server_protocol /* 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) { @@@ -968,7 -575,16 +968,7 @@@ /* 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) { @@@ -1030,11 -673,20 +1030,11 @@@ /* 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; diff --cc apps/silcd/server.c index d033284d,636b428f..f0ed13f8 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@@ -113,46 -123,21 +113,42 @@@ int silc_server_init(SilcServer server { 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(); @@@ -163,48 -148,64 +159,47 @@@ 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 @@@ -306,43 -293,8 +301,43 @@@ /* 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")); @@@ -356,140 -312,6 +351,139 @@@ return FALSE; } +/* 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; + - if (!server->config->identity || !server->config->identity->user || - !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->identity->user; - group=server->config->identity->group; ++ 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. */ @@@ -509,150 -329,17 +503,150 @@@ void silc_server_stop(SilcServer server 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); } +/* 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->listen_port->local_ip, ++ 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 @@@ -661,8 -348,8 +655,8 @@@ 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)")); @@@ -726,10 -525,8 +720,10 @@@ SILC_TASK_CALLBACK(silc_server_connect_ 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")); @@@ -909,194 -677,83 +903,194 @@@ SILC_TASK_CALLBACK(silc_server_connect_ 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; } @@@ -1357,84 -924,41 +1351,85 @@@ SILC_TASK_CALLBACK(silc_server_accept_n 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: diff --cc apps/silcd/server_backup.c index 4bcf0b11,00000000..6b3d876a mode 100644,000000..100644 --- a/apps/silcd/server_backup.c +++ b/apps/silcd/server_backup.c @@@ -1,1240 -1,0 +1,1240 @@@ +/* + + server_backup.c + + Author: Pekka Riikonen + + 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 */ - sock = silc_net_create_connection(server->config->listen_port->local_ip, ++ 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: + + + + = the protocol opcode + = 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. */ - SilcServerConfigSectionServerConnection *primary; ++ 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); +} diff --cc apps/silcd/serverconfig.c index 5a8f731d,2f617c26..e51039d6 --- a/apps/silcd/serverconfig.c +++ b/apps/silcd/serverconfig.c @@@ -2,15 -2,15 +2,15 @@@ serverconfig.c -- Author: Pekka Riikonen ++ Author: Johnny Mnemonic -- 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 @@@ -22,1319 -29,1151 +22,1141 @@@ #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. */ - - - Format: - - +: - - - - Format: - - +: - - - - Format: - - +: - - - - This section is used to set the server informations. - - Format: - - +::: - - - - This section is used to set the server's administrative information. - - Format: - - +::: - - - - This section is used to set ports the server is listenning. - - Format: - - +:: - - - - 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:: - +errorlogfile:: - - - - This section is used to define connection classes. These can be - used to optimize the server and the connections. - - Format: - - +::: - - - - This section is used to define client authentications. - - Format: - - +:::: - - - - This section is used to define the server's administration - authentications. - - Format: - - +:::: - - ++#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: - - +::::: - - - - 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: - - +::::: - - - - This section is used to deny specific connections to your server. This - can be used to deny both clients and servers. - - Format: - - +: