Fixed packet relaying.
[silc.git] / apps / silcd / packet_receive.c
index f09bccb6dc4d7910c847e52d2d79001dc20ec545..5d21089e91d35b03ade0f5acc148bf001c9627ca 100644 (file)
@@ -40,15 +40,17 @@ 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"));
 
@@ -71,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);
   }
 
@@ -137,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;
 
@@ -158,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;
 
@@ -180,7 +182,7 @@ void silc_server_notify(SilcServer server,
        client = 
          silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
                                 silc_id_dup(client_id, SILC_ID_CLIENT), 
-                                sock->user_data, NULL);
+                                sock->user_data, NULL, 0);
        if (!client) {
          SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
          silc_free(client_id);
@@ -196,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;
     }
@@ -211,6 +213,8 @@ void silc_server_notify(SilcServer server,
       /* 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));
@@ -225,6 +229,7 @@ void silc_server_notify(SilcServer server,
     silc_hash_table_add(channel->user_list, client, chl);
     silc_hash_table_add(client->channels, channel, chl);
     silc_free(client_id);
+    channel->user_count++;
 
     break;
 
@@ -259,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;
@@ -280,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 */
@@ -302,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;
 
@@ -324,14 +329,18 @@ void silc_server_notify(SilcServer server,
     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;
-    server->stat.clients--;
-    if (server->server_type == SILC_ROUTER)
-      server->stat.cell_clients--;
     break;
 
   case SILC_NOTIFY_TYPE_TOPIC_SET:
@@ -341,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);
@@ -360,17 +397,21 @@ 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;
     }
 
-    if (channel->topic)
-      silc_free(channel->topic);
-    channel->topic = silc_calloc(tmp_len + 1, sizeof(*channel->topic));
-    memcpy(channel->topic, tmp, tmp_len);
+    /* Change the topic */
+    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, 
@@ -392,7 +433,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;
       
@@ -400,7 +441,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;
       
@@ -444,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);
@@ -462,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, 
@@ -498,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);
@@ -520,6 +591,13 @@ void silc_server_notify(SilcServer server,
       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:
@@ -532,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);
@@ -564,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)) {
@@ -601,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,
@@ -618,16 +743,19 @@ void silc_server_notify(SilcServer server,
          if (chl2) {
            chl2->mode = mode;
            silc_free(channel_id);
+           silc_hash_table_list_reset(&htl);
            goto out;
          }
        }
        
-       if (chl->client == client) {
+       if (chl->client == client2) {
          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))
@@ -636,6 +764,7 @@ void silc_server_notify(SilcServer server,
          chl2 = chl;
        }
       }
+      silc_hash_table_list_reset(&htl);
       
       /* Send the same notify to the channel */
       if (!notify_sent)
@@ -659,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;
 
@@ -676,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, 
@@ -696,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;
       
@@ -735,15 +894,15 @@ 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;
 
     /* Get the channel entry */
