updates.
[silc.git] / apps / silcd / packet_receive.c
index d261e514f10d57022590133d52bda40ff9f618b2..9f1e4ccc2654c27786c2cde062f3b28716e479e7 100644 (file)
@@ -39,13 +39,15 @@ void silc_server_notify(SilcServer server,
   SilcArgumentPayload args;
   SilcChannelID *channel_id, *channel_id2;
   SilcClientID *client_id, *client_id2;
+  SilcServerID *server_id;
   SilcChannelEntry channel;
   SilcClientEntry client;
+  SilcServerEntry server_entry;
   SilcChannelClientEntry chl;
   SilcIDCacheEntry cache;
-  unsigned int mode;
+  uint32 mode;
   unsigned char *tmp;
-  unsigned int tmp_len;
+  uint32 tmp_len;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -68,7 +70,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, packet, TRUE);
+                              idata->hmac_receive, packet, TRUE);
   }
 
   /* If we are router and this packet is not already broadcast packet
@@ -270,17 +272,11 @@ void silc_server_notify(SilcServer server,
     if (tmp_len > 128)
       tmp = NULL;
 
-    /* Remove the client from all channels */
-    silc_server_remove_from_channels(server, NULL, client, TRUE, tmp, TRUE);
+    /* Remove the client from all channels. */
+    silc_server_remove_from_channels(server, NULL, client, TRUE, tmp, FALSE);
 
     client->data.registered = FALSE;
     cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
-
-#if 0
-    /* Remove the client entry */
-    if (!silc_idlist_del_client(server->global_list, client))
-      silc_idlist_del_client(server->local_list, client);
-#endif
     break;
 
   case SILC_NOTIFY_TYPE_TOPIC_SET:
@@ -422,6 +418,20 @@ void silc_server_notify(SilcServer server,
 
     SILC_GET32_MSB(mode, tmp);
 
+    /* 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 */
+      silc_server_create_channel_key(server, channel, 0);
+      
+      /* 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);
@@ -503,12 +513,38 @@ void silc_server_notify(SilcServer server,
 
     /* Get entry to the channel user list */
     silc_list_start(channel->user_list);
-    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+      SilcChannelClientEntry chl2 = NULL;
+
+      /* 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) {
+       silc_server_send_notify_cumode(server, sock, FALSE, channel,
+                                      (mode & (~SILC_CHANNEL_UMODE_CHANFO)),
+                                      server->id, SILC_ID_SERVER, 
+                                      SILC_ID_SERVER_LEN,
+                                      client->id, SILC_ID_CLIENT_LEN);
+       silc_free(channel_id);
+
+       /* Change the mode back if we changed it */
+       if (chl2)
+         chl2->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+       goto out;
+      }
+
       if (chl->client == client) {
        /* Change the mode */
        chl->mode = mode;
-       break;
+       if (!(mode & SILC_CHANNEL_UMODE_CHANFO))
+         break;
+
+       chl2 = chl;
       }
+    }
 
     /* Send the same notify to the channel */
     silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
@@ -597,6 +633,9 @@ void silc_server_notify(SilcServer server,
 
     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)
@@ -630,19 +669,84 @@ void silc_server_notify(SilcServer server,
     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->global_list, channel_id,
                                        channel_id2))
-      silc_idlist_replace_channel_id(server->local_list, channel_id,
-                                    channel_id2);
+      if (!silc_idlist_replace_channel_id(server->local_list, channel_id,
+                                         channel_id2)) {
+       silc_free(channel_id2);
+       channel_id2 = NULL;
+      }
+
+    if (channel_id2) {
+      SilcBuffer users = NULL, users_modes = NULL;
+      
+      /* 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(server, sock,
+                               SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                               users_modes->data, users_modes->len, FALSE);
+       silc_buffer_free(users_modes);
+      }
+    }
 
     silc_free(channel_id);
-    silc_free(channel_id2);
 
     break;
 
   case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
-    SILC_LOG_DEBUG(("SERVER SIGNOFF notify (not-impl XXX)"));
+    /* 
+     * 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, NULL);
+    if (!server_entry) {
+      server_entry = silc_idlist_find_server_by_id(server->local_list, 
+                                                  server_id, NULL);
+      if (!server_entry) {
+       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 */
+    if (!silc_idlist_del_server(server->global_list, server_entry))
+      silc_idlist_del_server(server->local_list, server_entry);
+
+    /* XXX update statistics */
+
     break;
 
   case SILC_NOTIFY_TYPE_KICKED:
@@ -706,7 +810,7 @@ void silc_server_notify(SilcServer server,
        * Distribute the notify to local clients on channels
        */
       unsigned char *id;
-      unsigned int id_len;
+      uint32 id_len;
     
       SILC_LOG_DEBUG(("KILLED notify"));
       
@@ -884,9 +988,9 @@ void silc_server_notify_list(SilcServer server,
 {
   SilcPacketContext *new;
   SilcBuffer buffer;
-  unsigned short len;
+  uint16 len;
 
-  SILC_LOG_DEBUG(("Processing New Notify List"));
+  SILC_LOG_DEBUG(("Processing Notify List"));
 
   if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
       packet->src_id_type != SILC_ID_SERVER)
@@ -961,7 +1065,7 @@ void silc_server_private_message(SilcServer server,
 
   /* Send the private message */
   silc_server_send_private_message(server, dst_sock, idata->send_key,
-                                  idata->hmac, packet);
+                                  idata->hmac_send, packet);
 }
 
 /* Received private message key packet.. This packet is never for us. It is to
@@ -993,7 +1097,7 @@ void silc_server_private_message_key(SilcServer server,
 
   /* Relay the packet */
   silc_server_relay_packet(server, dst_sock, idata->send_key,
-                          idata->hmac, packet, FALSE);
+                          idata->hmac_send, packet, FALSE);
 }
 
 /* Processes incoming command reply packet. The command reply packet may
@@ -1057,7 +1161,7 @@ void silc_server_command_reply(SilcServer server,
     idata = (SilcIDListData)client;
     
     /* Encrypt packet */
