updates.
[silc.git] / apps / silcd / server.c
index 999c24b60a6f6f8a893396354a5cc39280321e0b..96a2433ad82affaf9debd9fa62d4c019d90accec 100644 (file)
@@ -711,6 +711,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
   SilcServerConnection sconn = (SilcServerConnection)ctx->context;
   SilcSocketConnection sock = NULL;
   SilcServerConnAuthInternalContext *proto_ctx;
+  SilcServerConfigSectionServerConnection *conn = NULL;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -768,28 +769,35 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
   proto_ctx->dest_id_type = ctx->dest_id_type;
   proto_ctx->dest_id = ctx->dest_id;
 
-  /* Resolve the authentication method used in this connection */
-  proto_ctx->auth_meth = SILC_AUTH_PASSWORD;
-  if (server->config->routers) {
-    SilcServerConfigSectionServerConnection *conn = NULL;
-
-    /* Check if we find a match from user configured connections */
-    conn = silc_server_config_find_router_conn(server->config,
-                                              sock->hostname,
-                                              sock->port);
-    if (conn) {
-      /* Match found. Use the configured authentication method */
-      proto_ctx->auth_meth = conn->auth_meth;
-      if (conn->auth_data) {
-       proto_ctx->auth_data = strdup(conn->auth_data);
-       proto_ctx->auth_data_len = strlen(conn->auth_data);
-      }
-    } else {
-      /* No match found. */
-      /* XXX */
+  /* Resolve the authentication method used in this connection. Check if 
+     we find a match from user configured connections */
+  conn = silc_server_config_find_router_conn(server->config,
+                                            sock->hostname,
+                                            sock->port);
+  if (conn) {
+    /* Match found. Use the configured authentication method */
+    proto_ctx->auth_meth = conn->auth_meth;
+    if (conn->auth_data) {
+      proto_ctx->auth_data = strdup(conn->auth_data);
+      proto_ctx->auth_data_len = strlen(conn->auth_data);
     }
   } else {
-    /* XXX */
+    SILC_LOG_ERROR(("Could not find connection data for %s (%s) on port",
+                   sock->hostname, sock->ip, sock->port));
+    silc_protocol_free(protocol);
+    silc_ske_free_key_material(ctx->keymat);
+    if (ctx->packet)
+      silc_packet_context_free(ctx->packet);
+    if (ctx->ske)
+      silc_ske_free(ctx->ske);
+    if (ctx->dest_id)
+      silc_free(ctx->dest_id);
+    silc_free(ctx);
+    silc_task_unregister_by_callback(server->timeout_queue,
+                                    silc_server_failure_callback);
+    silc_server_disconnect_remote(server, sock, "Server closed connection: "
+                                 "Key exchange failed");
+    return;
   }
 
   /* Free old protocol as it is finished now */
@@ -959,13 +967,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
 
   /* Check max connections */
   if (sock > SILC_SERVER_MAX_CONNECTIONS) {
-    if (server->config->redirect) {
-      /* XXX Redirecting connection to somewhere else now?? */
-      /*silc_server_send_notify("Server is full, trying to redirect..."); */
-    } else {
-      SILC_LOG_ERROR(("Refusing connection, server is full"));
-      server->stat.conn_failures++;
-    }
+    SILC_LOG_ERROR(("Refusing connection, server is full"));
+    server->stat.conn_failures++;
     return;
   }
 
@@ -1184,7 +1187,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
         and other information is created after we have received NEW_CLIENT
         packet from client. */
       client = silc_idlist_add_client(server->local_list, 
-                                     NULL, NULL, NULL, NULL, NULL, sock);
+                                     NULL, 0, NULL, NULL, NULL, NULL, sock);
       if (!client) {
        SILC_LOG_ERROR(("Could not add new client to cache"));
        silc_free(sock->user_data);
@@ -1796,6 +1799,7 @@ void silc_server_packet_parse_type(SilcServer server,
     SILC_LOG_DEBUG(("Connection authentication request packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
+    silc_server_connection_auth_request(server, sock, packet);
     break;
 
     /*
@@ -2003,7 +2007,8 @@ void silc_server_free_client_data(SilcServer server,
 
   /* If there is pending outgoing data for the client then purge it
      to the network before removing the client entry. */
-  if (SILC_IS_OUTBUF_PENDING(sock) && (SILC_IS_DISCONNECTED(sock) == FALSE)) {
+  if (sock && SILC_IS_OUTBUF_PENDING(sock) && 
+      (SILC_IS_DISCONNECTED(sock) == FALSE)) {
     server->stat.packets_sent++;
 
     if (sock->outbuf->data - sock->outbuf->head)
@@ -2476,6 +2481,9 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
     return NULL;
   }
 
+  entry->cipher = strdup(cipher);
+  entry->hmac_name = strdup(hmac);
+
   /* Now create the actual key material */
   silc_server_create_channel_key(server, entry, 
                                 silc_cipher_get_key_len(key) / 8);
@@ -2669,6 +2677,10 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
     goto out;
   }
 
+  if (channel->cipher)
+    silc_free(channel->cipher);
+  channel->cipher = strdup(cipher);
+
   /* Save the key */
   channel->key_len = tmp_len * 8;
   channel->key = silc_calloc(tmp_len, sizeof(unsigned char));
@@ -3102,7 +3114,8 @@ void silc_server_save_users_on_channel(SilcServer server,
       /* We don't have that client anywhere, add it. The client is added
         to global list since server didn't have it in the lists so it must be 
         global. */
-      client = silc_idlist_add_client(server->global_list, NULL, NULL, NULL, 
+      client = silc_idlist_add_client(server->global_list, NULL, 0, NULL, 
+                                     NULL, 
                                      silc_id_dup(client_id, SILC_ID_CLIENT), 
                                      sock->user_data, NULL);
       if (!client) {
@@ -3129,11 +3142,13 @@ void silc_server_save_users_on_channel(SilcServer server,
 
 /* Lookups route to the client indicated by `id' client ID. The connection
    object and internal data object is returned. Returns NULL if route
-   could not be found to the client. */
+   could not be found to the client. If the `client_id' is specified then
+   it is used and the `id_data' is ignored. */
 
 SilcSocketConnection silc_server_get_client_route(SilcServer server,
                                                  unsigned char *id_data,
                                                  unsigned int id_len,
+                                                 SilcClientID *client_id,
                                                  SilcIDListData *idata)
 {
   SilcClientID *id;
@@ -3142,10 +3157,14 @@ SilcSocketConnection silc_server_get_client_route(SilcServer server,
   SILC_LOG_DEBUG(("Start"));
 
   /* Decode destination Client ID */
-  id = silc_id_str2id(id_data, id_len, SILC_ID_CLIENT);
-  if (!id) {
-    SILC_LOG_ERROR(("Could not decode destination Client ID, dropped"));
-    return NULL;
+  if (!client_id) {
+    id = silc_id_str2id(id_data, id_len, SILC_ID_CLIENT);
+    if (!id) {
+      SILC_LOG_ERROR(("Could not decode destination Client ID, dropped"));
+      return NULL;
+    }
+  } else {
+    id = silc_id_dup(client_id, SILC_ID_CLIENT);
   }
 
   /* If the destination belongs to our server we don't have to route
@@ -3244,3 +3263,40 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
 
   return buffer;
 }
+
+/* Finds client entry by Client ID and if it is not found then resolves
+   it using WHOIS command. */
+
+SilcClientEntry silc_server_get_client_resolve(SilcServer server,
+                                              SilcClientID *client_id)
+{
+  SilcClientEntry client;
+
+  client = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
+  if (!client) {
+    client = silc_idlist_find_client_by_id(server->global_list, 
+                                          client_id, NULL);
+    if (!client && server->server_type == SILC_ROUTER)
+      return NULL;
+  }
+
+  if (!client && server->standalone)
+    return NULL;
+
+  if (!client || !client->nickname || !client->username) {
+    SilcBuffer buffer, idp;
+
+    idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
+                                           ++server->cmd_ident, 1,
+                                           3, idp->data, idp->len);
+    silc_server_packet_send(server, client ? client->router->connection :
+                           server->router->connection,
+                           SILC_PACKET_COMMAND, 0,
+                           buffer->data, buffer->len, FALSE);
+    silc_buffer_free(idp);
+    silc_buffer_free(buffer);
+  }
+
+  return client;
+}