Started implementing protocol version 1.1 and narrowing down
[silc.git] / apps / silcd / packet_receive.c
index 65aba7318907e6c024dc0769da3c76a1570b54b2..f0c3616da003fd8061cd92cc3000ec7032e41c8a 100644 (file)
@@ -2,9 +2,9 @@
 
   packet_receive.c
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2001 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
@@ -40,15 +40,16 @@ void silc_server_notify(SilcServer server,
   SilcChannelID *channel_id = NULL, *channel_id2;
   SilcClientID *client_id, *client_id2;
   SilcServerID *server_id;
-  SilcChannelEntry channel;
-  SilcClientEntry client;
-  SilcServerEntry server_entry;
+  SilcIdType id_type;
+  SilcChannelEntry channel = NULL;
+  SilcClientEntry client = NULL, client2 = NULL;
+  SilcServerEntry server_entry = NULL;
   SilcChannelClientEntry chl;
   SilcIDCacheEntry cache;
   SilcHashTableList htl;
-  uint32 mode;
+  SilcUInt32 mode;
   unsigned char *tmp;
-  uint32 tmp_len;
+  SilcUInt32 tmp_len;
   bool local;
 
   SILC_LOG_DEBUG(("Start"));
@@ -72,7 +73,7 @@ void silc_server_notify(SilcServer server,
     if (dst_sock)
       /* Relay the packet */
       silc_server_relay_packet(server, dst_sock, idata->send_key,
-                              idata->hmac_receive, idata->psn_send++,
+                              idata->hmac_send, idata->psn_send++,
                               packet, TRUE);
   }
 
@@ -138,7 +139,7 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
     if (!tmp)
       goto out;
-    channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+    channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!channel_id)
       goto out;
 
@@ -159,7 +160,7 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
-    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!client_id)
       goto out;
 
