New silcconfig library and server parser. Merged silc-newconfig-final.patch.
[silc.git] / apps / silcd / command.c
index c4bad1acfe4d9fe4db0ad7064069b3e9ddae3814..b4d5bcee37adf53669b7e5e77dde3ac515eb6dae 100644 (file)
@@ -131,7 +131,6 @@ static int silc_server_is_registered(SilcServer server,
 
   silc_server_command_send_status_reply(cmd, command,
                                        SILC_STATUS_ERR_NOT_REGISTERED);
-  silc_server_command_free(cmd);
   return FALSE;
 }
 
@@ -149,6 +148,11 @@ SILC_TASK_CALLBACK(silc_server_command_process_timeout)
   SilcServerCommandTimeout timeout = (SilcServerCommandTimeout)context;
   SilcClientEntry client = (SilcClientEntry)timeout->ctx->sock->user_data;
 
+  if (!client) {
+    silc_server_command_free(timeout->ctx);
+    silc_free(timeout);
+  }
+
   /* Update access time */
   client->last_command = time(NULL);
 
@@ -159,6 +163,8 @@ SILC_TASK_CALLBACK(silc_server_command_process_timeout)
                                     timeout->ctx, 
                                     timeout->cmd->cmd))
     timeout->cmd->cb(timeout->ctx, NULL);
+  else
+    silc_server_command_free(timeout->ctx);
 
   silc_free(timeout);
 }
@@ -233,15 +239,12 @@ void silc_server_command_process(SilcServer server,
                         silc_server_command_process_timeout,
                         (void *)timeout, 
                         2 - (time(NULL) - client->last_command), 0,
-                        SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_NORMAL);
+                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
     else
       silc_schedule_task_add(server->schedule, sock->sock, 
                         silc_server_command_process_timeout,
-                        (void *)timeout, 
-                        0, 1,
-                        SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_NORMAL);
+                        (void *)timeout, 0, 1,
+                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
     return;
   }
 
@@ -251,6 +254,8 @@ void silc_server_command_process(SilcServer server,
     cmd->cb(ctx, NULL);
   else if (silc_server_is_registered(server, sock, ctx, cmd->cmd))
     cmd->cb(ctx, NULL);
+  else
+    silc_server_command_free(ctx);
 }
 
 /* Allocate Command Context */
@@ -561,6 +566,8 @@ silc_server_command_whois_check(SilcServerCommandContext cmd,
   int i, k;
   bool no_res = TRUE;
 
+  SILC_LOG_DEBUG(("Start"));
+
   for (i = 0; i < clients_count; i++) {
     entry = clients[i];
     if (!entry)
@@ -1059,7 +1066,6 @@ silc_server_command_whowas_check(SilcServerCommandContext cmd,
                                  silc_server_command_whowas, 
                                  silc_server_command_dup(cmd));
       cmd->pending = TRUE;
-      
       silc_command_set_ident(cmd->payload, old_ident);
 
       silc_buffer_free(tmpbuf);
@@ -1077,36 +1083,53 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
 {
   SilcServer server = cmd->server;
   char *tmp;
-  int i, count = 0, len;
+  int i, k, count = 0, len;
   SilcBuffer packet, idp;
   SilcClientEntry entry = NULL;
   SilcCommandStatus status;
   uint16 ident = silc_command_get_ident(cmd->payload);
-  char found = FALSE;
   char nh[256], uh[256];
+  int valid_count;
 
   status = SILC_STATUS_OK;
-  if (clients_count > 1)
-    status = SILC_STATUS_LIST_START;
 
+  /* Process only entries that are not registered anymore. */
+  valid_count = 0;
   for (i = 0; i < clients_count; i++) {
-    entry = clients[i];
+    if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
+      clients[i] = NULL;
+    else
+      valid_count++;
+  }
 
-    /* We will take only clients that are not valid anymore. They are the
-       ones that are not registered anymore but still have a ID. They
-       have disconnected us, and thus valid for WHOWAS. */
-    if (entry->data.status & SILC_IDLIST_STATUS_REGISTERED || !entry->id)
-      continue;
+  if (!valid_count) {
+    /* No valid entries found at all, just send error */
+    unsigned char *tmp;
+    
+    tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+    if (tmp)
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
+                                          SILC_STATUS_ERR_NO_SUCH_NICK,
+                                          3, tmp, strlen(tmp));
+    return;
+  }
 
-    if (count && i - 1 == count)
-      break;
+  if (valid_count > 1)
+    status = SILC_STATUS_LIST_START;
 
-    found = TRUE;
+  for (i = 0, k = 0; i < clients_count; i++) {
+    entry = clients[i];
+    if (!entry)
+      continue;
 
-    if (clients_count > 2)
+    if (k >= 1)
       status = SILC_STATUS_LIST_ITEM;
-    if (clients_count > 1 && i == clients_count - 1)
+    if (valid_count > 1 && k == valid_count - 1)
       status = SILC_STATUS_LIST_END;
+    if (count && k - 1 == count)
+      status = SILC_STATUS_LIST_END;
+    if (count && k - 1 > count)
+      break;
 
     /* Send WHOWAS reply */
     idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
@@ -1147,13 +1170,9 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
     
     silc_buffer_free(packet);
     silc_buffer_free(idp);
-  }
 
-  if (found == FALSE && entry)
-    silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
-                                        SILC_STATUS_ERR_NO_SUCH_NICK,
-                                        3, entry->nickname, 
-                                        strlen(entry->nickname));
+    k++;
+  }
 }
 
 static int
