silc-client: target public key verification better
[silc.git] / apps / irssi / src / silc / core / client_ops.c
index 2de86781ee02c2339e3728f42678ac95e0e36e01..9ad989e29ff80b58638ffe5fa24b6c2b78cf0f93 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2007 Pekka Riikonen
+  Copyright (C) 2001 - 2014 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -212,14 +212,26 @@ void silc_say(SilcClient client, SilcClientConnection conn,
              SilcClientMessageType type, char *msg, ...)
 {
   SILC_SERVER_REC *server;
+  char *target = NULL;
   va_list va;
   char *str;
 
   server = conn == NULL ? NULL : conn->context;
 
+  switch (conn->context_type) {
+    case SILC_ID_CLIENT:
+      target = (conn->client_entry->nickname[0] ?
+               conn->client_entry->nickname : NULL);
+    break;
+
+    case SILC_ID_CHANNEL:
+      target = conn->channel_entry->channel_name;
+    break;
+  }
+
   va_start(va, msg);
   str = g_strdup_vprintf(msg, va);
-  printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
+  printtext(server, target, MSGLEVEL_CRAP, "%s", str);
   g_free(str);
   va_end(va);
 }
@@ -262,10 +274,11 @@ int verify_message_signature(SilcClientEntry sender,
                                      sizeof(sender->fingerprint));
       if (strcmp(fingerprint, fingerprint2)) {
         /* since the public key differs from the senders public key, the
-           verification _failed_ */
+           verification won't be done */
         silc_pkcs_public_key_free(pk);
         silc_free(fingerprint);
-        ret = SILC_MSG_SIGNED_UNKNOWN;
+        silc_free(fingerprint2);
+       return SILC_MSG_SIGNED_UNKNOWN;
       }
       silc_free(fingerprint2);
     }
@@ -945,7 +958,7 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
        tmp = cp;
       }
 
-      chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
+      chanrec->topic = (tmp && *tmp == '\0' ? NULL : g_strdup(tmp));
       signal_emit("channel topic changed", 1, chanrec);
 
       silc_free(dm);
@@ -1406,7 +1419,7 @@ typedef struct {
   SilcIdType id_type;
 } *GetkeyContext;
 