-    channel = silc_idlist_find_channel_by_id(server->global_list, 
+    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 = silc_idlist_find_channel_by_id(server->global_list, 
                                               channel_id, NULL);
       if (!channel) {
        silc_free(channel_id);
@@ -760,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;
 
@@ -770,9 +929,9 @@ void silc_server_notify(SilcServer server,
                    silc_id_render(channel_id2, SILC_ID_CHANNEL)));
 
     /* Replace the Channel ID */
-    if (!silc_idlist_replace_channel_id(server->global_list, channel_id,
+    if (!silc_idlist_replace_channel_id(server->local_list, channel_id,
                                        channel_id2))
-      if (!silc_idlist_replace_channel_id(server->local_list, channel_id,
+      if (!silc_idlist_replace_channel_id(server->global_list, channel_id,
                                          channel_id2)) {
        silc_free(channel_id2);
        channel_id2 = NULL;
@@ -780,7 +939,14 @@ void silc_server_notify(SilcServer server,
 
     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);
@@ -800,6 +966,15 @@ void silc_server_notify(SilcServer server,
                                     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);
@@ -817,16 +992,18 @@ 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;
 
     /* 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
@@ -841,16 +1018,18 @@ 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;
 
            /* 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;
@@ -858,15 +1037,20 @@ void silc_server_notify(SilcServer server,
            }
            silc_free(client_id);
 
-           /* Remove the client from all channels. */
-           silc_server_remove_from_channels(server, NULL, client, 
-                                            TRUE, NULL, FALSE);
-           
-           client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
-           cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
+           /* 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);
          }
        }
 
@@ -881,8 +1065,8 @@ void silc_server_notify(SilcServer server,
     silc_server_remove_clients_by_server(server, server_entry, TRUE);
 
     /* Remove the server entry */
-    if (!silc_idlist_del_server(server->global_list, server_entry))
-      silc_idlist_del_server(server->local_list, server_entry);
+    silc_idlist_del_server(local ? server->local_list :
+                          server->global_list, server_entry);
 
     /* XXX update statistics */
 
@@ -919,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;
 
@@ -934,6 +1118,43 @@ 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;
+    
+    /* Get kicker. In protocol version 1.0 this is not mandatory argument
+       so we check it only if it is provided. */
+    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, 
@@ -951,7 +1172,7 @@ void silc_server_notify(SilcServer server,
        * Distribute the notify to local clients on channels
        */
       unsigned char *id;
-      uint32 id_len;
+      SilcUInt32 id_len;
     
       SILC_LOG_DEBUG(("KILLED notify"));
       
@@ -959,7 +1180,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;
 
@@ -1011,12 +1232,12 @@ void silc_server_notify(SilcServer server,
      */
 
     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);
+    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!client_id)
       goto out;
 
@@ -1037,9 +1258,16 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
     if (!tmp)
       goto out;
+    SILC_GET32_MSB(mode, tmp);
 
-    /* Save the mode */
-    SILC_GET32_MSB(client->mode, tmp);
+    /* 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;
+    }
+
+    /* Change the mode */
+    client->mode = mode;
 
     break;
 
@@ -1054,7 +1282,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;
     
@@ -1091,7 +1319,7 @@ void silc_server_notify(SilcServer server,
     if (tmp && channel->ban_list) {
       char *start, *end, *n;
       
-      if (!strcmp(channel->ban_list, tmp)) {
+      if (!strncmp(channel->ban_list, tmp, strlen(channel->ban_list) - 1)) {
        silc_free(channel->ban_list);
        channel->ban_list = NULL;
       } else {
@@ -1107,7 +1335,6 @@ void silc_server_notify(SilcServer server,
        }
       }
     }
-
     break;
 
     /* Ignore rest of the notify types for now */
@@ -1128,7 +1355,7 @@ void silc_server_notify_list(SilcServer server,
 {
   SilcPacketContext *new;
   SilcBuffer buffer;
-  uint16 len;
+  SilcUInt16 len;
 
   SILC_LOG_DEBUG(("Processing Notify List"));
 
@@ -1206,9 +1433,22 @@ void silc_server_private_message(SilcServer server,
     if (!idp)
       return;
 
-    silc_server_send_command_reply(server, sock, SILC_COMMAND_IDENTIFY,
-                                  SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0, 1,
-                                  2, idp, idp->len);
+    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;
   }
@@ -1290,7 +1530,7 @@ void silc_server_command_reply(SilcServer server,
 
   if (packet->dst_id_type == SILC_ID_SERVER) {
     /* For now this must be for us */
-    if (memcmp(packet->dst_id, server->id_string, packet->dst_id_len)) {
+    if (memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
       SILC_LOG_ERROR(("Cannot process command reply to unknown server"));
       return;
     }
@@ -1301,19 +1541,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);
@@ -1331,8 +1575,8 @@ 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;
   bool local = TRUE;
 
   SILC_LOG_DEBUG(("Processing channel message"));
@@ -1358,27 +1602,28 @@ 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, NULL)) {
       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 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"));
@@ -1388,16 +1633,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
@@ -1444,9 +1687,9 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   SilcClientID *client_id;
   SilcBuffer reply;
   SilcIDListData idata;
-  SilcIDCacheEntry id_cache = NULL;
   char *username = NULL, *realname = NULL, *id_string;
-  uint32 id_len;
+  SilcUInt16 username_len;
+  SilcUInt32 id_len;
   int ret;
   char *hostname, *nickname;
   int nickfail = 0;
@@ -1462,22 +1705,23 @@ 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;
   }
 
   /* Parse incoming packet */
   ret = silc_buffer_unformat(buffer,
-                            SILC_STR_UI16_STRING_ALLOC(&username),
+                            SILC_STR_UI16_NSTRING_ALLOC(&username, 
+                                                        &username_len),
                             SILC_STR_UI16_STRING_ALLOC(&realname),
                             SILC_STR_END);
   if (ret == -1) {
-    if (username)
-      silc_free(username);
-    if (realname)
-      silc_free(realname);
+    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;
@@ -1485,17 +1729,24 @@ SilcClientEntry silc_server_new_client(SilcServer server,
 
   if (!username) {
     silc_free(username);
-    if (realname)
-      silc_free(realname);
+    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;
   }
 
-  if (strlen(username) > 128)
-    username[127] = '\0';
+  if (username_len > 128)
+    username[128] = '\0';
 
-  nickname = strdup(username);
+  /* 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
@@ -1507,15 +1758,15 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     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);
+    hostname = silc_memdup(username + tlen + 1, strlen(username) - tlen - 1);
 
     if (strcmp(sock->hostname, sock->ip) && 
        strcmp(sock->hostname, hostname)) {
       silc_free(username);
       silc_free(hostname);
-      if (realname)
-       silc_free(realname);
+      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");
@@ -1532,18 +1783,17 @@ SilcClientEntry silc_server_new_client(SilcServer server,
        phostname && strcmp(phostname, hostname)) {
       silc_free(username);
       silc_free(hostname);
-      if (phostname)
-       silc_free(phostname);
-      if (realname)
-       silc_free(realname);
+      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");
       return NULL;
     }
     
-    if (phostname)
-      silc_free(phostname);
+    silc_free(phostname);
   } else {
     /* The hostname is not present, add it. */
     char *newusername;
@@ -1598,7 +1848,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
 
   /* Add the client again to the ID cache */
   silc_idcache_add(server->local_list->clients, client->nickname,
-                  client_id, client, FALSE);
+                  client_id, client, 0, NULL);
 
   /* Notify our router about new client on the SILC network */
   if (!server->standalone)
@@ -1627,8 +1877,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 "
@@ -1646,10 +1895,14 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                             server->stat.my_servers,
                             server->stat.my_routers));
     SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                           ("%d server operators and %d router operators "
-                            "online",
-                            server->stat.my_server_ops,
-                            server->stat.my_router_ops));
+                           ("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",
@@ -1691,7 +1944,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;
 
@@ -1707,7 +1960,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;
   }
 
@@ -1743,6 +2004,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);
@@ -1766,7 +2037,7 @@ SilcServerEntry silc_server_new_server(SilcServer 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, FALSE);
+                  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
@@ -1879,12 +2150,13 @@ static void silc_server_new_id_real(SilcServer server,
       router = silc_idlist_find_server_by_id(server->local_list,
                                             sender_id, TRUE, NULL);
     silc_free(sender_id);
-    if (!router)
-      goto out;
     router_sock = sock;
     id_list = server->global_list;
   }
 
+  if (!router)
+    goto out;
+
   switch(id_type) {
   case SILC_ID_CLIENT:
     {
@@ -1912,7 +2184,7 @@ static void silc_server_new_id_real(SilcServer server,
         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);
+                                    id, router, NULL, 0);
       if (!entry) {
        SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
 
@@ -2028,7 +2300,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"));
 
@@ -2100,10 +2372,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;
 
@@ -2151,7 +2423,7 @@ void silc_server_new_channel(SilcServer server,
                      sock->hostname));
     
       silc_idlist_add_channel(server->global_list, strdup(channel_name), 
-                             0, channel_id, sock->user_data, NULL, NULL);
+                             0, channel_id, sock->user_data, NULL, NULL, 0);
       server->stat.channels++;
     }
   } else {
@@ -2204,6 +2476,8 @@ void silc_server_new_channel(SilcServer server,
       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),
@@ -2236,7 +2510,8 @@ void silc_server_new_channel(SilcServer server,
        silc_server_send_notify_cmode(server, sock, FALSE, channel,
                                      channel->mode, server->id,
                                      SILC_ID_SERVER,
-                                     channel->cipher, channel->hmac_name);
+                                     channel->cipher, channel->hmac_name,
+                                     channel->passphrase);
       }
 
       /* Create new key for the channel and send it to the server and
@@ -2249,8 +2524,8 @@ void silc_server_new_channel(SilcServer server,
        /* 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_CHANNEL_LEN;
-       
+       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->
@@ -2303,7 +2578,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"));
 
@@ -2414,10 +2689,10 @@ void silc_server_connection_auth_request(SilcServer server,
                                         SilcSocketConnection sock,
                                         SilcPacketContext *packet)
 {
-  SilcServerConfigSectionClientConnection *client = NULL;
-  uint16 conn_type;
-  int ret, port;
-  SilcAuthMethod auth_meth;
+  SilcServerConfigClient *client = NULL;
+  SilcUInt16 conn_type;
+  int ret;
+  SilcAuthMethod auth_meth = SILC_AUTH_NONE;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -2437,21 +2712,21 @@ void silc_server_connection_auth_request(SilcServer server,
 
   /* 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,
-                                              sock->ip,
-                                              port);
+  client = silc_server_config_find_client(server, sock->ip);
   if (!client)
-    client = silc_server_config_find_client_conn(server->config,
-                                                sock->hostname,
-                                                port);
-  if (client)
-    auth_meth = client->auth_meth;
-         
+    client = silc_server_config_find_client(server, sock->hostname);
+  if (client) {
+    if (client->passphrase) {
+      if (client->publickeys && !server->config->prefer_passphrase_auth)
+       auth_meth = SILC_AUTH_PUBLIC_KEY;
+      else
+       auth_meth = SILC_AUTH_PASSWORD;
+    } else if (client->publickeys)
+      auth_meth = SILC_AUTH_PUBLIC_KEY;
+  }
+
   /* Send it back to the client */
-  silc_server_send_connection_auth_request(server, sock,
-                                          conn_type,
-                                          auth_meth);
+  silc_server_send_connection_auth_request(server, sock, conn_type, auth_meth);
 }
 
 /* Received REKEY packet. The sender of the packet wants to regenerate