@@ -1193,7 +1212,6 @@ silc_server_command_whowas_process(SilcServerCommandContext cmd)
                                silc_server_command_whowas,
                                silc_server_command_dup(cmd));
     cmd->pending = TRUE;
-
     silc_command_set_ident(cmd->payload, old_ident);
 
     silc_buffer_free(tmpbuf);
@@ -2332,7 +2350,7 @@ SILC_SERVER_CMD_FUNC(topic)
     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
     /* Send notify about topic change to all clients on the channel */
-    silc_server_send_notify_to_channel(server, NULL, channel, TRUE, 
+    silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
                                       SILC_NOTIFY_TYPE_TOPIC_SET, 2,
                                       idp->data, idp->len,
                                       channel->topic, strlen(channel->topic));
@@ -2429,6 +2447,7 @@ SILC_SERVER_CMD_FUNC(invite)
   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
   if (tmp) {
     char invite[512];
+    bool resolve;
 
     dest_id = silc_id_payload_parse_id(tmp, len);
     if (!dest_id) {
@@ -2438,11 +2457,12 @@ SILC_SERVER_CMD_FUNC(invite)
     }
 
     /* Get the client entry */
-    dest = silc_server_get_client_resolve(server, dest_id);
+    dest = silc_server_get_client_resolve(server, dest_id, &resolve);
     if (!dest) {
-      if (server->server_type != SILC_SERVER) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
-                                    SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+      if (server->server_type != SILC_SERVER || !resolve) {
+       silc_server_command_send_status_reply(
+                                       cmd, SILC_COMMAND_INVITE,
+                                       SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
        goto out;
       }
       
@@ -2655,6 +2675,7 @@ SILC_SERVER_CMD_FUNC(kill)
   SilcClientID *client_id;
   unsigned char *tmp, *comment;
   uint32 tmp_len, tmp_len2;
+  bool local;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 2);
 
@@ -2692,9 +2713,11 @@ SILC_SERVER_CMD_FUNC(kill)
   /* Get the client entry */
   remote_client = silc_idlist_find_client_by_id(server->local_list, 
                                                client_id, TRUE, NULL);
+  local = TRUE;
   if (!remote_client) {
     remote_client = silc_idlist_find_client_by_id(server->global_list, 
                                                  client_id, TRUE, NULL);
+    local = FALSE;
     if (!remote_client) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
@@ -2748,9 +2771,17 @@ SILC_SERVER_CMD_FUNC(kill)
     silc_server_free_client_data(server, sock, remote_client, FALSE, NULL);
     silc_server_close_connection(server, sock);
   } else {
+    /* Update statistics */
+    if (remote_client->connection)
+      server->stat.my_clients--;
+    if (server->server_type == SILC_ROUTER)
+      server->stat.cell_clients--;
+    SILC_OPER_STATS_UPDATE(remote_client, server, SILC_UMODE_SERVER_OPERATOR);
+    SILC_OPER_STATS_UPDATE(remote_client, router, SILC_UMODE_ROUTER_OPERATOR);
+
     /* Remove remote client */
-    if (!silc_idlist_del_client(server->global_list, remote_client))
-      silc_idlist_del_client(server->local_list, remote_client);
+    silc_idlist_del_client(local ? server->local_list :
+                          server->global_list, remote_client);
   }
 
  out:
@@ -2818,10 +2849,10 @@ SILC_SERVER_CMD_FUNC(info)
     memset(info_string, 0, sizeof(info_string));
     snprintf(info_string, sizeof(info_string), 
             "location: %s server: %s admin: %s <%s>",
-            server->config->admin_info->location,
-            server->config->admin_info->server_type,
-            server->config->admin_info->admin_name,
-            server->config->admin_info->admin_email);
+            server->config->server_info->location,
+            server->config->server_info->server_type,
+            server->config->server_info->admin,
+            server->config->server_info->email);
 
     server_info = info_string;
     entry = server->id_entry;
@@ -2981,6 +3012,7 @@ static void silc_server_command_join_channel(SilcServer server,
   uint16 ident = silc_command_get_ident(cmd->payload);
   char check[512], check2[512];
   bool founder = FALSE;
+  bool resolve;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -2991,11 +3023,18 @@ static void silc_server_command_join_channel(SilcServer server,
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
     client = (SilcClientEntry)sock->user_data;
   } else {
-    client = silc_server_get_client_resolve(server, client_id);
+    client = silc_server_get_client_resolve(server, client_id, &resolve);
     if (!client) {
       if (cmd->pending)
        goto out;
 
+      if (!resolve) {
+       silc_server_command_send_status_reply(
+                                        cmd, SILC_COMMAND_JOIN,
+                                        SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+       goto out;
+      }
+
       /* The client info is being resolved. Reprocess this packet after
         receiving the reply to the query. */
       silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
@@ -3226,24 +3265,24 @@ static void silc_server_command_join_channel(SilcServer server,
       /* Distribute the channel key to all backup routers. */
       silc_server_backup_send(server, NULL, SILC_PACKET_CHANNEL_KEY, 0,
                              keyp->data, keyp->len, FALSE, TRUE);
+  }
 
-    /* If client became founder by providing correct founder auth data
-       notify the mode change to the channel. */
-    if (founder) {
-      SILC_PUT32_MSB(chl->mode, mode);
-      silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
-                                        SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
-                                        clidp->data, clidp->len,
-                                        mode, 4, clidp->data, clidp->len);
+  /* If client became founder by providing correct founder auth data
+     notify the mode change to the channel. */
+  if (founder) {
+    SILC_PUT32_MSB(chl->mode, mode);
+    silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
+                                      SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
+                                      clidp->data, clidp->len,
+                                      mode, 4, clidp->data, clidp->len);
       
-      /* Set CUMODE notify type to network */
-      if (!server->standalone)
-       silc_server_send_notify_cumode(server, server->router->connection,
-                                      server->server_type == SILC_ROUTER ? 
-                                      TRUE : FALSE, channel,
-                                      chl->mode, client->id, SILC_ID_CLIENT,
-                                      client->id);
-    }
+    /* Set CUMODE notify type to network */
+    if (!server->standalone)
+      silc_server_send_notify_cumode(server, server->router->connection,
+                                    server->server_type == SILC_ROUTER ? 
+                                    TRUE : FALSE, channel,
+                                    chl->mode, client->id, SILC_ID_CLIENT,
+                                    client->id);
   }
 
   silc_buffer_free(reply);
@@ -3316,16 +3355,8 @@ SILC_SERVER_CMD_FUNC(join)
                                             channel_name, NULL);
 
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
-    /* If this is coming from client the Client ID in the command packet must
-       be same as the client's ID. */
-    if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
-      SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
-      if (!SILC_ID_CLIENT_COMPARE(entry->id, client_id)) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                       SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-       goto out;
-      }
-    }
+    SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
+    client_id = silc_id_dup(entry->id, SILC_ID_CLIENT);
 
     if (!channel || channel->disabled) {
       /* Channel not found */
@@ -3336,8 +3367,9 @@ SILC_SERVER_CMD_FUNC(join)
        channel = silc_server_create_new_channel(server, server->id, cipher, 
                                                 hmac, channel_name, TRUE);
        if (!channel) {
-         silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+         silc_server_command_send_status_reply(
+                                        cmd, SILC_COMMAND_JOIN,
+                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
          goto out;
        }
        
@@ -3377,6 +3409,8 @@ SILC_SERVER_CMD_FUNC(join)
                                      silc_server_command_join,
                                      silc_server_command_dup(cmd));
          cmd->pending = TRUE;
+          silc_command_set_ident(cmd->payload, old_ident);
+         silc_buffer_free(tmpbuf);
          goto out;
        }
        
