updates.
[silc.git] / apps / silcd / protocol.c
index 5bf971010d58ec8fabd3816fcfb8088080c1ba91..449a6886daaa3b9190982cc6d85c1ff2f5f49632 100644 (file)
@@ -131,12 +131,11 @@ silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock,
 
       /* Save the key for future checking */
       unlink(filename);
-      silc_pkcs_save_public_key_data(filename, pk, pk_len,
-                                    SILC_PKCS_FILE_PEM);
+      silc_pkcs_save_public_key_data(filename, pk, pk_len, SILC_PKCS_FILE_PEM);
       return TRUE;
     }
 
-    if (memcmp(encpk, pk, encpk_len)) {
+    if (memcmp(pk, encpk, encpk_len)) {
       SILC_LOG_WARNING(("%s (%s) port %d server public key does not match "
                        "with local copy", sock->hostname, sock->ip, 
                        sock->port));
@@ -368,8 +367,10 @@ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
 
   if (maj != maj2)
     status = SILC_SKE_STATUS_BAD_VERSION;
+#if 0
   if (min > min2)
     status = SILC_SKE_STATUS_BAD_VERSION;
+#endif
 
   /* XXX < 0.6 is not allowed */
   if (maj == 0 && min < 5)
@@ -652,6 +653,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
       if (ctx->timeout_task)
        silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
+      /* Assure that after calling final callback there cannot be pending
+        executions for this protocol anymore. This just unregisters any 
+        timeout callbacks for this protocol. */
+      silc_protocol_cancel(protocol, server->schedule);
+
       /* Call the final callback */
       if (protocol->final_callback)
        silc_protocol_execute_final(protocol, server->schedule);
@@ -674,6 +680,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
     if (ctx->timeout_task)
       silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
+    /* Assure that after calling final callback there cannot be pending
+       executions for this protocol anymore. This just unregisters any 
+       timeout callbacks for this protocol. */
+    silc_protocol_cancel(protocol, server->schedule);
+
     /* On error the final callback is always called. */
     if (protocol->final_callback)
       silc_protocol_execute_final(protocol, server->schedule);
@@ -692,6 +703,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
     if (ctx->timeout_task)
       silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
+    /* Assure that after calling final callback there cannot be pending
+       executions for this protocol anymore. This just unregisters any 
+       timeout callbacks for this protocol. */
+    silc_protocol_cancel(protocol, server->schedule);
+    
     /* On error the final callback is always called. */
     if (protocol->final_callback)
       silc_protocol_execute_final(protocol, server->schedule);
@@ -709,13 +725,13 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
  */
 
 static int 
-silc_server_password_authentication(SilcServer server, char *auth1
-                                   char *auth2)
+silc_server_password_authentication(SilcServer server, char *remote_auth
+                                   char *local_auth)
 {
-  if (!auth1 || !auth2)
+  if (!remote_auth || !local_auth)
     return FALSE;
 
-  if (!memcmp(auth1, auth2, strlen(auth1)))
+  if (!memcmp(remote_auth, local_auth, strlen(local_auth)))
     return TRUE;
 
   return FALSE;
@@ -798,6 +814,51 @@ silc_server_get_public_key_auth(SilcServer server,
   return FALSE;
 }
 
+/* Function that actually performs the authentication to the remote. This
+   supports both passphrase and public key authentication. */
+
+static bool 
+silc_server_get_authentication(SilcServerConnAuthInternalContext *ctx,
+                              char *local_passphrase,
+                              void *local_publickey,
+                              unsigned char *remote_auth,
+                              uint32 remote_auth_len)
+{
+  SilcServer server = (SilcServer)ctx->server;
+  SilcSKE ske = ctx->ske;
+  bool result = FALSE;
+
+  /* If we don't have authentication data set at all we do not require
+     authentication at all */
+  if (!local_passphrase && !local_publickey) {
+    SILC_LOG_DEBUG(("No authentication required"));
+    return TRUE;
+  }
+
+  /* If both passphrase and public key is provided then we'll try both of
+     them and see which one of them authenticates.  If only one of them is
+     set, then try only that. */
+
+  /* Try first passphrase (as it is faster to check) */
+  if (local_passphrase) {
+    SILC_LOG_DEBUG(("Password authentication"));
+    result = silc_server_password_authentication(server, local_passphrase,
+                                                remote_auth);
+  }
+
+  /* Try public key authenetication */
+  if (!result && local_publickey) {
+    SILC_LOG_DEBUG(("Public key authentication"));
+    result = silc_server_public_key_authentication(server, 
+                                                  local_publickey,
+                                                  remote_auth,
+                                                  remote_auth_len, 
+                                                  ske);
+  }
+
+  return result;
+}
+
 /* Performs connection authentication protocol. If responder, we 
    authenticate the remote data received. If initiator, we will send
    authentication data to the remote end. */
@@ -890,57 +951,24 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
 
        /* Remote end is client */
        if (conn_type == SILC_SOCKET_TYPE_CLIENT) {
-         SilcServerConfigSectionClientConnection *client = ctx->cconfig;
+         SilcServerConfigSectionClient *client = ctx->cconfig;
          
          if (client) {
-           switch(client->auth_meth) {
-           case SILC_AUTH_NONE:
-             /* No authentication required */
-             SILC_LOG_DEBUG(("No authentication required"));
-             break;
-             
-           case SILC_AUTH_PASSWORD:
-             /* Password authentication */
-             SILC_LOG_DEBUG(("Password authentication"));
-             ret = silc_server_password_authentication(server, auth_data,
-                                                       client->auth_data);
-
-             if (ret)
-               break;
-
+           ret = silc_server_get_authentication(ctx, client->passphrase,
+                                                client->publickey,
+                                                auth_data, payload_len);
+           if (!ret) {
              /* Authentication failed */
              SILC_LOG_ERROR(("Authentication failed"));
              SILC_LOG_DEBUG(("Authentication failed"));
              silc_free(auth_data);
              protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->schedule, 
-                                   0, 300000);
-             return;
-             break;
-             
-           case SILC_AUTH_PUBLIC_KEY:
-             /* Public key authentication */
-             SILC_LOG_DEBUG(("Public key authentication"));
-             ret = silc_server_public_key_authentication(server, 
-                                                         client->auth_data,
-                                                         auth_data,
-                                                         payload_len, 
-                                                         ctx->ske);
-
-             if (ret)
-               break;
-
-             SILC_LOG_ERROR(("Authentication failed"));
-             SILC_LOG_DEBUG(("Authentication failed"));
-             silc_free(auth_data);
-             protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->schedule, 
-                                   0, 300000);
+             silc_protocol_execute(protocol, server->schedule, 0, 300000);
              return;
            }
          } else {
-           SILC_LOG_DEBUG(("No configuration for remote connection"));
-           SILC_LOG_ERROR(("Remote connection not configured"));
+           SILC_LOG_DEBUG(("No configuration for remote client connection"));
+           SILC_LOG_ERROR(("Remote client connection not configured"));
            SILC_LOG_ERROR(("Authentication failed"));
            silc_free(auth_data);
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
@@ -952,57 +980,24 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
        
        /* Remote end is server */
        if (conn_type == SILC_SOCKET_TYPE_SERVER) {
-         SilcServerConfigSectionServerConnection *serv = ctx->sconfig;
+         SilcServerConfigSectionServer *serv = ctx->sconfig;
          
          if (serv) {
-           switch(serv->auth_meth) {
-           case SILC_AUTH_NONE:
-             /* No authentication required */
-             SILC_LOG_DEBUG(("No authentication required"));
-             break;
-             
-           case SILC_AUTH_PASSWORD:
-             /* Password authentication */
-             SILC_LOG_DEBUG(("Password authentication"));
-             ret = silc_server_password_authentication(server, auth_data,
-                                                       serv->auth_data);
-
-             if (ret)
-               break;
-             
+           ret = silc_server_get_authentication(ctx, serv->passphrase,
+                                                serv->publickey,
+                                                auth_data, payload_len);
+           if (!ret) {
              /* Authentication failed */
              SILC_LOG_ERROR(("Authentication failed"));
              SILC_LOG_DEBUG(("Authentication failed"));
              silc_free(auth_data);
              protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->schedule, 
-                                   0, 300000);
-             return;
-             break;
-
-           case SILC_AUTH_PUBLIC_KEY:
-             /* Public key authentication */
-             SILC_LOG_DEBUG(("Public key authentication"));
-             ret = silc_server_public_key_authentication(server, 
-                                                         serv->auth_data,
-                                                         auth_data,
-                                                         payload_len, 
-                                                         ctx->ske);
-                                                         
-             if (ret)
-               break;
-
-             SILC_LOG_ERROR(("Authentication failed"));
-             SILC_LOG_DEBUG(("Authentication failed"));
-             silc_free(auth_data);
-             protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->schedule, 
-                                   0, 300000);
+             silc_protocol_execute(protocol, server->schedule, 0, 300000);
              return;
            }
          } else {
-           SILC_LOG_DEBUG(("No configuration for remote connection"));
-           SILC_LOG_ERROR(("Remote connection not configured"));
+           SILC_LOG_DEBUG(("No configuration for remote server connection"));
+           SILC_LOG_ERROR(("Remote server connection not configured"));
            SILC_LOG_ERROR(("Authentication failed"));
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
            silc_protocol_execute(protocol, server->schedule, 
@@ -1014,57 +1009,24 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
        
        /* Remote end is router */
        if (conn_type == SILC_SOCKET_TYPE_ROUTER) {
-         SilcServerConfigSectionServerConnection *serv = ctx->rconfig;
+         SilcServerConfigSectionRouter *serv = ctx->rconfig;
 
          if (serv) {
-           switch(serv->auth_meth) {
-           case SILC_AUTH_NONE:
-             /* No authentication required */
-             SILC_LOG_DEBUG(("No authentication required"));
-             break;
-             
-           case SILC_AUTH_PASSWORD:
-             /* Password authentication */
-             SILC_LOG_DEBUG(("Password authentication"));
-             ret = silc_server_password_authentication(server, auth_data,
-                                                       serv->auth_data);
-
-             if (ret)
-               break;
-             
+           ret = silc_server_get_authentication(ctx, serv->passphrase,
+                                                serv->publickey,
+                                                auth_data, payload_len);
+           if (!ret) {
              /* Authentication failed */
              SILC_LOG_ERROR(("Authentication failed"));
              SILC_LOG_DEBUG(("Authentication failed"));
              silc_free(auth_data);
              protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->schedule, 
-                                   0, 300000);
-             return;
-             break;
-             
-           case SILC_AUTH_PUBLIC_KEY:
-             /* Public key authentication */
-             SILC_LOG_DEBUG(("Public key authentication"));
-             ret = silc_server_public_key_authentication(server, 
-                                                         serv->auth_data,
-                                                         auth_data,
-                                                         payload_len, 
-                                                         ctx->ske);
-                                                         
-             if (ret)
-               break;
-             
-             SILC_LOG_ERROR(("Authentication failed"));
-             SILC_LOG_DEBUG(("Authentication failed"));
-             silc_free(auth_data);
-             protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->schedule, 
-                                   0, 300000);
+             silc_protocol_execute(protocol, server->schedule, 0, 300000);
              return;
            }
          } else {
-           SILC_LOG_DEBUG(("No configuration for remote connection"));
-           SILC_LOG_ERROR(("Remote connection not configured"));
+           SILC_LOG_DEBUG(("No configuration for remote router connection"));
+           SILC_LOG_ERROR(("Remote router connection not configured"));
            SILC_LOG_ERROR(("Authentication failed"));
            silc_free(auth_data);
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
@@ -1170,6 +1132,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
       if (ctx->timeout_task)
        silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
+      /* Assure that after calling final callback there cannot be pending
+        executions for this protocol anymore. This just unregisters any 
+        timeout callbacks for this protocol. */
+      silc_protocol_cancel(protocol, server->schedule);
+    
       /* Protocol has ended, call the final callback */
       if (protocol->final_callback)
        silc_protocol_execute_final(protocol, server->schedule);
@@ -1196,6 +1163,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
       if (ctx->timeout_task)
        silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
+      /* Assure that after calling final callback there cannot be pending
+        executions for this protocol anymore. This just unregisters any 
+        timeout callbacks for this protocol. */
+      silc_protocol_cancel(protocol, server->schedule);
+    
       /* On error the final callback is always called. */
       if (protocol->final_callback)
        silc_protocol_execute_final(protocol, server->schedule);
@@ -1215,6 +1187,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
     if (ctx->timeout_task)
       silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
+    /* Assure that after calling final callback there cannot be pending
+       executions for this protocol anymore. This just unregisters any 
+       timeout callbacks for this protocol. */
+    silc_protocol_cancel(protocol, server->schedule);
+    
     /* On error the final callback is always called. */
     if (protocol->final_callback)
       silc_protocol_execute_final(protocol, server->schedule);
@@ -1584,6 +1561,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
        encrypted with the new key so set the decryption key to the new key */
     silc_server_protocol_rekey_generate(server, ctx, FALSE);
 
+    /* Assure that after calling final callback there cannot be pending
+       executions for this protocol anymore. This just unregisters any 
+       timeout callbacks for this protocol. */
+    silc_protocol_cancel(protocol, server->schedule);
+    
     /* Protocol has ended, call the final callback */
     if (protocol->final_callback)
       silc_protocol_execute_final(protocol, server->schedule);
@@ -1601,6 +1583,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
       silc_ske_abort(ctx->ske, ctx->ske->status);
     }
 
+    /* Assure that after calling final callback there cannot be pending
+       executions for this protocol anymore. This just unregisters any 
+       timeout callbacks for this protocol. */
+    silc_protocol_cancel(protocol, server->schedule);
+    
     /* On error the final callback is always called. */
     if (protocol->final_callback)
       silc_protocol_execute_final(protocol, server->schedule);
@@ -1613,6 +1600,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
      * We have received failure from remote
      */
 
+    /* Assure that after calling final callback there cannot be pending
+       executions for this protocol anymore. This just unregisters any 
+       timeout callbacks for this protocol. */
+    silc_protocol_cancel(protocol, server->schedule);
+    
     /* On error the final callback is always called. */
     if (protocol->final_callback)
       silc_protocol_execute_final(protocol, server->schedule);