@@ -197,7 +198,7 @@ void silc_server_notify(SilcServer server,
       break;
 
     /* Do not add client to channel if it is there already */
-    if (silc_server_client_on_channel(client, channel)) {
+    if (silc_server_client_on_channel(client, channel, NULL)) {
       SILC_LOG_DEBUG(("Client already on channel"));
       break;
     }
@@ -263,7 +264,7 @@ void silc_server_notify(SilcServer server,
       silc_free(channel_id);
       goto out;
     }
-    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!client_id) {
       silc_free(channel_id);
       goto out;
@@ -284,7 +285,7 @@ void silc_server_notify(SilcServer server,
     silc_free(client_id);
 
     /* Check if on channel */
-    if (!silc_server_client_on_channel(client, channel))
+    if (!silc_server_client_on_channel(client, channel, NULL))
       break;
 
     /* Send the leave notify to channel */
@@ -306,7 +307,7 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
-    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!client_id)
       goto out;
 
@@ -349,6 +350,34 @@ void silc_server_notify(SilcServer server,
 
     SILC_LOG_DEBUG(("TOPIC SET 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, NULL);
+    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 the topic */
+    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+    if (!tmp) {
+      silc_free(channel_id);
+      goto out;
+    }
+
     if (!channel_id) {
       channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
                                  packet->dst_id_type);
@@ -368,13 +397,19 @@ void silc_server_notify(SilcServer server,
       }
     }
 
-    /* Get the topic */
-    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
-    if (!tmp) {
-      silc_free(channel_id);
+    if (channel->topic && !strcmp(channel->topic, tmp))
+      goto out;
+
+    /* Get user's channel entry and check that topic set is allowed. */
+    if (!silc_server_client_on_channel(client, channel, &chl))
+      goto out;
+    if (chl->mode == SILC_CHANNEL_UMODE_NONE && 
+       channel->mode & SILC_CHANNEL_MODE_TOPIC) {
+      SILC_LOG_DEBUG(("Topic change is not allowed"));
       goto out;
     }
 
+    /* Change the topic */
     silc_free(channel->topic);
     channel->topic = strdup(tmp);
 
@@ -391,6 +426,8 @@ void silc_server_notify(SilcServer server,
        * Distribute the notify to local clients on the channel
        */
       unsigned char *id, *id2;
+      char *nickname;
+      SilcUInt32 nickname_len;
 
       SILC_LOG_DEBUG(("NICK CHANGE notify"));
       
@@ -398,7 +435,7 @@ void silc_server_notify(SilcServer server,
       id = silc_argument_get_arg_type(args, 1, &tmp_len);
       if (!id)
        goto out;
-      client_id = silc_id_payload_parse_id(id, tmp_len);
+      client_id = silc_id_payload_parse_id(id, tmp_len, NULL);
       if (!client_id)
        goto out;
       
@@ -406,7 +443,7 @@ void silc_server_notify(SilcServer server,
       id2 = silc_argument_get_arg_type(args, 2, &tmp_len);
       if (!id2)
        goto out;
-      client_id2 = silc_id_payload_parse_id(id2, tmp_len);
+      client_id2 = silc_id_payload_parse_id(id2, tmp_len, NULL);
       if (!client_id2)
        goto out;
       
@@ -415,26 +452,24 @@ void silc_server_notify(SilcServer server,
       SILC_LOG_DEBUG(("New Client ID id(%s)", 
                      silc_id_render(client_id2, SILC_ID_CLIENT)));
 
+      /* From protocol version 1.1 we also get the new nickname */
+      nickname = silc_argument_get_arg_type(args, 3, &nickname_len);;
+
       /* Replace the Client ID */
       client = silc_idlist_replace_client_id(server->global_list, client_id,
-                                            client_id2);
+                                            client_id2, nickname);
       if (!client)
        client = silc_idlist_replace_client_id(server->local_list, client_id, 
-                                              client_id2);
+                                              client_id2, nickname);
 
       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_server_send_notify_on_channels(server, NULL, client,
+                                           SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
+                                           id, tmp_len, id2, tmp_len,
+                                           nickname, nickname ?
+                                           nickname_len : 0);
       }
 
       silc_free(client_id);
@@ -450,6 +485,29 @@ void silc_server_notify(SilcServer server,
     
     SILC_LOG_DEBUG(("CMODE 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, &id_type);
+    if (!client_id)
+      goto out;
+
+    /* Get client entry */
+    if (id_type == SILC_ID_CLIENT) {
+      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);
+    }
+
     if (!channel_id) {
       channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
                                  packet->dst_id_type);
@@ -468,20 +526,28 @@ void silc_server_notify(SilcServer server,
        goto out;
       }
     }
+    silc_free(channel_id);
 
     /* Get the mode */
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
-    if (!tmp) {
-      silc_free(channel_id);
+    if (!tmp)
       goto out;
-    }
-
     SILC_GET32_MSB(mode, tmp);
 
     /* Check if mode changed */
     if (channel->mode == mode)
       break;
 
+    /* Get user's channel entry and check that mode change is allowed */
+    if (client) {
+      if (!silc_server_client_on_channel(client, channel, &chl))
+       goto out;
+      if (!silc_server_check_cmode_rights(server, channel, chl, mode)) {
+       SILC_LOG_DEBUG(("CMODE change is not allowed"));
+       goto out;
+      }
+    }
+
     /* Send the same notify to the channel */
     silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
                                       FALSE, packet->buffer->data, 
@@ -504,7 +570,6 @@ void silc_server_notify(SilcServer server,
 
     /* Change mode */
     channel->mode = mode;
-    silc_free(channel_id);
 
     /* Get the hmac */
     tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
@@ -545,6 +610,29 @@ void silc_server_notify(SilcServer server,
       
       SILC_LOG_DEBUG(("CUMODE 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, &id_type);
+      if (!client_id)
+       goto out;
+
+      /* Get client entry */
+      if (id_type == SILC_ID_CLIENT) {
+       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);
+      }
+
       if (!channel_id) {
        channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
                                    packet->dst_id_type);
@@ -577,23 +665,47 @@ void silc_server_notify(SilcServer server,
       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
       if (!tmp)
        goto out;
-      client_id = silc_id_payload_parse_id(tmp, tmp_len);
+      client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
       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) {
+      client2 = silc_idlist_find_client_by_id(server->global_list, 
+                                             client_id, TRUE, NULL);
+      if (!client2) {
+       client2 = silc_idlist_find_client_by_id(server->local_list, 
+                                               client_id, TRUE, NULL);
+       if (!client2) {
          silc_free(client_id);
          goto out;
        }
       }
       silc_free(client_id);
 
+      if (client) {
+       /* Check that sender is on channel */
+       if (!silc_server_client_on_channel(client, channel, &chl))
+         goto out;
+       
+       if (client != client2) {
+         /* Sender must be operator */
+         if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+           SILC_LOG_DEBUG(("CUMODE change is not allowed"));
+           goto out;
+         }
+
+         /* Check that target is on channel */
+         if (!silc_server_client_on_channel(client2, channel, &chl))
+           goto out;
+
+         /* If target is founder mode change is not allowed. */
+         if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+           SILC_LOG_DEBUG(("CUMODE change is not allowed"));
+           goto out;
+         }
+       }
+      }
+
       /* Get entry to the channel user list */
       silc_hash_table_list(channel->user_list, &htl);
       while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
@@ -614,10 +726,10 @@ void silc_server_notify(SilcServer server,
 
          mode &= ~SILC_CHANNEL_UMODE_CHANFO;
          silc_server_send_notify_cumode(server, sock, FALSE, channel, mode,
-                                        client->id, SILC_ID_CLIENT,
-                                        client->id);
+                                        client2->id, SILC_ID_CLIENT,
+                                        client2->id);
          
-         idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+         idp = silc_id_payload_encode(client2->id, SILC_ID_CLIENT);
          SILC_PUT32_MSB(mode, cumode);
          silc_server_send_notify_to_channel(server, sock, channel, FALSE, 
                                             SILC_NOTIFY_TYPE_CUMODE_CHANGE,
@@ -636,7 +748,7 @@ void silc_server_notify(SilcServer server,
          }
        }
        
-       if (chl->client == client) {
+       if (chl->client == client2) {
          if (chl->mode == mode) {
            notify_sent = TRUE;
            break;
@@ -676,7 +788,7 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
-    channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+    channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!channel_id)
       goto out;
 
@@ -693,8 +805,38 @@ void silc_server_notify(SilcServer server,
     }
     silc_free(channel_id);
 
-    /* Get the added invite */
+    /* Get client ID */
     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+    if (!tmp)
+      goto out;
+    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+    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 user's channel entry and check that inviting is allowed. */
+    if (!silc_server_client_on_channel(client, channel, &chl))
+      goto out;
+    if (chl->mode == SILC_CHANNEL_UMODE_NONE && 
+       channel->mode & SILC_CHANNEL_MODE_INVITE) {
+      SILC_LOG_DEBUG(("Inviting is not allowed"));
+      goto out;
+    }
+
+    /* Get the added invite */
+    tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
     if (tmp) {
       if (!channel->invite_list)
        channel->invite_list = silc_calloc(tmp_len + 2, 
@@ -713,7 +855,7 @@ void silc_server_notify(SilcServer server,
     }
 
     /* Get the deleted invite */
-    tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
+    tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
     if (tmp && channel->invite_list) {
       char *start, *end, *n;
       
@@ -752,7 +894,7 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
-    channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+    channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!channel_id)
       goto out;
 
@@ -777,7 +919,7 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
     if (!tmp)
       goto out;
-    channel_id2 = silc_id_payload_parse_id(tmp, tmp_len);
+    channel_id2 = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!channel_id2)
       goto out;
 
@@ -850,7 +992,7 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
-    server_id = silc_id_payload_parse_id(tmp, tmp_len);
+    server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!server_id)
       goto out;
 
@@ -876,7 +1018,7 @@ void silc_server_notify(SilcServer server,
            tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
            if (!tmp)
              continue;
-           client_id = silc_id_payload_parse_id(tmp, tmp_len);
+           client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
            if (!client_id)
              continue;
 
@@ -961,7 +1103,7 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
-    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!client_id)
       goto out;
 
@@ -976,6 +1118,42 @@ void silc_server_notify(SilcServer server,
        goto out;
       }
     }
+    silc_free(client_id);
+
+    /* If target is founder they cannot be kicked */
+    if (!silc_server_client_on_channel(client, channel, &chl))
+      goto out;
+    if (chl->mode & SILC_CHANNEL_UMODE_CHANFO)
+      goto out;
+    
+    /* From protocol version 1.1 we get the kicker's ID as well. */
+    tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+    if (tmp) {
+      client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+      if (!client_id)
+       goto out;
+
+      /* If the the client is not in local list we check global list */
+      client2 = silc_idlist_find_client_by_id(server->global_list, 
+                                             client_id, TRUE, NULL);
+      if (!client2) {
+       client2 = silc_idlist_find_client_by_id(server->local_list, 
+                                               client_id, TRUE, NULL);
+       if (!client2) {
+         silc_free(client_id);
+         goto out;
+       }
+      }
+      silc_free(client_id);
+
+      /* Kicker must be operator on channel */
+      if (!silc_server_client_on_channel(client2, channel, &chl))
+       goto out;
+      if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+       SILC_LOG_DEBUG(("Kicking is not allowed"));
+       goto out;
+      }
+    }
 
     /* Send to channel */
     silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
@@ -992,8 +1170,8 @@ void silc_server_notify(SilcServer server,
       /* 
        * Distribute the notify to local clients on channels
        */
-      unsigned char *id;
-      uint32 id_len;
+      unsigned char *id, *comment;
+      SilcUInt32 id_len, comment_len;
     
       SILC_LOG_DEBUG(("KILLED notify"));
       
@@ -1001,7 +1179,7 @@ void silc_server_notify(SilcServer server,
       id = silc_argument_get_arg_type(args, 1, &id_len);
       if (!id)
        goto out;
-      client_id = silc_id_payload_parse_id(id, id_len);
+      client_id = silc_id_payload_parse_id(id, id_len, NULL);
       if (!client_id)
        goto out;
 
@@ -1028,16 +1206,42 @@ void silc_server_notify(SilcServer server,
       }
 
       /* Get comment */
-      tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
-      if (tmp_len > 128)
-       tmp = NULL;
+      comment = silc_argument_get_arg_type(args, 2, &comment_len);
+      if (comment_len > 128)
+       comment_len = 127;
+
+      /* From protocol version 1.1 we get the killer's ID as well. */
+      tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+      if (tmp) {
+       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+       if (!client_id)
+         goto out;
+
+       /* If the the client is not in local list we check global list */
+       client2 = silc_idlist_find_client_by_id(server->global_list, 
+                                               client_id, TRUE, NULL);
+       if (!client2) {
+         client2 = silc_idlist_find_client_by_id(server->local_list, 
+                                                 client_id, TRUE, NULL);
+         if (!client2) {
+           silc_free(client_id);
+           goto out;
+         }
+       }
+       silc_free(client_id);
+
+       /* Killer must be router operator */
+       if (!(client2->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+         SILC_LOG_DEBUG(("Killing is not allowed"));
+         goto out;
+       }
+      }
 
       /* 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, 
+                                         SILC_NOTIFY_TYPE_KILLED, 3,
+                                         id, id_len, comment, comment_len,
                                          tmp, tmp_len);
 
       /* Remove the client from all channels */
@@ -1058,7 +1262,7 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
-    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!client_id)
       goto out;
 
@@ -1081,30 +1285,13 @@ void silc_server_notify(SilcServer server,
       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);
+    /* Check that mode changing is allowed. */
+    if (!silc_server_check_umode_rights(server, client, mode)) {
+      SILC_LOG_DEBUG(("UMODE change is not allowed"));
+      goto out;
+    }
 
-    /* Save the mode */
+    /* Change the mode */
     client->mode = mode;
 
     break;
@@ -1120,7 +1307,7 @@ do {                                              \
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
-    channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+    channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!channel_id)
       goto out;
     
@@ -1193,7 +1380,7 @@ void silc_server_notify_list(SilcServer server,
 {
   SilcPacketContext *new;
   SilcBuffer buffer;
-  uint16 len;
+  SilcUInt16 len;
 
   SILC_LOG_DEBUG(("Processing Notify List"));
 
@@ -1379,19 +1566,23 @@ void silc_server_command_reply(SilcServer server,
 
   if (packet->dst_id_type == SILC_ID_CLIENT && client && id) {
     /* Relay the packet to the client */
+    const SilcBufferStruct p;
     
     dst_sock = (SilcSocketConnection)client->connection;
+    idata = (SilcIDListData)client;
+    
     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;
+    if (!silc_packet_send_prepare(dst_sock, 0, 0, buffer->len,
+                                  idata->hmac_send, (const SilcBuffer)&p)) {
+      SILC_LOG_ERROR(("Cannot send packet"));
+      return;
+    }
+    silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
     
     /* Encrypt packet */
     silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
-                       dst_sock->outbuf, buffer->len);
+                       (SilcBuffer)&p, buffer->len);
     
     /* Send the packet */
     silc_server_packet_send_real(server, dst_sock, TRUE);
@@ -1409,8 +1600,9 @@ void silc_server_channel_message(SilcServer server,
 {
   SilcChannelEntry channel = NULL;
   SilcChannelID *id = NULL;
-  void *sender = NULL;
-  void *sender_entry = NULL;
+  void *sender_id = NULL;
+  SilcClientEntry sender_entry = NULL;
+  SilcChannelClientEntry chl;
   bool local = TRUE;
 
   SILC_LOG_DEBUG(("Processing channel message"));
@@ -1436,27 +1628,41 @@ void silc_server_channel_message(SilcServer server,
 
   /* 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)
+  sender_id = silc_id_str2id(packet->src_id, packet->src_id_len, 
+                            packet->src_id_type);
+  if (!sender_id)
     goto out;
   if (packet->src_id_type == SILC_ID_CLIENT) {
     sender_entry = silc_idlist_find_client_by_id(server->local_list, 
-                                                sender, TRUE, NULL);
+                                                sender_id, TRUE, NULL);
     if (!sender_entry) {
       local = FALSE;
       sender_entry = silc_idlist_find_client_by_id(server->global_list, 
-                                                  sender, TRUE, NULL);
+                                                  sender_id, TRUE, NULL);
     }
     if (!sender_entry || !silc_server_client_on_channel(sender_entry, 
-                                                       channel)) {
+                                                       channel, &chl)) {
       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 channel is moderated check that client is allowed to send
+       messages. */
+    if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && !chl->mode) {
+      SILC_LOG_DEBUG(("Channel is silenced from normal users"));
+      goto out;
+    }
+    if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS && 
+       chl->mode & SILC_CHANNEL_UMODE_CHANOP &&
+       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+      SILC_LOG_DEBUG(("Channel is silenced from operators"));
+      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. When the client is local to us it means that we've routed
+       this packet to network, and now someone is routing it back to us. */
     if (server->server_type == SILC_ROUTER &&
        sock->type == SILC_SOCKET_TYPE_ROUTER && local) {
       SILC_LOG_DEBUG(("Channel message rerouted to the sender, drop it"));
@@ -1466,16 +1672,14 @@ void silc_server_channel_message(SilcServer server,
 
   /* 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,
+  silc_server_packet_relay_to_channel(server, sock, channel, sender_id,
                                      packet->src_id_type, sender_entry,
                                      packet->buffer->data,
                                      packet->buffer->len, FALSE);
 
  out:
-  if (sender)
-    silc_free(sender);
-  if (id)
-    silc_free(id);
+  silc_free(sender_id);
+  silc_free(id);
 }
 
 /* Received channel key packet. We distribute the key to all of our locally
@@ -1523,8 +1727,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   SilcBuffer reply;
   SilcIDListData idata;
   char *username = NULL, *realname = NULL, *id_string;
-  uint16 username_len;
-  uint32 id_len;
+  SilcUInt16 username_len;
+  SilcUInt32 id_len;
   int ret;
   char *hostname, *nickname;
   int nickfail = 0;
@@ -1540,9 +1744,9 @@ SilcClientEntry silc_server_new_client(SilcServer server,
 
   /* 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_LOG_INFO(("Unauthenticated client attempted to register to network"));
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
-                                  "Unknown client");
+                                  "You have not been authenticated");
     return NULL;
   }
 
@@ -1555,6 +1759,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   if (ret == -1) {
     silc_free(username);
     silc_free(realname);
+    SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
+                   "connection", sock->hostname, sock->ip));
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                   "Incomplete client information");
     return NULL;
@@ -1563,6 +1769,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   if (!username) {
     silc_free(username);
     silc_free(realname);
+    SILC_LOG_ERROR(("Client %s (%s) did not send its username, closing "
+                   "connection", sock->hostname, sock->ip));
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                   "Incomplete client information");
     return NULL;
@@ -1596,6 +1804,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
       silc_free(username);
       silc_free(hostname);
       silc_free(realname);
+      SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
+                     "connection", sock->hostname, sock->ip));
       silc_server_disconnect_remote(server, sock, 
                                    "Server closed connection: "
                                    "Incomplete client information");
@@ -1614,6 +1824,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
       silc_free(hostname);
       silc_free(phostname);
       silc_free(realname);
+      SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
+                     "connection", sock->hostname, sock->ip));
       silc_server_disconnect_remote(server, sock, 
                                    "Server closed connection: "
                                    "Incomplete client information");
@@ -1704,8 +1916,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                           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));
+                          server->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 "
@@ -1772,7 +1983,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   SilcServerID *server_id;
   SilcIDListData idata;
   unsigned char *server_name, *id_string;
-  uint16 id_len, name_len;
+  SilcUInt16 id_len, name_len;
   int ret;
   bool local = TRUE;
 
@@ -1788,7 +1999,15 @@ SilcServerEntry silc_server_new_server(SilcServer 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);
+    if (!silc_idcache_del_by_context(server->global_list->servers, 
+                                    new_server)) {
+      SILC_LOG_INFO(("Unauthenticated %s attempted to register to "
+                    "network", (sock->type == SILC_SOCKET_TYPE_SERVER ?
+                                "server" : "router")));
+      silc_server_disconnect_remote(server, sock, "Server closed connection: "
+                                   "You have not been authenticated");
+      return NULL;
+    }
     local = FALSE;
   }
 
@@ -1824,6 +2043,16 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   }
   silc_free(id_string);
 
+  /* Check for valid server ID */
+  if (!silc_id_is_valid_server_id(server, server_id, sock)) {
+    SILC_LOG_INFO(("Invalid server ID sent by %s (%s)",
+                  sock->ip, sock->hostname));
+    silc_server_disconnect_remote(server, sock, "Server closed connection: "
+                                 "Your Server ID is not valid");
+    silc_free(server_name);
+    return NULL;
+  }
+
   /* Check that we do not have this ID already */
   server_entry = silc_idlist_find_server_by_id(server->local_list, 
                                               server_id, TRUE, NULL);
@@ -2110,7 +2339,7 @@ void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
 {
   SilcPacketContext *new_id;
   SilcBuffer idp;
-  uint16 id_len;
+  SilcUInt16 id_len;
 
   SILC_LOG_DEBUG(("Processing New ID List"));
 
@@ -2182,10 +2411,10 @@ void silc_server_new_channel(SilcServer server,
   SilcChannelPayload payload;
   SilcChannelID *channel_id;
   char *channel_name;
-  uint32 name_len;
+  SilcUInt32 name_len;
   unsigned char *id;
-  uint32 id_len;
-  uint32 mode;
+  SilcUInt32 id_len;
+  SilcUInt32 mode;
   SilcServerEntry server_entry;
   SilcChannelEntry channel;
 
@@ -2388,7 +2617,7 @@ void silc_server_new_channel_list(SilcServer server,
 {
   SilcPacketContext *new;
   SilcBuffer buffer;
-  uint16 len1, len2;
+  SilcUInt16 len1, len2;
 
   SILC_LOG_DEBUG(("Processing New Channel List"));
 
@@ -2500,7 +2729,7 @@ void silc_server_connection_auth_request(SilcServer server,
                                         SilcPacketContext *packet)
 {
   SilcServerConfigClient *client = NULL;
-  uint16 conn_type;
+  SilcUInt16 conn_type;
   int ret;
   SilcAuthMethod auth_meth = SILC_AUTH_NONE;
 
@@ -2527,11 +2756,11 @@ void silc_server_connection_auth_request(SilcServer server,
     client = silc_server_config_find_client(server, sock->hostname);
   if (client) {
     if (client->passphrase) {
-      if (client->publickey && !server->config->prefer_passphrase_auth)
+      if (client->publickeys && !server->config->prefer_passphrase_auth)
        auth_meth = SILC_AUTH_PUBLIC_KEY;
       else
        auth_meth = SILC_AUTH_PASSWORD;
-    } else if (client->publickey)
+    } else if (client->publickeys)
       auth_meth = SILC_AUTH_PUBLIC_KEY;
   }