@@ -3440,10 +3474,12 @@ SILC_SERVER_CMD_FUNC(join)
     if (silc_command_get(reply->payload) == SILC_COMMAND_JOIN) {
       tmp = silc_argument_get_arg_type(reply->args, 6, NULL);
       SILC_GET32_MSB(created, tmp);
-      create_key = FALSE;      /* Router returned the key already */
+      if (silc_argument_get_arg_type(reply->args, 7, NULL))
+       create_key = FALSE;     /* Router returned the key already */
     }
 
-    if (silc_command_get(reply->payload) == SILC_COMMAND_WHOIS)
+    if (silc_command_get(reply->payload) == SILC_COMMAND_WHOIS &&
+       !silc_hash_table_count(channel->user_list))
       created = TRUE;
   }
 
@@ -3490,10 +3526,10 @@ SILC_SERVER_CMD_FUNC(motd)
 
     idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
 
-    if (server->config && server->config->motd && 
-       server->config->motd->motd_file) {
+    if (server->config && server->config->server_info &&
+       server->config->server_info->motd_file) {
       /* Send motd */
-      motd = silc_file_readfile(server->config->motd->motd_file, &motd_len);
+      motd = silc_file_readfile(server->config->server_info->motd_file, &motd_len);
       if (!motd)
        goto out;
       
@@ -3636,9 +3672,14 @@ SILC_SERVER_CMD_FUNC(umode)
       goto out;
     }
   } else {
-    if (client->mode & SILC_UMODE_SERVER_OPERATOR)
-      /* Remove the server operator rights */
+    /* Remove the server operator rights */
+    if (client->mode & SILC_UMODE_SERVER_OPERATOR) {
       client->mode &= ~SILC_UMODE_SERVER_OPERATOR;
+      if (client->connection)
+       server->stat.my_server_ops--;
+      if (server->server_type == SILC_ROUTER)
+       server->stat.server_ops--;
+    }
   }
 
   if (mask & SILC_UMODE_ROUTER_OPERATOR) {
@@ -3649,9 +3690,14 @@ SILC_SERVER_CMD_FUNC(umode)
       goto out;
     }
   } else {
-    if (client->mode & SILC_UMODE_ROUTER_OPERATOR)
-      /* Remove the router operator rights */
+    /* Remove the router operator rights */
+    if (client->mode & SILC_UMODE_ROUTER_OPERATOR) {
       client->mode &= ~SILC_UMODE_ROUTER_OPERATOR;
+      if (client->connection)
+       server->stat.my_router_ops--;
+      if (server->server_type == SILC_ROUTER)
+       server->stat.router_ops--;
+    }
   }
 
   if (mask & SILC_UMODE_GONE) {
@@ -3834,22 +3880,22 @@ SILC_SERVER_CMD_FUNC(cmode)
       /* The mode is removed and we need to generate and distribute
         new channel key. Clients are not using private channel keys
         anymore after this. */
-
+      
       /* Re-generate channel key */
       if (!silc_server_create_channel_key(server, channel, 0))
        goto out;
-      
+       
       /* Send the channel key. This sends it to our local clients and if
         we are normal server to our router as well. */
       silc_server_send_channel_key(server, NULL, channel, 
                                   server->server_type == SILC_ROUTER ? 
                                   FALSE : !server->standalone);
-
+       
       cipher = channel->channel_key->cipher->name;
       hmac = (char *)silc_hmac_get_name(channel->hmac);
     }
   }