-void silc_getkey_cb(bool success, void *context)
+void silc_getkey_cb(SilcBool success, void *context)
 {
   GetkeyContext getkey = (GetkeyContext)context;
   char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
@@ -1421,15 +1434,8 @@ void silc_getkey_cb(bool success, void *context)
   silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
 
   if (success) {
-    if (getkey->id_type == SILC_ID_CLIENT)
-      printformat_module("fe-common/silc", NULL, NULL,
-                        MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED_CLIENT,
-                        name,
-                        silc_pubkey->identifier.realname ?
-                        silc_pubkey->identifier.realname : "",
-                        silc_pubkey->identifier.email ?
-                        silc_pubkey->identifier.email : "");
-    else
+    /* Client's verification notice was showed in verify_internal() */
+    if (getkey->id_type != SILC_ID_CLIENT)
       printformat_module("fe-common/silc", NULL, NULL,
                         MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED,
                         entity, name);
@@ -1440,17 +1446,18 @@ void silc_getkey_cb(bool success, void *context)
   }
 
   /*
-       * Drop our references as need be.
-       */
-  switch (getkey->id_type)
-  {
-    case SILC_ID_CLIENT:
-          silc_client_unref_client(getkey->client, getkey->conn, (SilcClientEntry)getkey->entry);
-          break;
+   * Drop our references as need be.
+   */
+  switch (getkey->id_type) {
+  case SILC_ID_CLIENT:
+    silc_client_unref_client(getkey->client, getkey->conn,
+                            (SilcClientEntry)getkey->entry);
+    break;
 
-    case SILC_ID_SERVER:
-          silc_client_unref_server(getkey->client, getkey->conn, (SilcServerEntry)getkey->entry);
-               break;
+  case SILC_ID_SERVER:
+    silc_client_unref_server(getkey->client, getkey->conn,
+                            (SilcServerEntry)getkey->entry);
+    break;
   }
 
   silc_free(getkey);
@@ -1676,7 +1683,7 @@ void silc_command_reply(SilcClient client, SilcClientConnection conn,
 
       if (idle && nickname) {
        memset(buf, 0, sizeof(buf));
-       snprintf(buf, sizeof(buf) - 1, "%lu %s",
+       snprintf(buf, sizeof(buf) - 1, "%u %s",
                 idle > 60 ? (idle / 60) : idle,
                 idle > 60 ? "minutes" : "seconds");
 
@@ -2112,17 +2119,16 @@ void silc_command_reply(SilcClient client, SilcClientConnection conn,
                ((SilcClientEntry)entry)->nickname :
                ((SilcServerEntry)entry)->server_name);
 
-       switch (id_type)
-       {
-               case SILC_ID_CLIENT:
-                       name = ((SilcClientEntry)entry)->nickname;
-                       silc_client_ref_client(client, conn, (SilcClientEntry)entry);
-                       break;
-
-               case SILC_ID_SERVER:
-                       name = ((SilcServerEntry)entry)->server_name;
-                       silc_client_ref_server(client, conn, (SilcServerEntry)entry);
-                       break;
+       switch (id_type) {
+       case SILC_ID_CLIENT:
+         name = ((SilcClientEntry)entry)->nickname;
+         silc_client_ref_client(client, conn, (SilcClientEntry)entry);
+         break;
+
+       case SILC_ID_SERVER:
+         name = ((SilcServerEntry)entry)->server_name;
+         silc_client_ref_server(client, conn, (SilcServerEntry)entry);
+         break;
        }
 
        silc_verify_public_key_internal(client, conn, name,
@@ -2395,19 +2401,19 @@ typedef struct {
 } *PublicKeyVerify;
 
 static void verify_public_key_completion(const char *line, void *context,
-               SilcKeyboardPromptStatus reason)
+                                        SilcKeyboardPromptStatus reason)
 {
   PublicKeyVerify verify = (PublicKeyVerify)context;
-  bool success = (reason == KeyboardCompletionSuccess);
+  SilcBool success = (reason == KeyboardCompletionSuccess);
 
   if (success && (line[0] == 'Y' || line[0] == 'y')) {
-    /* Call the completion */
-    if (verify->completion)
-      verify->completion(TRUE, verify->context);
-
     /* Save the key for future checking */
     silc_pkcs_save_public_key(verify->filename, verify->public_key,
                              SILC_PKCS_FILE_BASE64);
+
+    /* Call the completion */
+    if (verify->completion)
+      verify->completion(TRUE, verify->context);
   } else {
     /* Call the completion */
     if (verify->completion)
@@ -2426,21 +2432,17 @@ static void verify_public_key_completion(const char *line, void *context,
    * we failed due to an overlapping callback, in which case we shouldn't
    * overwrite the async context block pointer.
    */
-
-  if (reason != KeyboardCompletionFailed)
-  {
+  if (reason != KeyboardCompletionFailed) {
     /*
-         * Null out the completion context in the server record as this operation
-         * is done as far as we are concerned.  The underlying keyboard library
-         * routine will take care of freeing the async context memory when the
-         * actual callback is called by irssi in the abort case.  In the success
-         * case, it will free the async context memory after we return from this
-         * routine.
-         */
-
-     SILC_SERVER_REC *server = (SILC_SERVER_REC*)(verify->conn->context);
-
-         server->prompt_op = NULL;
+     * Null out the completion context in the server record as this operation
+     * is done as far as we are concerned.  The underlying keyboard library
+     * routine will take care of freeing the async context memory when the
+     * actual callback is called by irssi in the abort case.  In the success
+     * case, it will free the async context memory after we return from this
+     * routine.
+     */
+    SILC_SERVER_REC *server = (SILC_SERVER_REC*)(verify->conn->context);
+    server->prompt_op = NULL;
   }
 
   silc_free(verify->filename);
@@ -2467,7 +2469,7 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
   SilcPublicKey local_pubkey;
   SilcSILCPublicKey silc_pubkey;
   SilcUInt16 port;
-  SILC_SERVER_REC *server;
+  SILC_SERVER_REC *server = NULL;
   const char *hostname, *ip;
   unsigned char *pk;
   SilcUInt32 pk_len;
@@ -2479,48 +2481,19 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
   int i;
 
   server = (SILC_SERVER_REC*)conn->context;
-
-  /*
-       * If we don't have a context yet, then we'll set it up based on the
-       * stream context associated with the SilcPacketStream that is attached
-       * to the SilcClientConnection.  This is a bit ugly, but we need to have a
-       * per-connection context value to perform the public key verify operation,
-       * and the public API was not designed to let us have this in a particularly
-       * straightforward fashion.
-       */
-
-  if (!server) {
-    SilcPacketStream packet_stream;
-        SilcStream       stream;
-
-    packet_stream = conn->stream;
-
-        if (!packet_stream)
-    {
+  if (conn_type != SILC_CONN_CLIENT) {
+    SILC_VERIFY(server);
+    if (!server) {
       if (completion)
-        completion(FALSE, context);
-      return;
-    }
-
-    stream        = silc_packet_stream_get_stream(packet_stream);
-
-    if (!stream)
-    {
-      if (completion)
-        completion(FALSE, context);
-      return;
-    }
-
-    server        = (SILC_SERVER_REC*)(silc_socket_stream_get_context(stream));
-
-    if (!server)
-    {
-      if (completion)
-        completion(FALSE, context);
+       completion(FALSE, context);
       return;
     }
+  }
 
-    conn->context = (void *)server;
+  /* If we have pending public key prompt already up */
+  if (server && server->prompt_op) {
+    silc_async_abort(server->prompt_op, NULL, NULL);
+    server->prompt_op = NULL;
   }
 
   if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
@@ -2599,6 +2572,9 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
   fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
   babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
 
+  if (!name && conn->context_type == SILC_ID_CLIENT)
+    name = conn->client_entry->nickname;
+
   verify = silc_calloc(1, sizeof(*verify));
   verify->client = client;
   verify->conn = conn;
@@ -2625,6 +2601,14 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
                         silc_pubkey->identifier.realname,
                         silc_pubkey->identifier.email ?
                         silc_pubkey->identifier.email : "");
+    else if (conn_type == SILC_CONN_CLIENT &&
+            (silc_pubkey->identifier.realname ||
+             silc_pubkey->identifier.email))
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+                        SILCTXT_PUBKEY_RECEIVED_CLIENT, "",
+                        silc_pubkey->identifier.realname,
+                        silc_pubkey->identifier.email ?
+                        silc_pubkey->identifier.email : "");
     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                       SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
@@ -2632,7 +2616,8 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
     format = format_get_text("fe-common/silc", NULL, NULL, NULL,
                             SILCTXT_PUBKEY_ACCEPT);
     silc_keyboard_entry_redirect(verify_public_key_completion,
-                           format, 0, verify, &server->prompt_op);
+                                format, 0, verify,
+                                server ? &server->prompt_op : NULL);
     g_free(format);
     silc_free(fingerprint);
     silc_free(babbleprint);
@@ -2656,6 +2641,14 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
                           silc_pubkey->identifier.realname,
                           silc_pubkey->identifier.email ?
                           silc_pubkey->identifier.email : "");
+      else if (conn_type == SILC_CONN_CLIENT &&
+              (silc_pubkey->identifier.realname ||
+               silc_pubkey->identifier.email))
+       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+                          SILCTXT_PUBKEY_RECEIVED_CLIENT, "",
+                          silc_pubkey->identifier.realname,
+                          silc_pubkey->identifier.email ?
+                          silc_pubkey->identifier.email : "");
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
@@ -2665,7 +2658,9 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
       format = format_get_text("fe-common/silc", NULL, NULL, NULL,
                               SILCTXT_PUBKEY_ACCEPT_ANYWAY);
       silc_keyboard_entry_redirect(verify_public_key_completion,
-                             format, 0, verify, &server->prompt_op);
+                                  format, 0, verify,
+                                  server ? &server->prompt_op : NULL);
+
       g_free(format);
       silc_free(fingerprint);
       silc_free(babbleprint);
@@ -2686,6 +2681,14 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
                           silc_pubkey->identifier.realname,
                           silc_pubkey->identifier.email ?
                           silc_pubkey->identifier.email : "");
+      else if (conn_type == SILC_CONN_CLIENT &&
+              (silc_pubkey->identifier.realname ||
+               silc_pubkey->identifier.email))
+       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+                          SILCTXT_PUBKEY_RECEIVED_CLIENT, "",
+                          silc_pubkey->identifier.realname,
+                          silc_pubkey->identifier.email ?
+                          silc_pubkey->identifier.email : "");
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
@@ -2695,7 +2698,8 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
       format = format_get_text("fe-common/silc", NULL, NULL, NULL,
                               SILCTXT_PUBKEY_ACCEPT_ANYWAY);
       silc_keyboard_entry_redirect(verify_public_key_completion,
-                             format, 0, verify, &server->prompt_op);
+                                  format, 0, verify,
+                                  server ? &server->prompt_op : NULL);
       g_free(format);
       silc_free(fingerprint);
       silc_free(babbleprint);
@@ -2716,6 +2720,14 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
                           silc_pubkey->identifier.realname,
                           silc_pubkey->identifier.email ?
                           silc_pubkey->identifier.email : "");
+      else if (conn_type == SILC_CONN_CLIENT &&
+              (silc_pubkey->identifier.realname ||
+               silc_pubkey->identifier.email))
+       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+                          SILCTXT_PUBKEY_RECEIVED_CLIENT, "",
+                          silc_pubkey->identifier.realname,
+                          silc_pubkey->identifier.email ?
+                          silc_pubkey->identifier.email : "");
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
@@ -2731,7 +2743,8 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
       format = format_get_text("fe-common/silc", NULL, NULL, NULL,
                               SILCTXT_PUBKEY_ACCEPT_ANYWAY);
       silc_keyboard_entry_redirect(verify_public_key_completion,
-                             format, 0, verify, &server->prompt_op);
+                                  format, 0, verify,
+                                  server ? &server->prompt_op : NULL);
       g_free(format);
       silc_free(fingerprint);
       silc_free(babbleprint);