-    silc_packet_encrypt(idata->send_key, idata->hmac, dst_sock->outbuf, 
+    silc_packet_encrypt(idata->send_key, idata->hmac_send, dst_sock->outbuf, 
                        buffer->len);
     
     /* Send the packet */
@@ -1078,6 +1182,7 @@ void silc_server_channel_message(SilcServer server,
   SilcChannelClientEntry chl;
   SilcChannelID *id = NULL;
   void *sender = NULL;
+  void *sender_entry = NULL;
 
   SILC_LOG_DEBUG(("Processing channel message"));
 
@@ -1108,12 +1213,13 @@ void silc_server_channel_message(SilcServer server,
                          packet->src_id_type);
   if (!sender)
     goto out;
-  if (sock->type != SILC_SOCKET_TYPE_ROUTER && 
-      packet->src_id_type == SILC_ID_CLIENT) {
+  if (packet->src_id_type == SILC_ID_CLIENT) {
     silc_list_start(channel->user_list);
     while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
-      if (chl->client && !SILC_ID_CLIENT_COMPARE(chl->client->id, sender))
+      if (chl->client && !SILC_ID_CLIENT_COMPARE(chl->client->id, sender)) {
+       sender_entry = chl->client;
        break;
+      }
     }
     if (chl == SILC_LIST_END) {
       SILC_LOG_DEBUG(("Client not on channel"));
@@ -1121,39 +1227,10 @@ void silc_server_channel_message(SilcServer server,
     }
   }
 
-  /* 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)) {
-    SilcBuffer chp;
-    unsigned int iv_len, i, data_len;
-
-    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(data_len, packet->buffer->data);
-    chp = silc_channel_message_payload_encode(data_len, 
-                                             packet->buffer->data + 2,
-                                             iv_len, channel->iv,
-                                             channel->channel_key,
-                                             channel->hmac, server->rng);
-    silc_buffer_put(packet->buffer, chp->data, chp->len);
-    silc_buffer_free(chp);
-  }
-
   /* 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,
+                                     packet->src_id_type, sender_entry,
                                      packet->buffer->data,
                                      packet->buffer->len, FALSE);
 
@@ -1174,7 +1251,9 @@ void silc_server_channel_key(SilcServer server,
   SilcBuffer buffer = packet->buffer;
   SilcChannelEntry channel;
 
-  if (packet->src_id_type != SILC_ID_SERVER)
+  if (packet->src_id_type != SILC_ID_SERVER ||
+      (server->server_type == SILC_ROUTER &&
+       sock->type == SILC_SOCKET_TYPE_ROUTER))
     return;
 
   /* Save the channel key */
@@ -1216,6 +1295,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   if (!silc_idcache_find_by_context(server->local_list->clients,
                                    sock->user_data, &cache)) {
     SILC_LOG_ERROR(("Lost client's cache entry - bad thing"));
+    silc_server_disconnect_remote(server, sock, "Server closed connection: "
+                                  "Unknown client");
     return NULL;
   }
 
@@ -1229,6 +1310,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
       silc_free(username);
     if (realname)
       silc_free(realname);
+    silc_server_disconnect_remote(server, sock, "Server closed connection: "
+                                  "Incomplete client information");
     return NULL;
   }
 
@@ -1259,6 +1342,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   cache->id = (void *)client_id;
   cache->type = SILC_ID_CLIENT;
   cache->data = username;
+  cache->data_len = strlen(username);
   silc_idcache_sort_by_data(server->local_list->clients);
 
   /* Notify our router about new client on the SILC network */
@@ -1353,7 +1437,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   SilcServerID *server_id;
   SilcIDListData idata;
   unsigned char *server_name, *id_string;
-  unsigned short id_len, name_len;
+  uint16 id_len, name_len;
   int ret;
 
   SILC_LOG_DEBUG(("Creating new server"));
@@ -1414,6 +1498,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   cache->id = (void *)server_id;
   cache->type = SILC_ID_SERVER;
   cache->data = server_name;
+  cache->data_len = strlen(server_name);
   silc_idcache_sort_by_data(server->local_list->servers);
 
   /* Distribute the information about new server in the SILC network
@@ -1486,8 +1571,25 @@ static void silc_server_new_id_real(SilcServer server,
   else
     id_list = server->global_list;
 
-  router_sock = sock;
-  router = sock->user_data;
+  /* 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) {
+    router_sock = sock;
+    router = sock->user_data;
+  } 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, NULL);
+    if (!router)
+      router = silc_idlist_find_server_by_id(server->local_list,
+                                            sender_id, NULL);
+    silc_free(sender_id);
+    if (!router)
+      goto out;
+    router_sock = sock;
+  }
 
   switch(id_type) {
   case SILC_ID_CLIENT:
@@ -1521,11 +1623,17 @@ static void silc_server_new_id_real(SilcServer server,
     break;
 
   case SILC_ID_SERVER:
+    /* 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;
+    }
+
     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. */
     silc_idlist_add_server(id_list, NULL, 0, id, router, router_sock);
@@ -1565,7 +1673,7 @@ void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
 {
   SilcPacketContext *new_id;
   SilcBuffer idp;
-  unsigned short id_len;
+  uint16 id_len;
 
   SILC_LOG_DEBUG(("Processing New ID List"));
 
@@ -1633,9 +1741,10 @@ void silc_server_new_channel(SilcServer server,
   SilcChannelPayload payload;
   SilcChannelID *channel_id;
   char *channel_name;
-  unsigned int name_len;
+  uint32 name_len;
   unsigned char *id;
-  unsigned int id_len;
+  uint32 id_len;
+  uint32 mode;
 
   SILC_LOG_DEBUG(("Processing New Channel"));
 
@@ -1720,6 +1829,10 @@ void silc_server_new_channel(SilcServer server,
       /* 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 (!channel->id)
+       channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
 
       if (SILC_ID_CHANNEL_COMPARE(channel_id, channel->id)) {
        /* They don't match, send CHANNEL_CHANGE notify to the server to
@@ -1731,32 +1844,67 @@ void silc_server_new_channel(SilcServer server,
                                               SILC_ID_CHANNEL_LEN);
       }
 
+      /* 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, SILC_ID_SERVER_LEN,
+                                     channel->cipher, channel->hmac_name);
+      }
+
       /* Create new key for the channel and send it to the server and
         everybody else possibly on the channel. */
 
-      silc_server_create_channel_key(server, channel, 0);
-
-      /* Send to the channel */
-      silc_server_send_channel_key(server, sock, channel, FALSE);
+      if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
+       silc_server_create_channel_key(server, channel, 0);
+       
+       /* 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;
+       
+       /* 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);
+      }
 
-      /* 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(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. */
-      /* XXX TODO **/
+      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(server, sock,
+                               SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                               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
@@ -1768,7 +1916,7 @@ void silc_server_new_channel_list(SilcServer server,
 {
   SilcPacketContext *new;
   SilcBuffer buffer;
-  unsigned short len1, len2;
+  uint16 len1, len2;
 
   SILC_LOG_DEBUG(("Processing New Channel List"));
 
@@ -1859,5 +2007,88 @@ void silc_server_key_agreement(SilcServer server,
 
   /* Relay the packet */
   silc_server_relay_packet(server, dst_sock, idata->send_key,
-                          idata->hmac, packet, FALSE);
+                          idata->hmac_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's always knows what authentication
+   method to use. */
+
+void silc_server_connection_auth_request(SilcServer server,
+                                        SilcSocketConnection sock,
+                                        SilcPacketContext *packet)
+{
+  SilcServerConfigSectionClientConnection *client = NULL;
+  uint16 conn_type;
+  int ret;
+  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;
+  client = silc_server_config_find_client_conn(server->config,
+                                              sock->ip,
+                                              sock->port);
+  if (!client)
+    client = silc_server_config_find_client_conn(server->config,
+                                                sock->hostname,
+                                                sock->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 */
+    protocol->execute(server->timeout_queue, 0, protocol, sock->sock, 0, 0);
 }