-  
+
   if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
     /* User limit is set on channel */
     uint32 user_limit;
@@ -4248,9 +4294,9 @@ SILC_SERVER_CMD_FUNC(cumode)
 
   /* If the target client is founder, no one else can change their mode
      but themselves. */
-  if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && chl->client != target_client) {
+  if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && client != target_client) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                         SILC_STATUS_ERR_NOT_YOU);
+                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV);
     goto out;
   }
 
@@ -4509,7 +4555,7 @@ SILC_SERVER_CMD_FUNC(kick)
     silc_server_send_notify_kicked(server, server->router->connection,
                                   server->server_type == SILC_ROUTER ?
                                   TRUE : FALSE, channel,
-                                  target_client->id, comment);
+                                  target_client->id, client->id, comment);
 
   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
     /* Re-generate channel key */
@@ -4537,7 +4583,7 @@ SILC_SERVER_CMD_FUNC(oper)
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   unsigned char *username, *auth;
   uint32 tmp_len;
-  SilcServerConfigSectionAdminConnection *admin;
+  SilcServerConfigSectionAdmin *admin;
   SilcIDListData idata = (SilcIDListData)client;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_OPER, cmd, 1, 2);
@@ -4586,6 +4632,12 @@ SILC_SERVER_CMD_FUNC(oper)
   /* Client is now server operator */
   client->mode |= SILC_UMODE_SERVER_OPERATOR;
 