@@ -2740,6 +2753,21 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
       return;
     }
 
+    if (conn_type == SILC_CONN_CLIENT)
+      printformat_module("fe-common/silc", NULL, NULL,
+                        MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED_CLIENT,
+                        (name
+                         ? name
+                         : (silc_pubkey->identifier.realname
+                            ? silc_pubkey->identifier.realname
+                            : (silc_pubkey->identifier.email
+                               ? silc_pubkey->identifier.email
+                               : ""))),
+                        silc_pubkey->identifier.realname ?
+                        silc_pubkey->identifier.realname : "",
+                        silc_pubkey->identifier.email ?
+                        silc_pubkey->identifier.email : "");
+
     /* Local copy matched */
     if (completion)
       completion(TRUE, context);
@@ -2778,7 +2806,7 @@ typedef struct {
 } *AskPassphrase;
 
 void ask_passphrase_completion(const char *passphrase, void *context,
-               SilcKeyboardPromptStatus reason)
+                              SilcKeyboardPromptStatus reason)
 {
   AskPassphrase p = (AskPassphrase)context;
   if (passphrase && passphrase[0] == '\0')
@@ -2786,11 +2814,9 @@ void ask_passphrase_completion(const char *passphrase, void *context,
   p->completion((unsigned char *)passphrase,
                passphrase ? strlen(passphrase) : 0, p->context);
 
-  if (reason != KeyboardCompletionFailed)
-  {
+  if (reason != KeyboardCompletionFailed) {
     SILC_SERVER_REC *server = (SILC_SERVER_REC *)(p->conn->context);
-
-        server->prompt_op = NULL;
+    server->prompt_op = NULL;
   }
 
   silc_free(p);
@@ -2800,14 +2826,22 @@ void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
                         SilcAskPassphrase completion, void *context)
 {
   SILC_SERVER_REC *server = (SILC_SERVER_REC*)(conn->context);
-  AskPassphrase p = silc_calloc(1, sizeof(*p));
+  AskPassphrase p;
+
+  p = silc_calloc(1, sizeof(*p));
+  if (!p) {
+    if (completion)
+      completion(NULL, 0, context);
+    return;
+  }
+
   p->completion = completion;
   p->conn       = conn;
   p->context    = context;
 
   silc_keyboard_entry_redirect(ask_passphrase_completion,
-                         "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p, &server->prompt_op);
+                              "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN,
+                              p, &server->prompt_op);
 }
 
 typedef struct {
@@ -2846,7 +2880,7 @@ void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
 
   /* Check whether we find the password for this server in our
      configuration.  If it's set, always send it server. */
-  setup = server_setup_find_port(hostname, port);
+  setup = server_setup_find(hostname, port, "silcnet");
   if (setup && setup->password) {
     completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
               context);