updates.
authorPekka Riikonen <priikone@silcnet.org>
Fri, 16 Mar 2001 15:51:06 +0000 (15:51 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Fri, 16 Mar 2001 15:51:06 +0000 (15:51 +0000)
13 files changed:
CHANGES
README
apps/silcd/command.c
apps/silcd/idlist.c
apps/silcd/idlist.h
apps/silcd/protocol.c
apps/silcd/serverconfig.c
apps/silcd/serverconfig.h
doc/draft-riikonen-silc-spec-01.nroff
lib/silcclient/command.c
lib/silcclient/command_reply.c
lib/silccore/silcauth.c
lib/silccore/silcauth.h

diff --git a/CHANGES b/CHANGES
index 7676dd2cf8441d4bee6c3caab55f01adae64451f..84f84aba29408d6bc7faf3adecaef675397f7592 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,35 @@
+Fri Mar 16 15:52:49 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Implemented OPER and SILCOPER commands into the server and
+         the client library.
+
+       * Added silc_auth_verify and silc_auth_verify_data to verify
+         the authentication directly from the authentication payload.
+         It supports verifying both passphrase and public key based
+         authentication.  Affected file lib/silccore/silcauth.[ch].
+
+       * Added `hash' field to the SilcIDListData structure.  It is the
+         hash negotiated in the SKE protocol.  Affected file is
+         silcd/idlist.[ch].
+
+       * Slight redesigning of the SilcAuthPayload handling routines.
+         Do not send SilcPKCS but SilcPublicKey as argument.
+
+       * Implemented the public key authentication support to the
+         serverconfig.  The public key is loaded fromthe provided path
+         and saved as authentication data to void * pointer.  Thus,
+         changed the unsigned char *auth_data to void *auth_data;
+
+       * Fixed SHUTDOWN command to send the reply before the server
+         is shutdown. :)  Affected file silcd/command.c.
+
+       * Fixed fatal bug in CONNECT command.  The hostname was invalid
+         memory and server crashed.  Affected file silcd/command.c.
+
+       * Fixed fatal bug in CLOSE command.  The server_entry became
+         invalid but was referenced later in the command.  Affected file
+         silcd/command.c.
+
 Thu Mar 15 12:46:58 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Fixed fatal bug in failure packet handling.  Server ignored
diff --git a/README b/README
index b630091b966809f1bd2e53b2025bd3512b242118..191ebd1e37e8daedb37867b2701f0512f28f5e0c 100644 (file)
--- a/README
+++ b/README
@@ -170,13 +170,21 @@ Following commands has been, at least partly, implemented:
 
                Shows client version.
 
+       /OPER   <username> [<public key>]
+
+               Obtains server operator privileges.
+
+       /SILCOPER <username> [<public key>]
+
+               Obtains router operator privileges.
+
        /CONNECT <server> [<port>]
 
                Connects to server the remote <server>.  You must be
                server operator to be able to do this.
 
 
-       /CLOSE <server> [<port>]
+       /CLOSE  <server> [<port>]
 
                Closes connection to the <server>.  You must be server
                operator to be able to do this.
index 0395e40d2910cb9756c57b627b51d363f99d5914..ef844c0a082ae25b8ec3a419f7577e0079f73cb3 100644 (file)
@@ -3307,12 +3307,138 @@ SILC_SERVER_CMD_FUNC(kick)
   silc_server_command_free(cmd);
 }
 
+/* Server side of OPER command. Client uses this comand to obtain server
+   operator privileges to this server/router. */
+
 SILC_SERVER_CMD_FUNC(oper)
 {
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  unsigned char *username, *auth;
+  unsigned int tmp_len;
+  SilcServerConfigSectionAdminConnection *admin;
+  SilcIDListData idata = (SilcIDListData)client;
+
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_OPER, cmd, 1, 2);
+
+  if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+    goto out;
+
+  /* Get the username */
+  username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  if (!username) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+
+  /* Get the admin configuration */
+  admin = silc_server_config_find_admin(server->config, cmd->sock->ip,
+                                       username, client->nickname);
+  if (!admin) {
+    admin = silc_server_config_find_admin(server->config, cmd->sock->hostname,
+                                         username, client->nickname);
+    if (!admin) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+                                           SILC_STATUS_ERR_AUTH_FAILED);
+      goto out;
+    }
+  }
+
+  /* Get the authentication payload */
+  auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+  if (!auth) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+
+  /* Verify the authentication data */
+  if (!silc_auth_verify_data(auth, tmp_len, admin->auth_meth, 
+                            admin->auth_data, admin->auth_data_len,
+                            idata->hash, client->id, SILC_ID_CLIENT)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+                                         SILC_STATUS_ERR_AUTH_FAILED);
+    goto out;
+  }
+
+  /* Client is now server operator */
+  client->mode |= SILC_UMODE_SERVER_OPERATOR;
+
+  /* Send reply to the sender */
+  silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+                                       SILC_STATUS_OK);
+
+ out:
+  silc_server_command_free(cmd);
 }
 
+/* Server side of SILCOPER command. Client uses this comand to obtain router
+   operator privileges to this router. */
+
 SILC_SERVER_CMD_FUNC(silcoper)
 {
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  unsigned char *username, *auth;
+  unsigned int tmp_len;
+  SilcServerConfigSectionAdminConnection *admin;
+  SilcIDListData idata = (SilcIDListData)client;
+
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_SILCOPER, cmd, 1, 2);
+
+  if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+    goto out;
+
+  /* Get the username */
+  username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  if (!username) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+
+  /* Get the admin configuration */
+  admin = silc_server_config_find_admin(server->config, cmd->sock->ip,
+                                       username, client->nickname);
+  if (!admin) {
+    admin = silc_server_config_find_admin(server->config, cmd->sock->hostname,
+                                         username, client->nickname);
+    if (!admin) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+                                           SILC_STATUS_ERR_AUTH_FAILED);
+      goto out;
+    }
+  }
+
+  /* Get the authentication payload */
+  auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+  if (!auth) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+
+  /* Verify the authentication data */
+  if (!silc_auth_verify_data(auth, tmp_len, admin->auth_meth, 
+                            admin->auth_data, admin->auth_data_len,
+                            idata->hash, client->id, SILC_ID_CLIENT)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+                                         SILC_STATUS_ERR_AUTH_FAILED);
+    goto out;
+  }
+
+  /* Client is now router operator */
+  client->mode |= SILC_UMODE_ROUTER_OPERATOR;
+
+  /* Send reply to the sender */
+  silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+                                       SILC_STATUS_OK);
+
+ out:
+  silc_server_command_free(cmd);
 }
 
 /* Server side command of CONNECT. Connects us to the specified remote
@@ -3323,7 +3449,7 @@ SILC_SERVER_CMD_FUNC(connect)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-  unsigned char *tmp;
+  unsigned char *tmp, *host;
   unsigned int tmp_len;
   unsigned int port = SILC_PORT;
 
@@ -3347,8 +3473,8 @@ SILC_SERVER_CMD_FUNC(connect)
   }
 
   /* Get the remote server */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  if (!tmp) {
+  host = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  if (!host) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -3360,7 +3486,7 @@ SILC_SERVER_CMD_FUNC(connect)
     SILC_GET32_MSB(port, tmp);
 
   /* Create the connection. It is done with timeout and is async. */
-  silc_server_create_connection(server, tmp, port);
+  silc_server_create_connection(server, host, port);
 
   /* Send reply to the sender */
   silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
@@ -3382,6 +3508,7 @@ SILC_SERVER_CMD_FUNC(close)
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   SilcServerEntry server_entry;
+  SilcSocketConnection sock;
   unsigned char *tmp;
   unsigned int tmp_len;
   unsigned char *name;
@@ -3420,16 +3547,15 @@ SILC_SERVER_CMD_FUNC(close)
     goto out;
   }
 
-  /* Close the connection to the server */
-  silc_server_free_sock_user_data(server, server_entry->connection);
-  silc_server_disconnect_remote(server, server_entry->connection,
-                               "Server closed connection: "
-                               "Closed by operator");
-  
   /* Send reply to the sender */
   silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
                                        SILC_STATUS_OK);
 
+  /* Close the connection to the server */
+  sock = (SilcSocketConnection)server_entry->connection;
+  silc_server_free_sock_user_data(server, sock);
+  silc_server_close_connection(server, sock);
+  
  out:
   silc_server_command_free(cmd);
 }
@@ -3455,13 +3581,14 @@ SILC_SERVER_CMD_FUNC(shutdown)
     goto out;
   }
 
-  /* Then, gracefully, or not, bring the server down. */
-  silc_server_stop(server);
-
   /* Send reply to the sender */
   silc_server_command_send_status_reply(cmd, SILC_COMMAND_SHUTDOWN,
                                        SILC_STATUS_OK);
 
+  /* Then, gracefully, or not, bring the server down. */
+  silc_server_stop(server);
+  exit(0);
+
  out:
   silc_server_command_free(cmd);
 }
index 86b603179b036ce579ec3329c0d1f5b8dff85fff..aca1c2812721eecdc43ee94ab6abcb2ee48b16e6 100644 (file)
@@ -36,6 +36,7 @@ void silc_idlist_add_data(void *entry, SilcIDListData idata)
   SilcIDListData data = (SilcIDListData)entry;
   data->send_key = idata->send_key;
   data->receive_key = idata->receive_key;
+  data->hash = idata->hash;
   data->hmac = idata->hmac;
   data->hmac_key = idata->hmac_key;
   data->hmac_key_len = idata->hmac_key_len;
@@ -179,8 +180,9 @@ silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
     server = (SilcServerEntry)id_cache->context;
     sock = (SilcSocketConnection)server->connection;
     
-    if (sock && (!strcmp(sock->hostname, hostname) ||
-                !strcmp(sock->ip, hostname)) && sock->port == port)
+    if (sock && ((sock->hostname && !strcmp(sock->hostname, hostname)) ||
+                (sock->ip && !strcmp(sock->ip, hostname)))
+       && sock->port == port)
       break;
 
     id_cache = NULL;
index 9d29d74fdfc02a0c0f054673981b31099ffd4ddb..bcd3c3f143095549fc6693c2fc5a7202a14e33b5 100644 (file)
@@ -44,6 +44,9 @@ typedef struct {
   SilcCipher send_key;
   SilcCipher receive_key;
 
+  /* Hash selected in the SKE protocol, NULL if not needed at all */
+  SilcHash hash;
+
   /* HMAC and raw key data */
   SilcHmac hmac;
   unsigned char *hmac_key;
index ca091612ba9dd8d1a9170284c29fe09940ffaba7..1c0335571050b3324d8c11e464c23c5723d1b214 100644 (file)
@@ -113,10 +113,19 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske,
                           ske->ke2_payload->pk_len);
 #endif
 
+  /* Save the hash */
+  if (!silc_hash_alloc(hash->hash->name, &idata->hash)) {
+    silc_cipher_free(idata->send_key);
+    silc_cipher_free(idata->receive_key);
+    silc_free(conn_data);
+    return FALSE;
+  }
+
   /* Save HMAC key to be used in the communication. */
   if (!silc_hmac_alloc(hmac->hmac->name, NULL, &idata->hmac)) {
     silc_cipher_free(idata->send_key);
     silc_cipher_free(idata->receive_key);
+    silc_hash_free(idata->hash);
     silc_free(conn_data);
     return FALSE;
   }
index cc51b89b0dab976c7dec9605abfd5a5d12bb55de..d1c0ad37c10c7266136c81b61d9a7bd3c2c86ec1 100644 (file)
@@ -682,12 +682,30 @@ int silc_server_config_parse_lines(SilcServerConfig config,
       }
 
       /* Get authentication data */
-      ret = silc_config_get_token(line, &config->clients->auth_data);
+      ret = silc_config_get_token(line, (char **)&config->clients->auth_data);
       if (ret < 0)
        break;
-      if (ret == 0)
-       /* Any host */
-       config->clients->host = strdup("*");
+
+      if (config->clients->auth_meth == SILC_AUTH_PASSWORD) {
+       config->clients->auth_data_len = strlen(config->clients->auth_data);
+      } else if (config->clients->auth_meth == SILC_AUTH_PUBLIC_KEY) {
+       /* Get the public key */
+       SilcPublicKey public_key;
+
+       if (!silc_pkcs_load_public_key(config->clients->auth_data,
+                                      &public_key, SILC_PKCS_FILE_PEM))
+         if (!silc_pkcs_load_public_key(config->clients->auth_data,
+                                        &public_key, SILC_PKCS_FILE_BIN)) {
+           fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
+                   config->filename, pc->linenum, 
+                   (char *)config->clients->auth_data);
+           break;
+         }
+
+       silc_free(config->clients->auth_data);
+       config->clients->auth_data = (void *)public_key;
+       config->clients->auth_data_len = 0;
+      }
 
       /* Get port */
       ret = silc_config_get_token(line, &tmp);
@@ -745,10 +763,31 @@ int silc_server_config_parse_lines(SilcServerConfig config,
       }
 
       /* Get authentication data */
-      ret = silc_config_get_token(line, &config->servers->auth_data);
+      ret = silc_config_get_token(line, (char **)&config->servers->auth_data);
       if (ret < 0)
        break;
 
+      if (config->servers->auth_meth == SILC_AUTH_PASSWORD) {
+       config->servers->auth_data_len = strlen(config->servers->auth_data);
+      } else if (config->servers->auth_meth == SILC_AUTH_PUBLIC_KEY) {
+       /* Get the public key */
+       SilcPublicKey public_key;
+
+       if (!silc_pkcs_load_public_key(config->servers->auth_data,
+                                      &public_key, SILC_PKCS_FILE_PEM))
+         if (!silc_pkcs_load_public_key(config->servers->auth_data,
+                                        &public_key, SILC_PKCS_FILE_BIN)) {
+           fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
+                   config->filename, pc->linenum, 
+                   (char *)config->servers->auth_data);
+           break;
+         }
+
+       silc_free(config->servers->auth_data);
+       config->servers->auth_data = (void *)public_key;
+       config->servers->auth_data_len = 0;
+      }
+
       /* Get port */
       ret = silc_config_get_token(line, &tmp);
       if (ret < 0)
@@ -810,10 +849,31 @@ int silc_server_config_parse_lines(SilcServerConfig config,
       }
 
       /* Get authentication data */
-      ret = silc_config_get_token(line, &config->routers->auth_data);
+      ret = silc_config_get_token(line, (char **)&config->routers->auth_data);
       if (ret < 0)
        break;
 
+      if (config->routers->auth_meth == SILC_AUTH_PASSWORD) {
+       config->routers->auth_data_len = strlen(config->routers->auth_data);
+      } else if (config->routers->auth_meth == SILC_AUTH_PUBLIC_KEY) {
+       /* Get the public key */
+       SilcPublicKey public_key;
+
+       if (!silc_pkcs_load_public_key(config->routers->auth_data,
+                                      &public_key, SILC_PKCS_FILE_PEM))
+         if (!silc_pkcs_load_public_key(config->routers->auth_data,
+                                        &public_key, SILC_PKCS_FILE_BIN)) {
+           fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
+                   config->filename, pc->linenum, 
+                   (char *)config->routers->auth_data);
+           break;
+         }
+
+       silc_free(config->routers->auth_data);
+       config->routers->auth_data = (void *)public_key;
+       config->routers->auth_data_len = 0;
+      }
+
       /* Get port */
       ret = silc_config_get_token(line, &tmp);
       if (ret < 0)
@@ -902,10 +962,31 @@ int silc_server_config_parse_lines(SilcServerConfig config,
       }
 
       /* Get authentication data */
-      ret = silc_config_get_token(line, &config->admins->auth_data);
+      ret = silc_config_get_token(line, (char **)&config->admins->auth_data);
       if (ret < 0)
        break;
 
+      if (config->admins->auth_meth == SILC_AUTH_PASSWORD) {
+       config->admins->auth_data_len = strlen(config->admins->auth_data);
+      } else if (config->admins->auth_meth == SILC_AUTH_PUBLIC_KEY) {
+       /* Get the public key */
+       SilcPublicKey public_key;
+
+       if (!silc_pkcs_load_public_key(config->admins->auth_data,
+                                      &public_key, SILC_PKCS_FILE_PEM))
+         if (!silc_pkcs_load_public_key(config->admins->auth_data,
+                                        &public_key, SILC_PKCS_FILE_BIN)) {
+           fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
+                   config->filename, pc->linenum, 
+                   (char *)config->admins->auth_data);
+           break;
+         }
+
+       silc_free(config->admins->auth_data);
+       config->admins->auth_data = (void *)public_key;
+       config->admins->auth_data_len = 0;
+      }
+
       check = TRUE;
       checkmask |= (1L << pc->section->type);
       break;
@@ -1403,7 +1484,7 @@ silc_server_config_find_admin(SilcServerConfig config,
     host = "*";
   if (!username)
     username = "*";
-  if (nickname)
+  if (!nickname)
     nickname = "*";
 
   admin = config->admins;
index 3e911eac4556d26e6e80588e25124017a70aad1c..77644e4fae1f1250276353c9fd26faffabfda43f 100644 (file)
@@ -95,8 +95,9 @@ typedef struct SilcServerConfigSectionConnectionClassStruct {
 /* Holds all client authentication data from config file */
 typedef struct SilcServerConfigSectionClientConnectionStruct {
   char *host;
-  int auth_meth;
-  char *auth_data;
+  SilcAuthMethod auth_meth;
+  void *auth_data;
+  unsigned int auth_data_len;
   unsigned short port;
   unsigned int class;
   struct SilcServerConfigSectionClientConnectionStruct *next;
@@ -108,8 +109,9 @@ typedef struct SilcServerConfigSectionAdminConnectionStruct {
   char *host;
   char *username;
   char *nickname;
-  int auth_meth;
-  char *auth_data;
+  SilcAuthMethod auth_meth;
+  void *auth_data;
+  unsigned int auth_data_len;
   struct SilcServerConfigSectionAdminConnectionStruct *next;
   struct SilcServerConfigSectionAdminConnectionStruct *prev;
 } SilcServerConfigSectionAdminConnection;
@@ -117,8 +119,9 @@ typedef struct SilcServerConfigSectionAdminConnectionStruct {
 /* Holds all configured server/router connections from config file */
 typedef struct SilcServerConfigSectionServerConnectionStruct {
   char *host;
-  int auth_meth;
-  char *auth_data;
+  SilcAuthMethod auth_meth;
+  void *auth_data;
+  unsigned int auth_data_len;
   unsigned short port;
   char *version;
   unsigned int class;
index fa5909171dd745fbaaa800b123ff8b468a5bdf4b..79e6fafd5b52fac41ee289b143959b50d79dc5a4 100644 (file)
@@ -2354,7 +2354,7 @@ List of all defined commands in SILC follows.
    13   SILC_COMMAND_OPER
 
         Max Arguments:  2
-            Arguments:  (1) <username>  (2) <authentication data>
+            Arguments:  (1) <username>  (2) <authentication payload>
 
         This command is used by normal client to obtain server operator
         privileges on some server or router.  Note that router operator
@@ -2363,11 +2363,10 @@ List of all defined commands in SILC follows.
         must use SILCOPER command to obtain router level privileges.
 
         The <username> is the username set in the server configurations
-        as operator.  The <authentication data> is the data that the
+        as operator.  The <authentication payload> is the data that the
         client is authenticated against.  It may be passphrase prompted
-        for user on client's screen or it may be public key
-        authentication data (data signed with private key), or 
-        certificate.
+        for user on client's screen or it may be public key or certificate
+        authentication data (data signed with private key).
 
         Reply messages to the command:
 
@@ -2382,7 +2381,6 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
             SILC_STATUS_ERR_TOO_MANY_PARAMS
             SILC_STATUS_ERR_NOT_REGISTERED
-            SILC_STATUS_ERR_BAD_PASSWORD
             SILC_STATUS_ERR_AUTH_FAILED
 
 
@@ -2961,7 +2959,7 @@ List of all defined commands in SILC follows.
    23   SILC_COMMAND_SILCOPER
 
         Max Arguments:  2
-            Arguments:  (1) <username>  (2) <authentication data>
+            Arguments:  (1) <username>  (2) <authentication payload>
 
         This command is used by normal client to obtain router operator
         privileges (also known as SILC operator) on some router.  Note
@@ -2969,7 +2967,7 @@ List of all defined commands in SILC follows.
         server operator privileges.
 
         The <username> is the username set in the server configurations
-        as operator.  The <authentication data> is the data that the
+        as operator.  The <authentication payload> is the data that the
         client is authenticated against.  It may be passphrase prompted
         for user on client's screen or it may be public key
         authentication data (data signed with private key), or 
@@ -2994,7 +2992,6 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
             SILC_STATUS_ERR_TOO_MANY_PARAMS
             SILC_STATUS_ERR_NOT_REGISTERED
-            SILC_STATUS_ERR_BAD_PASSWORD
             SILC_STATUS_ERR_AUTH_FAILED
 
 
index e01a9b19500102e37c105659a68b4d988c02fa60..4b3214b4d8f3c56e65467fcfef1b6ccd2326ded3 100644 (file)
@@ -35,7 +35,7 @@ SilcClientCommand silc_command_list[] =
   SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3),
   SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 2),
   SILC_CLIENT_CMD(kill, KILL, "KILL", 
-                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
   SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
   SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
@@ -51,11 +51,11 @@ SilcClientCommand silc_command_list[] =
   SILC_CLIENT_CMD(restart, RESTART, "RESTART",
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
   SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
-                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
   SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN",
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 1),
   SILC_CLIENT_CMD(silcoper, SILCOPER, "SILOPER",
-                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 2),
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 3),
   SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
   SILC_CLIENT_CMD(users, USERS, "USERS", SILC_CF_LAG | SILC_CF_REG, 2),
 
@@ -1264,12 +1264,126 @@ SILC_CLIENT_CMD_FUNC(kick)
   silc_client_command_free(cmd);
 }
 
-SILC_CLIENT_CMD_FUNC(silcoper)
+/* OPER command. Used to obtain server operator privileges. */
+
+SILC_CLIENT_CMD_FUNC(oper)
 {
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcBuffer buffer;
+  unsigned char *auth_data;
+  SilcBuffer auth;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc < 2) {
+    cmd->client->ops->say(cmd->client, conn, 
+                         "Usage: /OPER <username> [<public key>]");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc == 3) {
+    /* XXX Get public key */
+    auth_data = NULL;
+    COMMAND_ERROR;
+    goto out;
+  } else {
+    /* Get passphrase */
+
+    auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
+    if (!auth_data) {
+      COMMAND_ERROR;
+      goto out;
+    }
+
+    /* Encode the authentication payload */
+    auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
+                                   auth_data, strlen(auth_data));
+  }
+
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2, 
+                                         1, cmd->argv[1], 
+                                         strlen(cmd->argv[1]),
+                                         2, auth->data, auth->len);
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+                         0, NULL, NULL, buffer->data, buffer->len, TRUE);
+
+  silc_buffer_free(buffer);
+  silc_buffer_free(auth);
+  memset(auth_data, 0, strlen(auth_data));
+  silc_free(auth_data);
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
 }
 
-SILC_CLIENT_CMD_FUNC(oper)
+/* SILCOPER command. Used to obtain router operator privileges. */
+
+SILC_CLIENT_CMD_FUNC(silcoper)
 {
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcBuffer buffer;
+  unsigned char *auth_data;
+  SilcBuffer auth;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc < 2) {
+    cmd->client->ops->say(cmd->client, conn, 
+                         "Usage: /SILCOPER <username> [<public key>]");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc == 3) {
+    /* XXX Get public key */
+    auth_data = NULL;
+    COMMAND_ERROR;
+    goto out;
+  } else {
+    /* Get passphrase */
+
+    auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
+    if (!auth_data) {
+      COMMAND_ERROR;
+      goto out;
+    }
+
+    /* Encode the authentication payload */
+    auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
+                                   auth_data, strlen(auth_data));
+  }
+
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2, 
+                                         1, cmd->argv[1], 
+                                         strlen(cmd->argv[1]),
+                                         2, auth->data, auth->len);
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+                         0, NULL, NULL, buffer->data, buffer->len, TRUE);
+
+  silc_buffer_free(buffer);
+  silc_buffer_free(auth);
+  memset(auth_data, 0, strlen(auth_data));
+  silc_free(auth_data);
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
 }
 
 /* CONNECT command. Connects the server to another server. */
index e21a3f52c9d92c2bf1983a1fbfea7c527bc7c739..a9833571d2974604810ae453fe85a647cbc69e52 100644 (file)
@@ -1160,10 +1160,56 @@ SILC_CLIENT_CMD_REPLY_FUNC(kick)
 
 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
 {
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  unsigned char *tmp;
+
+  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+  SILC_GET16_MSB(status, tmp);
+  if (status != SILC_STATUS_OK) {
+    cmd->client->ops->say(cmd->client, conn,
+            "%s", silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS));
+
+  /* Execute any pending command callbacks */
+  SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
+
+ out:
+  SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
+  silc_client_command_reply_free(cmd);
 }
 
 SILC_CLIENT_CMD_REPLY_FUNC(oper)
 {
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  unsigned char *tmp;
+
+  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+  SILC_GET16_MSB(status, tmp);
+  if (status != SILC_STATUS_OK) {
+    cmd->client->ops->say(cmd->client, conn,
+            "%s", silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS));
+
+  /* Execute any pending command callbacks */
+  SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
+
+ out:
+  SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
+  silc_client_command_reply_free(cmd);
 }
 
 SILC_CLIENT_CMD_REPLY_FUNC(connect)
index 153058609f607080e151ab1a7493ae95abe9c3f6..a7a43c4106da093537ad7e87c4dca6fd365b1a0d 100644 (file)
@@ -132,7 +132,8 @@ void silc_auth_payload_free(SilcAuthPayload payload)
    dictates. */
 
 static unsigned char *
-silc_auth_public_key_encode_data(SilcPKCS pkcs, unsigned char *random,
+silc_auth_public_key_encode_data(SilcPublicKey public_key, 
+                                unsigned char *random,
                                 unsigned int random_len, void *id,
                                 SilcIdType type, unsigned int *ret_len)
 {
@@ -140,7 +141,7 @@ silc_auth_public_key_encode_data(SilcPKCS pkcs, unsigned char *random,
   unsigned char *pk, *id_data, *ret;
   unsigned int pk_len, id_len;
 
-  pk = silc_pkcs_get_public_key(pkcs, &pk_len);
+  pk = silc_pkcs_public_key_encode(public_key, &pk_len);
   if (!pk)
     return NULL;
 
@@ -176,7 +177,7 @@ silc_auth_public_key_encode_data(SilcPKCS pkcs, unsigned char *random,
    to do public key based authentication. This generates the random data
    and the actual authentication data. Returns NULL on error. */
 
-SilcBuffer silc_auth_public_key_auth_generate(SilcPKCS pkcs,
+SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
                                              SilcHash hash,
                                              void *id, SilcIdType type)
 {
@@ -186,6 +187,7 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPKCS pkcs,
   unsigned char *tmp;
   unsigned int tmp_len;
   SilcBuffer buf;
+  SilcPKCS pkcs;
 
   SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
 
@@ -195,11 +197,18 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPKCS pkcs,
     return NULL;
   
   /* Encode the auth data */
-  tmp = silc_auth_public_key_encode_data(pkcs, random, 256, id, type, 
+  tmp = silc_auth_public_key_encode_data(public_key, random, 256, id, type, 
                                         &tmp_len);
   if (!tmp)
     return NULL;
 
+  /* Allocate PKCS object */
+  if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
+    memset(tmp, 0, tmp_len);
+    silc_free(tmp);
+    return NULL;
+  }
+
   /* Compute the hash and the signature. */
   if (!silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
                                &auth_len)) {
@@ -207,6 +216,7 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPKCS pkcs,
     memset(tmp, 0, tmp_len);
     silc_free(tmp);
     silc_free(random);
+    silc_pkcs_free(pkcs);
     return NULL;
   }
 
@@ -219,6 +229,7 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPKCS pkcs,
   memset(random, 0, 256);
   silc_free(tmp);
   silc_free(random);
+  silc_pkcs_free(pkcs);
 
   return buf;
 }
@@ -227,16 +238,17 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPKCS pkcs,
    successfull. */
 
 int silc_auth_public_key_auth_verify(SilcAuthPayload payload,
-                                    SilcPKCS pkcs, SilcHash hash,
+                                    SilcPublicKey public_key, SilcHash hash,
                                     void *id, SilcIdType type)
 {
   unsigned char *tmp;
   unsigned int tmp_len;
+  SilcPKCS pkcs;
 
   SILC_LOG_DEBUG(("Verifying authentication data"));
 
   /* Encode auth data */
-  tmp = silc_auth_public_key_encode_data(pkcs, payload->random_data, 
+  tmp = silc_auth_public_key_encode_data(public_key, payload->random_data, 
                                         payload->random_len, 
                                         id, type, &tmp_len);
   if (!tmp) {
@@ -244,18 +256,27 @@ int silc_auth_public_key_auth_verify(SilcAuthPayload payload,
     return FALSE;
   }
 
+  /* Allocate PKCS object */
+  if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
+    memset(tmp, 0, tmp_len);
+    silc_free(tmp);
+    return FALSE;
+  }
+
   /* Verify the authentication data */
   if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
                                  payload->auth_len, tmp, tmp_len)) {
 
     memset(tmp, 0, tmp_len);
     silc_free(tmp);
+    silc_pkcs_free(pkcs);
     SILC_LOG_DEBUG(("Authentication failed"));
     return FALSE;
   }
 
   memset(tmp, 0, tmp_len);
   silc_free(tmp);
+  silc_pkcs_free(pkcs);
 
   SILC_LOG_DEBUG(("Authentication successfull"));
 
@@ -265,7 +286,8 @@ int silc_auth_public_key_auth_verify(SilcAuthPayload payload,
 /* Same as above but the payload is not parsed yet. This will parse it. */
 
 int silc_auth_public_key_auth_verify_data(SilcBuffer payload,
-                                         SilcPKCS pkcs, SilcHash hash,
+                                         SilcPublicKey public_key, 
+                                         SilcHash hash,
                                          void *id, SilcIdType type)
 {
   SilcAuthPayload auth_payload;
@@ -277,7 +299,7 @@ int silc_auth_public_key_auth_verify_data(SilcBuffer payload,
     return FALSE;
   }
 
-  ret = silc_auth_public_key_auth_verify(auth_payload, pkcs, hash, 
+  ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash, 
                                         id, type);
 
   silc_auth_payload_free(auth_payload);
@@ -285,6 +307,81 @@ int silc_auth_public_key_auth_verify_data(SilcBuffer payload,
   return ret;
 }
 
+/* Verifies the authentication data directly from the Authentication 
+   Payload. Supports all authentication methods. If the authentication
+   method is passphrase based then the `auth_data' and `auth_data_len'
+   are the passphrase and its length. If the method is public key
+   authentication then the `auth_data' is the SilcPublicKey and the
+   `auth_data_len' is ignored. */
+
+int silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
+                    void *auth_data, unsigned int auth_data_len, 
+                    SilcHash hash, void *id, SilcIdType type)
+{
+  SILC_LOG_DEBUG(("Verifying authentication"));
+
+  if (auth_method != payload->auth_method)
+    return FALSE;
+
+  switch (payload->auth_method) {
+  case SILC_AUTH_NONE:
+    /* No authentication */
+    SILC_LOG_DEBUG(("No authentication required"));
+    return TRUE;
+
+  case SILC_AUTH_PASSWORD:
+    /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
+       arguments are not needed. */
+    if (!memcmp(payload->auth_data, auth_data, payload->auth_len)) {
+      SILC_LOG_DEBUG(("Authentication successfull"));
+      return TRUE;
+    }
+    break;
+
+  case SILC_AUTH_PUBLIC_KEY:
+    /* Public key based authentication */
+    return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
+                                           hash, id, type);
+    break;
+
+  default:
+    break;
+  }
+
+  SILC_LOG_DEBUG(("Authentication failed"));
+
+  return FALSE;
+}
+
+/* Same as above but parses the authentication payload before verify. */
+
+int silc_auth_verify_data(unsigned char *payload, unsigned int payload_len,
+                         SilcAuthMethod auth_method, void *auth_data,
+                         unsigned int auth_data_len, SilcHash hash, 
+                         void *id, SilcIdType type)
+{
+  SilcAuthPayload auth_payload;
+  SilcBuffer buffer;
+  int ret;
+
+  buffer = silc_buffer_alloc(payload_len);
+  silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+  silc_buffer_put(buffer, payload, payload_len);
+  auth_payload = silc_auth_payload_parse(buffer);
+  if (!auth_payload) {
+    silc_buffer_free(buffer);
+    return FALSE;
+  }
+
+  ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len, 
+                        hash, id, type);
+
+  silc_auth_payload_free(auth_payload);
+  silc_buffer_free(buffer);
+
+  return ret;
+}
+
 /******************************************************************************
 
                             Key Agreement Payload
index c691722c1e6e93c1717a2f6c2c512363b1b30496..1e55d264885e8a4514b8388d8c4c15200ac17d2f 100644 (file)
@@ -48,15 +48,23 @@ SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
                                    unsigned char *auth_data,
                                    unsigned short auth_len);
 void silc_auth_payload_free(SilcAuthPayload payload);
-SilcBuffer silc_auth_public_key_auth_generate(SilcPKCS pkcs,
+SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
                                              SilcHash hash,
                                              void *id, SilcIdType type);
 int silc_auth_public_key_auth_verify(SilcAuthPayload payload,
-                                    SilcPKCS pkcs, SilcHash hash,
+                                    SilcPublicKey public_key, SilcHash hash,
                                     void *id, SilcIdType type);
 int silc_auth_public_key_auth_verify_data(SilcBuffer payload,
-                                         SilcPKCS pkcs, SilcHash hash,
+                                         SilcPublicKey public_key, 
+                                         SilcHash hash,
                                          void *id, SilcIdType type);
+int silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
+                    void *auth_data, unsigned int auth_data_len, 
+                    SilcHash hash, void *id, SilcIdType type);
+int silc_auth_verify_data(unsigned char *payload, unsigned int payload_len,
+                         SilcAuthMethod auth_method, void *auth_data,
+                         unsigned int auth_data_len, SilcHash hash, 
+                         void *id, SilcIdType type);
 SilcKeyAgreementPayload silc_key_agreement_payload_parse(SilcBuffer buffer);
 SilcBuffer silc_key_agreement_payload_encode(char *hostname,
                                             unsigned int port);