+  /* Update statistics */
+  if (client->connection)
+    server->stat.my_server_ops++;
+  if (server->server_type == SILC_ROUTER)
+    server->stat.server_ops++;
+
   /* Send UMODE change to primary router */
   if (!server->standalone)
     silc_server_send_notify_umode(server, server->router->connection, TRUE,
@@ -4609,7 +4661,7 @@ SILC_SERVER_CMD_FUNC(silcoper)
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   unsigned char *username, *auth;
   uint32 tmp_len;
-  SilcServerConfigSectionAdminConnection *admin;
+  SilcServerConfigSectionAdmin *admin;
   SilcIDListData idata = (SilcIDListData)client;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SILCOPER, cmd, 1, 2);
@@ -4664,6 +4716,12 @@ SILC_SERVER_CMD_FUNC(silcoper)
   /* Client is now router operator */
   client->mode |= SILC_UMODE_ROUTER_OPERATOR;
 
+  /* Update statistics */
+  if (client->connection)
+    server->stat.my_router_ops++;
+  if (server->server_type == SILC_ROUTER)
+    server->stat.router_ops++;
+
   /* Send UMODE change to primary router */
   if (!server->standalone)
     silc_server_send_notify_umode(server, server->router->connection, TRUE,
@@ -4786,7 +4844,11 @@ SILC_SERVER_CMD_FUNC(ban)
   }
 
   /* Get entry to the channel user list */
-  silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl);
+  if (!silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
+                                         SILC_STATUS_ERR_NOT_ON_CHANNEL);
+    goto out;
+  }
 
   /* The client must be at least channel operator. */
   if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
@@ -4847,7 +4909,7 @@ SILC_SERVER_CMD_FUNC(ban)
                                         2, id, id_len,
                                         3, channel->ban_list, 
                                         channel->ban_list ? 
-                                        strlen(channel->ban_list) - 1 : 0);
+                                        strlen(channel->ban_list) -1 : 0);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
     
@@ -5199,6 +5261,7 @@ SILC_SERVER_CMD_FUNC(getkey)
   uint32 tmp_len, pklen;
   SilcBuffer pk = NULL;
   SilcIdType id_type;
+  SilcPublicKey public_key;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -5267,11 +5330,12 @@ SILC_SERVER_CMD_FUNC(getkey)
     /* The client is locally connected, just get the public key and
        send it back. If they key does not exist then do not send it, 
        send just OK reply */
-    if (!client->data.public_key) {
+    public_key = client->data.public_key;
+    if (!public_key) {
       pkdata = NULL;
       pklen = 0;
     } else {
-      tmp = silc_pkcs_public_key_encode(client->data.public_key, &tmp_len);
+      tmp = silc_pkcs_public_key_encode(public_key, &tmp_len);
       pk = silc_buffer_alloc(4 + tmp_len);
       silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
       silc_buffer_format(pk,
@@ -5317,7 +5381,6 @@ SILC_SERVER_CMD_FUNC(getkey)
                                  silc_server_command_getkey,
                                  silc_server_command_dup(cmd));
       cmd->pending = TRUE;
-      
       silc_command_set_ident(cmd->payload, old_ident);
       silc_buffer_free(tmpbuf);
       goto out;
@@ -5330,12 +5393,14 @@ SILC_SERVER_CMD_FUNC(getkey)
     }
 
     /* If they key does not exist then do not send it, send just OK reply */
-    if (!server_entry->data.public_key) {
+    public_key = (!server_entry->data.public_key ? 
+                 (server_entry == server->id_entry ? server->public_key :
+                  NULL) : server_entry->data.public_key);
+    if (!public_key) {
       pkdata = NULL;
       pklen = 0;
     } else {
-      tmp = silc_pkcs_public_key_encode(server_entry->data.public_key, 
-                                       &tmp_len);
+      tmp = silc_pkcs_public_key_encode(public_key, &tmp_len);
       pk = silc_buffer_alloc(4 + tmp_len);
       silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
       silc_buffer_format(pk,