Mercurial > pidgin
diff libpurple/protocols/silc/buddy.c @ 18080:bb2e5f6ff2b4
propagate from branch 'im.pidgin.pidgin' (head 5fdf4fa0a7dcefa78c9ec2e7c25b151f1e3acf18)
to branch 'im.pidgin.pidgin.2.1.0' (head 1d53de833ec35c1899f24b60e7d79db753917c15)
author | Stu Tomlinson <stu@nosnilmot.com> |
---|---|
date | Sun, 10 Jun 2007 01:46:31 +0000 |
parents | 980a104267da |
children | 9a96d8711303 |
line wrap: on
line diff
--- a/libpurple/protocols/silc/buddy.c Fri Jun 08 13:25:28 2007 +0000 +++ b/libpurple/protocols/silc/buddy.c Sun Jun 10 01:46:31 2007 +0000 @@ -4,7 +4,7 @@ Author: Pekka Riikonen <priikone@silcnet.org> - Copyright (C) 2004 Pekka Riikonen + Copyright (C) 2004 - 2007 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 @@ -17,7 +17,7 @@ */ -#include "silcincludes.h" +#include "silc.h" #include "silcclient.h" #include "silcpurple.h" #include "wb.h" @@ -29,7 +29,7 @@ static void silcpurple_buddy_keyagr_do(PurpleConnection *gc, const char *name, - gboolean force_local); + gboolean force_local); typedef struct { char *nick; @@ -38,10 +38,10 @@ static void silcpurple_buddy_keyagr_resolved(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context) + SilcClientConnection conn, + SilcStatus status, + SilcDList clients, + void *context) { PurpleConnection *gc = client->application; SilcPurpleResolve r = context; @@ -62,21 +62,16 @@ silc_free(r); } -typedef struct { - gboolean responder; -} *SilcPurpleKeyAgr; - static void silcpurple_buddy_keyagr_cb(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry, - SilcKeyAgreementStatus status, - SilcSKEKeyMaterial *key, - void *context) + SilcClientConnection conn, + SilcClientEntry client_entry, + SilcKeyAgreementStatus status, + SilcSKEKeyMaterial key, + void *context) { PurpleConnection *gc = client->application; SilcPurple sg = gc->proto_data; - SilcPurpleKeyAgr a = context; if (!sg->conn) return; @@ -90,13 +85,13 @@ /* Set the private key for this client */ silc_client_del_private_message_key(client, conn, client_entry); silc_client_add_private_message_key_ske(client, conn, client_entry, - NULL, NULL, key, a->responder); + NULL, NULL, key); silc_ske_free_key_material(key); - + /* Open IM window */ convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, - client_entry->nickname, sg->account); + client_entry->nickname, sg->account); if (convo) { /* we don't have windows in the core anymore...but we may want to * provide some method for asking the UI to show the window @@ -104,7 +99,7 @@ */ } else { convo = purple_conversation_new(PURPLE_CONV_TYPE_IM, sg->account, - client_entry->nickname); + client_entry->nickname); } g_snprintf(tmp, sizeof(tmp), "%s [private key]", client_entry->nickname); purple_conversation_set_title(convo, tmp); @@ -113,7 +108,7 @@ case SILC_KEY_AGREEMENT_ERROR: purple_notify_error(gc, _("Key Agreement"), - _("Error occurred during key agreement"), NULL); + _("Error occurred during key agreement"), NULL); break; case SILC_KEY_AGREEMENT_FAILURE: @@ -122,53 +117,48 @@ case SILC_KEY_AGREEMENT_TIMEOUT: purple_notify_error(gc, _("Key Agreement"), - _("Timeout during key agreement"), NULL); + _("Timeout during key agreement"), NULL); break; case SILC_KEY_AGREEMENT_ABORTED: purple_notify_error(gc, _("Key Agreement"), - _("Key agreement was aborted"), NULL); + _("Key agreement was aborted"), NULL); break; case SILC_KEY_AGREEMENT_ALREADY_STARTED: purple_notify_error(gc, _("Key Agreement"), - _("Key agreement is already started"), NULL); + _("Key agreement is already started"), NULL); break; case SILC_KEY_AGREEMENT_SELF_DENIED: purple_notify_error(gc, _("Key Agreement"), - _("Key agreement cannot be started with yourself"), - NULL); + _("Key agreement cannot be started with yourself"), + NULL); break; default: break; } - - silc_free(a); } static void silcpurple_buddy_keyagr_do(PurpleConnection *gc, const char *name, - gboolean force_local) + gboolean force_local) { SilcPurple sg = gc->proto_data; - SilcClientEntry *clients; - SilcUInt32 clients_count; + SilcDList clients; + SilcClientEntry client_entry; + SilcClientConnectionParams params; char *local_ip = NULL, *remote_ip = NULL; gboolean local = TRUE; - char *nickname; - SilcPurpleKeyAgr a; + SilcSocket sock; if (!sg->conn || !name) return; - if (!silc_parse_userfqdn(name, &nickname, NULL)) - return; - /* Find client entry */ - clients = silc_client_get_clients_local(sg->client, sg->conn, nickname, name, - &clients_count); + clients = silc_client_get_clients_local(sg->client, sg->conn, name, + FALSE); if (!clients) { /* Resolve unknown user */ SilcPurpleResolve r = silc_calloc(1, sizeof(*r)); @@ -176,12 +166,14 @@ return; r->nick = g_strdup(name); r->gc = gc; - silc_client_get_clients(sg->client, sg->conn, nickname, NULL, + silc_client_get_clients(sg->client, sg->conn, name, NULL, silcpurple_buddy_keyagr_resolved, r); - silc_free(nickname); return; } + silc_socket_stream_get_info(silc_packet_stream_get_stream(sg->conn->stream), + &sock, NULL, NULL, NULL); + /* Resolve the local IP from the outgoing socket connection. We resolve it to check whether we have a private range IP address or public IP address. If we have public then we will assume that we are not behind @@ -196,14 +188,14 @@ Naturally this algorithm does not always get things right. */ - if (silc_net_check_local_by_sock(sg->conn->sock->sock, NULL, &local_ip)) { + if (silc_net_check_local_by_sock(sock, NULL, &local_ip)) { /* Check if the IP is private */ if (!force_local && silcpurple_ip_is_private(local_ip)) { local = FALSE; /* Local IP is private, resolve the remote server IP to see whether we are talking to Internet or just on LAN. */ - if (silc_net_check_host_by_sock(sg->conn->sock->sock, NULL, + if (silc_net_check_host_by_sock(sock, NULL, &remote_ip)) if (silcpurple_ip_is_private(remote_ip)) /* We assume we are in LAN. Let's provide @@ -218,19 +210,24 @@ if (local && !local_ip) local_ip = silc_net_localip(); - a = silc_calloc(1, sizeof(*a)); - if (!a) - return; - a->responder = local; + silc_dlist_start(clients); + client_entry = silc_dlist_get(clients); + + memset(¶ms, 0, sizeof(params)); + params.timeout_secs = 60; + if (local) + /* Provide connection point */ + params.local_ip = local_ip; /* Send the key agreement request */ - silc_client_send_key_agreement(sg->client, sg->conn, clients[0], - local ? local_ip : NULL, NULL, 0, 60, - silcpurple_buddy_keyagr_cb, a); + silc_client_send_key_agreement(sg->client, sg->conn, client_entry, + ¶ms, sg->public_key, + sg->private_key, + silcpurple_buddy_keyagr_cb, NULL); silc_free(local_ip); silc_free(remote_ip); - silc_free(clients); + silc_client_list_free(sg->client, sg->conn, clients); } typedef struct { @@ -244,8 +241,8 @@ static void silcpurple_buddy_keyagr_request_cb(SilcPurpleKeyAgrAsk a, gint id) { - SilcPurpleKeyAgr ai; SilcClientEntry client_entry; + SilcClientConnectionParams params; if (id != 1) goto out; @@ -255,26 +252,27 @@ &a->client_id); if (!client_entry) { purple_notify_error(a->client->application, _("Key Agreement"), - _("The remote user is not present in the network any more"), - NULL); + _("The remote user is not present in the network any more"), + NULL); goto out; } /* If the hostname was provided by the requestor perform the key agreement now. Otherwise, we will send him a request to connect to us. */ if (a->hostname) { - ai = silc_calloc(1, sizeof(*ai)); - if (!ai) - goto out; - ai->responder = FALSE; - silc_client_perform_key_agreement(a->client, a->conn, client_entry, + memset(¶ms, 0, sizeof(params)); + params.timeout_secs = 60; + silc_client_perform_key_agreement(a->client, a->conn, + client_entry, ¶ms, + a->conn->public_key, + a->conn->private_key, a->hostname, a->port, - silcpurple_buddy_keyagr_cb, ai); + silcpurple_buddy_keyagr_cb, NULL); } else { /* Send request. Force us as the point of connection since requestor did not provide the point of connection. */ silcpurple_buddy_keyagr_do(a->client->application, - client_entry->nickname, TRUE); + client_entry->nickname, TRUE); } out: @@ -283,14 +281,19 @@ } void silcpurple_buddy_keyagr_request(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry, - const char *hostname, SilcUInt16 port) + SilcClientConnection conn, + SilcClientEntry client_entry, + const char *hostname, SilcUInt16 port, + SilcUInt16 protocol) { char tmp[128], tmp2[128]; SilcPurpleKeyAgrAsk a; PurpleConnection *gc = client->application; + /* For now Pidgin don't support UDP key agreement */ + if (protocol == 1) + return; + g_snprintf(tmp, sizeof(tmp), _("Key agreement request received from %s. Would you like to " "perform the key agreement?"), client_entry->nickname); @@ -304,15 +307,15 @@ return; a->client = client; a->conn = conn; - a->client_id = *client_entry->id; + a->client_id = client_entry->id; if (hostname) a->hostname = strdup(hostname); a->port = port; purple_request_action(client->application, _("Key Agreement Request"), tmp, - hostname ? tmp2 : NULL, 1, gc->account, client_entry->nickname, - NULL, a, 2, _("Yes"), G_CALLBACK(silcpurple_buddy_keyagr_request_cb), - _("No"), G_CALLBACK(silcpurple_buddy_keyagr_request_cb)); + hostname ? tmp2 : NULL, 1, gc->account, client_entry->nickname, + NULL, a, 2, _("Yes"), G_CALLBACK(silcpurple_buddy_keyagr_request_cb), + _("No"), G_CALLBACK(silcpurple_buddy_keyagr_request_cb)); } static void @@ -333,9 +336,7 @@ PurpleBuddy *b; PurpleConnection *gc; SilcPurple sg; - char *nickname; - SilcClientEntry *clients; - SilcUInt32 clients_count; + SilcDList clients; g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); @@ -343,23 +344,16 @@ gc = purple_account_get_connection(b->account); sg = gc->proto_data; - if (!silc_parse_userfqdn(b->name, &nickname, NULL)) - return; - /* Find client entry */ clients = silc_client_get_clients_local(sg->client, sg->conn, - nickname, b->name, - &clients_count); - if (!clients) { - silc_free(nickname); + b->name, FALSE); + if (!clients) return; - } - clients[0]->prv_resp = FALSE; + silc_dlist_start(clients); silc_client_del_private_message_key(sg->client, sg->conn, - clients[0]); - silc_free(clients); - silc_free(nickname); + silc_dlist_get(clients)); + silc_client_list_free(sg->client, sg->conn, clients); } typedef struct { @@ -386,8 +380,8 @@ &p->client_id); if (!client_entry) { purple_notify_error(p->client->application, _("IM With Password"), - _("The remote user is not present in the network any more"), - NULL); + _("The remote user is not present in the network any more"), + NULL); silc_free(p); return; } @@ -398,21 +392,16 @@ silc_client_add_private_message_key(p->client, p->conn, client_entry, NULL, NULL, (unsigned char *)passphrase, - strlen(passphrase), FALSE, - client_entry->prv_resp); - if (!client_entry->prv_resp) - silc_client_send_private_message_key_request(p->client, - p->conn, - client_entry); + strlen(passphrase)); silc_free(p); } static void silcpurple_buddy_privkey_resolved(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context) + SilcClientConnection conn, + SilcStatus status, + SilcDList clients, + void *context) { char tmp[256]; @@ -434,42 +423,39 @@ silcpurple_buddy_privkey(PurpleConnection *gc, const char *name) { SilcPurple sg = gc->proto_data; - char *nickname; SilcPurplePrivkey p; - SilcClientEntry *clients; - SilcUInt32 clients_count; + SilcDList clients; + SilcClientEntry client_entry; if (!name) return; - if (!silc_parse_userfqdn(name, &nickname, NULL)) - return; /* Find client entry */ clients = silc_client_get_clients_local(sg->client, sg->conn, - nickname, name, - &clients_count); + name, FALSE); if (!clients) { - silc_client_get_clients(sg->client, sg->conn, nickname, NULL, + silc_client_get_clients(sg->client, sg->conn, name, NULL, silcpurple_buddy_privkey_resolved, g_strdup(name)); - silc_free(nickname); return; } + silc_dlist_start(clients); + client_entry = silc_dlist_get(clients); + p = silc_calloc(1, sizeof(*p)); if (!p) return; p->client = sg->client; p->conn = sg->conn; - p->client_id = *clients[0]->id; + p->client_id = client_entry->id; purple_request_input(gc, _("IM With Password"), NULL, _("Set IM Password"), NULL, FALSE, TRUE, NULL, _("OK"), G_CALLBACK(silcpurple_buddy_privkey_cb), _("Cancel"), G_CALLBACK(silcpurple_buddy_privkey_cb), gc->account, NULL, NULL, p); - silc_free(clients); - silc_free(nickname); + silc_client_list_free(sg->client, sg->conn, clients); } static void @@ -498,13 +484,21 @@ static void silcpurple_buddy_getkey(PurpleConnection *gc, const char *name); -static void -silcpurple_buddy_getkey_cb(SilcPurpleBuddyGetkey g, - SilcClientCommandReplyContext cmd) +static SilcBool +silcpurple_buddy_getkey_cb(SilcClient client, SilcClientConnection conn, + SilcCommand command, SilcStatus status, + SilcStatus error, void *context, va_list ap) { SilcClientEntry client_entry; - unsigned char *pk; - SilcUInt32 pk_len; + SilcPurpleBuddyGetkey g = context; + + if (status != SILC_STATUS_OK) { + purple_notify_error(g->client->application, _("Get Public Key"), + _("The remote user is not present in the network any more"), + NULL); + silc_free(g); + return FALSE; + } /* Get the client entry. */ client_entry = silc_client_get_client_by_id(g->client, g->conn, @@ -514,30 +508,28 @@ _("The remote user is not present in the network any more"), NULL); silc_free(g); - return; + return FALSE; } if (!client_entry->public_key) { silc_free(g); - return; + return FALSE; } /* Now verify the public key */ - pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len); silcpurple_verify_public_key(g->client, g->conn, client_entry->nickname, - SILC_SOCKET_TYPE_CLIENT, - pk, pk_len, SILC_SKE_PK_TYPE_SILC, - NULL, NULL); - silc_free(pk); + SILC_CONN_CLIENT, client_entry->public_key, + NULL, NULL); silc_free(g); + return TRUE; } static void silcpurple_buddy_getkey_resolved(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context) + SilcClientConnection conn, + SilcStatus status, + SilcDList clients, + void *context) { char tmp[256]; @@ -546,7 +538,7 @@ _("User %s is not present in the network"), (const char *)context); purple_notify_error(client->application, _("Get Public Key"), - _("Cannot fetch the public key"), tmp); + _("Cannot fetch the public key"), tmp); g_free(context); return; } @@ -561,42 +553,38 @@ SilcPurple sg = gc->proto_data; SilcClient client = sg->client; SilcClientConnection conn = sg->conn; - SilcClientEntry *clients; - SilcUInt32 clients_count; + SilcClientEntry client_entry; + SilcDList clients; SilcPurpleBuddyGetkey g; - char *nickname; + SilcUInt16 cmd_ident; if (!name) return; - if (!silc_parse_userfqdn(name, &nickname, NULL)) - return; - /* Find client entry */ - clients = silc_client_get_clients_local(client, conn, nickname, name, - &clients_count); + clients = silc_client_get_clients_local(client, conn, name, FALSE); if (!clients) { - silc_client_get_clients(client, conn, nickname, NULL, + silc_client_get_clients(client, conn, name, NULL, silcpurple_buddy_getkey_resolved, g_strdup(name)); - silc_free(nickname); return; } + silc_dlist_start(clients); + client_entry = silc_dlist_get(clients); + /* Call GETKEY */ g = silc_calloc(1, sizeof(*g)); if (!g) return; g->client = client; g->conn = conn; - g->client_id = *clients[0]->id; - silc_client_command_call(client, conn, NULL, "GETKEY", - clients[0]->nickname, NULL); - silc_client_command_pending(conn, SILC_COMMAND_GETKEY, - conn->cmd_ident, - (SilcCommandCb)silcpurple_buddy_getkey_cb, g); - silc_free(clients); - silc_free(nickname); + g->client_id = client_entry->id; + cmd_ident = silc_client_command_call(client, conn, NULL, "GETKEY", + client_entry->nickname, NULL); + silc_client_command_pending(conn, SILC_COMMAND_GETKEY, cmd_ident, + silcpurple_buddy_getkey_cb, g); + silc_client_list_free(client, conn, clients); } static void @@ -629,8 +617,7 @@ sg = gc->proto_data; pkfile = purple_blist_node_get_string(node, "public-key"); - if (!silc_pkcs_load_public_key(pkfile, &public_key, SILC_PKCS_FILE_PEM) && - !silc_pkcs_load_public_key(pkfile, &public_key, SILC_PKCS_FILE_BIN)) { + if (!silc_pkcs_load_public_key(pkfile, &public_key)) { purple_notify_error(gc, _("Show Public Key"), _("Could not load public key"), NULL); @@ -661,6 +648,7 @@ PurpleBuddy *b; unsigned char *offline_pk; SilcUInt32 offline_pk_len; + SilcPublicKey public_key; unsigned int offline : 1; unsigned int pubkey_search : 1; unsigned int init : 1; @@ -670,10 +658,10 @@ silcpurple_add_buddy_ask_pk_cb(SilcPurpleBuddyRes r, gint id); static void silcpurple_add_buddy_resolved(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context); + SilcClientConnection conn, + SilcStatus status, + SilcDList clients, + void *context); void silcpurple_get_info(PurpleConnection *gc, const char *who) { @@ -735,35 +723,38 @@ g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not trusted"), r->b->name); purple_notify_error(r->client->application, _("Add Buddy"), tmp, - _("You cannot receive buddy notifications until you " - "import his/her public key. You can use the Get Public Key " - "command to get the public key.")); + _("You cannot receive buddy notifications until you " + "import his/her public key. You can use the Get Public Key " + "command to get the public key.")); purple_prpl_got_user_status(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), SILCPURPLE_STATUS_ID_OFFLINE, NULL); } static void -silcpurple_add_buddy_save(bool success, void *context) +silcpurple_add_buddy_save(SilcBool success, void *context) { SilcPurpleBuddyRes r = context; PurpleBuddy *b = r->b; - SilcClient client = r->client; SilcClientEntry client_entry; SilcAttributePayload attr; SilcAttribute attribute; SilcVCardStruct vcard; - SilcAttributeObjMime message, extension; + SilcMime message = NULL, extension = NULL; #ifdef SILC_ATTRIBUTE_USER_ICON - SilcAttributeObjMime usericon; + SilcMime usericon = NULL; #endif SilcAttributeObjPk serverpk, usersign, serversign; gboolean usign_success = TRUE, ssign_success = TRUE; char filename[512], filename2[512], *fingerprint = NULL, *tmp; SilcUInt32 len; + SilcHash hash; int i; if (!success) { /* The user did not trust the public key. */ silcpurple_add_buddy_pk_no(r); + silc_free(r->offline_pk); + if (r->public_key) + silc_pkcs_public_key_free(r->public_key); silc_free(r); return; } @@ -783,6 +774,8 @@ purple_prpl_got_user_status(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), SILCPURPLE_STATUS_ID_OFFLINE, NULL); silc_free(fingerprint); silc_free(r->offline_pk); + if (r->public_key) + silc_pkcs_public_key_free(r->public_key); silc_free(r); return; } @@ -791,16 +784,15 @@ client_entry = silc_client_get_client_by_id(r->client, r->conn, &r->client_id); if (!client_entry) { + silc_free(r->offline_pk); + silc_pkcs_public_key_free(r->public_key); + if (r->public_key) + silc_pkcs_public_key_free(r->public_key); silc_free(r); return; } memset(&vcard, 0, sizeof(vcard)); - memset(&message, 0, sizeof(message)); - memset(&extension, 0, sizeof(extension)); -#ifdef SILC_ATTRIBUTE_USER_ICON - memset(&usericon, 0, sizeof(usericon)); -#endif memset(&serverpk, 0, sizeof(serverpk)); memset(&usersign, 0, sizeof(usersign)); memset(&serversign, 0, sizeof(serversign)); @@ -822,21 +814,24 @@ break; case SILC_ATTRIBUTE_STATUS_MESSAGE: - if (!silc_attribute_get_object(attr, (void *)&message, - sizeof(message))) + message = silc_mime_alloc(); + if (!silc_attribute_get_object(attr, (void *)message, + sizeof(*message))) continue; break; case SILC_ATTRIBUTE_EXTENSION: - if (!silc_attribute_get_object(attr, (void *)&extension, - sizeof(extension))) + extension = silc_mime_alloc(); + if (!silc_attribute_get_object(attr, (void *)extension, + sizeof(*extension))) continue; break; #ifdef SILC_ATTRIBUTE_USER_ICON case SILC_ATTRIBUTE_USER_ICON: - if (!silc_attribute_get_object(attr, (void *)&usericon, - sizeof(usericon))) + usericon = silc_mime_alloc(); + if (!silc_attribute_get_object(attr, (void *)usericon, + sizeof(*usericon))) continue; break; #endif @@ -872,50 +867,54 @@ } /* Verify the attribute signatures */ + silc_hash_alloc((const unsigned char *)"sha1", &hash); if (usersign.data) { - SilcPKCS pkcs; unsigned char *verifyd; SilcUInt32 verify_len; - silc_pkcs_alloc((unsigned char*)"rsa", &pkcs); verifyd = silc_attribute_get_verify_data(client_entry->attrs, FALSE, &verify_len); - if (verifyd && silc_pkcs_public_key_set(pkcs, client_entry->public_key)){ - if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash, - usersign.data, - usersign.data_len, - verifyd, verify_len)) - usign_success = FALSE; - } + if (verifyd && !silc_pkcs_verify(client_entry->public_key, + usersign.data, + usersign.data_len, + verifyd, verify_len, hash)) + usign_success = FALSE; silc_free(verifyd); } - if (serversign.data && !strcmp(serverpk.type, "silc-rsa")) { + if (serversign.data) { SilcPublicKey public_key; - SilcPKCS pkcs; + SilcPKCSType type = 0; unsigned char *verifyd; SilcUInt32 verify_len; - if (silc_pkcs_public_key_decode(serverpk.data, serverpk.data_len, - &public_key)) { - silc_pkcs_alloc((unsigned char *)"rsa", &pkcs); + if (!strcmp(serverpk.type, "silc-rsa")) + type = SILC_PKCS_SILC; + else if (!strcmp(serverpk.type, "ssh-rsa")) + type = SILC_PKCS_SSH2; + else if (!strcmp(serverpk.type, "x509v3-sign-rsa")) + type = SILC_PKCS_X509V3; + else if (!strcmp(serverpk.type, "pgp-sign-rsa")) + type = SILC_PKCS_OPENPGP; + + if (silc_pkcs_public_key_alloc(type, serverpk.data, + serverpk.data_len, + &public_key)) { verifyd = silc_attribute_get_verify_data(client_entry->attrs, TRUE, &verify_len); - if (verifyd && silc_pkcs_public_key_set(pkcs, public_key)) { - if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash, - serversign.data, - serversign.data_len, - verifyd, verify_len)) - ssign_success = FALSE; - } + if (verifyd && !silc_pkcs_verify(public_key, + serversign.data, + serversign.data_len, + verifyd, verify_len, + hash)) + ssign_success = FALSE; silc_pkcs_public_key_free(public_key); silc_free(verifyd); } } - fingerprint = silc_fingerprint(client_entry->fingerprint, - client_entry->fingerprint_len); + fingerprint = silc_fingerprint(client_entry->fingerprint, 20); for (i = 0; i < strlen(fingerprint); i++) if (fingerprint[i] == ' ') fingerprint[i] = '_'; @@ -954,46 +953,45 @@ } /* Save status message */ - if (message.mime) { + if (message) { memset(filename2, 0, sizeof(filename2)); g_snprintf(filename2, sizeof(filename2) - 1, "%s" G_DIR_SEPARATOR_S "status_message.mime", filename); - silc_file_writefile(filename2, (char *)message.mime, - message.mime_len); + tmp = (char *)silc_mime_get_data(message, &len); + silc_file_writefile(filename2, tmp, len); + silc_mime_free(message); } /* Save extension data */ - if (extension.mime) { + if (extension) { memset(filename2, 0, sizeof(filename2)); g_snprintf(filename2, sizeof(filename2) - 1, "%s" G_DIR_SEPARATOR_S "extension.mime", filename); - silc_file_writefile(filename2, (char *)extension.mime, - extension.mime_len); + tmp = (char *)silc_mime_get_data(extension, &len); + silc_file_writefile(filename2, tmp, len); + silc_mime_free(extension); } #ifdef SILC_ATTRIBUTE_USER_ICON /* Save user icon */ - if (usericon.mime) { - SilcMime m = silc_mime_decode(usericon.mime, - usericon.mime_len); - if (m) { - const char *type = silc_mime_get_field(m, "Content-Type"); - if (!strcmp(type, "image/jpeg") || - !strcmp(type, "image/gif") || - !strcmp(type, "image/bmp") || - !strcmp(type, "image/png")) { - const unsigned char *data; - SilcUInt32 data_len; - data = silc_mime_get_data(m, &data_len); - if (data) { - /* TODO: Check if SILC gives us something to use as the checksum instead */ - purple_buddy_icons_set_for_user(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), g_memdup(data, data_len), data_len, NULL); - } + if (usericon) { + const char *type = silc_mime_get_field(usericon, "Content-Type"); + if (type && + (!strcmp(type, "image/jpeg") || + !strcmp(type, "image/gif") || + !strcmp(type, "image/bmp") || + !strcmp(type, "image/png"))) { + const unsigned char *data; + SilcUInt32 data_len; + data = silc_mime_get_data(usericon, &data_len); + if (data) { + /* TODO: Check if SILC gives us something to use as the checksum instead */ + purple_buddy_icons_set_for_user(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), g_memdup(data, data_len), data_len, NULL); } - silc_mime_free(m); } + silc_mime_free(usericon); } #endif } @@ -1015,7 +1013,11 @@ silc_client_command_call(r->client, r->conn, NULL, "WATCH", "-pubkey", filename2, NULL); + silc_hash_free(hash); silc_free(fingerprint); + silc_free(r->offline_pk); + if (r->public_key) + silc_pkcs_public_key_free(r->public_key); silc_free(r); } @@ -1023,11 +1025,9 @@ silcpurple_add_buddy_ask_import(void *user_data, const char *name) { SilcPurpleBuddyRes r = (SilcPurpleBuddyRes)user_data; - SilcPublicKey public_key; /* Load the public key */ - if (!silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_PEM) && - !silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_BIN)) { + if (!silc_pkcs_load_public_key(name, &r->public_key)) { silcpurple_add_buddy_ask_pk_cb(r, 0); purple_notify_error(r->client->application, _("Add Buddy"), _("Could not load public key"), NULL); @@ -1035,12 +1035,10 @@ } /* Now verify the public key */ - r->offline_pk = silc_pkcs_public_key_encode(public_key, &r->offline_pk_len); + r->offline_pk = silc_pkcs_public_key_encode(r->public_key, &r->offline_pk_len); silcpurple_verify_public_key(r->client, r->conn, r->b->name, - SILC_SOCKET_TYPE_CLIENT, - r->offline_pk, r->offline_pk_len, - SILC_SKE_PK_TYPE_SILC, - silcpurple_add_buddy_save, r); + SILC_CONN_CLIENT, r->public_key, + silcpurple_add_buddy_save, r); } static void @@ -1065,9 +1063,9 @@ /* Open file selector to select the public key. */ purple_request_file(r->client->application, _("Open..."), NULL, FALSE, - G_CALLBACK(silcpurple_add_buddy_ask_import), - G_CALLBACK(silcpurple_add_buddy_ask_pk_cancel), - purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r); + G_CALLBACK(silcpurple_add_buddy_ask_import), + G_CALLBACK(silcpurple_add_buddy_ask_pk_cancel), + purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r); } @@ -1078,20 +1076,29 @@ g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not present in the network"), r->b->name); purple_request_action(r->client->application, _("Add Buddy"), tmp, - _("To add the buddy you must import his/her public key. " - "Press Import to import a public key."), 0, - purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r, 2, - _("Cancel"), G_CALLBACK(silcpurple_add_buddy_ask_pk_cb), - _("_Import..."), G_CALLBACK(silcpurple_add_buddy_ask_pk_cb)); + _("To add the buddy you must import his/her public key. " + "Press Import to import a public key."), 0, + purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r, 2, + _("Cancel"), G_CALLBACK(silcpurple_add_buddy_ask_pk_cb), + _("_Import..."), G_CALLBACK(silcpurple_add_buddy_ask_pk_cb)); } -static void -silcpurple_add_buddy_getkey_cb(SilcPurpleBuddyRes r, - SilcClientCommandReplyContext cmd) +static SilcBool +silcpurple_add_buddy_getkey_cb(SilcClient client, SilcClientConnection conn, + SilcCommand command, SilcStatus status, + SilcStatus error, void *context, va_list ap) { + SilcPurpleBuddyRes r = context; SilcClientEntry client_entry; - unsigned char *pk; - SilcUInt32 pk_len; + + if (status != SILC_STATUS_OK) { + /* The buddy is offline/nonexistent. We will require user + to associate a public key with the buddy or the buddy + cannot be added. */ + r->offline = TRUE; + silcpurple_add_buddy_ask_pk(r); + return FALSE; + } /* Get the client entry. */ client_entry = silc_client_get_client_by_id(r->client, r->conn, @@ -1102,16 +1109,14 @@ cannot be added. */ r->offline = TRUE; silcpurple_add_buddy_ask_pk(r); - return; + return FALSE; } /* Now verify the public key */ - pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len); silcpurple_verify_public_key(r->client, r->conn, client_entry->nickname, - SILC_SOCKET_TYPE_CLIENT, - pk, pk_len, SILC_SKE_PK_TYPE_SILC, - silcpurple_add_buddy_save, r); - silc_free(pk); + SILC_CONN_CLIENT, client_entry->public_key, + silcpurple_add_buddy_save, r); + return TRUE; } static void @@ -1120,6 +1125,7 @@ PurpleRequestField *f; const GList *list; SilcClientEntry client_entry; + SilcDList clients; f = purple_request_fields_get_field(fields, "list"); list = purple_request_field_list_get_selected(f); @@ -1131,7 +1137,11 @@ } client_entry = purple_request_field_list_get_data(f, list->data); - silcpurple_add_buddy_resolved(r->client, r->conn, &client_entry, 1, r); + clients = silc_dlist_init(); + silc_dlist_add(clients, client_entry); + silcpurple_add_buddy_resolved(r->client, r->conn, SILC_STATUS_OK, + clients, r); + silc_dlist_uninit(clients); } static void @@ -1143,16 +1153,14 @@ } static void -silcpurple_add_buddy_select(SilcPurpleBuddyRes r, - SilcClientEntry *clients, - SilcUInt32 clients_count) +silcpurple_add_buddy_select(SilcPurpleBuddyRes r, SilcDList clients) { PurpleRequestFields *fields; PurpleRequestFieldGroup *g; PurpleRequestField *f; char tmp[512], tmp2[128]; - int i; char *fingerprint; + SilcClientEntry client_entry; fields = purple_request_fields_new(); g = purple_request_field_group_new(NULL); @@ -1161,56 +1169,56 @@ purple_request_field_list_set_multi_select(f, FALSE); purple_request_fields_add_group(fields, g); - for (i = 0; i < clients_count; i++) { + silc_dlist_start(clients); + while ((client_entry = silc_dlist_get(clients))) { fingerprint = NULL; - if (clients[i]->fingerprint) { - fingerprint = silc_fingerprint(clients[i]->fingerprint, - clients[i]->fingerprint_len); + if (*client_entry->fingerprint) { + fingerprint = silc_fingerprint(client_entry->fingerprint, 20); g_snprintf(tmp2, sizeof(tmp2), "\n%s", fingerprint); } g_snprintf(tmp, sizeof(tmp), "%s - %s (%s@%s)%s", - clients[i]->realname, clients[i]->nickname, - clients[i]->username, clients[i]->hostname ? - clients[i]->hostname : "", + client_entry->realname, client_entry->nickname, + client_entry->username, *client_entry->hostname ? + client_entry->hostname : "", fingerprint ? tmp2 : ""); - purple_request_field_list_add(f, tmp, clients[i]); + purple_request_field_list_add(f, tmp, client_entry); silc_free(fingerprint); } purple_request_fields(r->client->application, _("Add Buddy"), - _("Select correct user"), - r->pubkey_search - ? _("More than one user was found with the same public key. Select " - "the correct user from the list to add to the buddy list.") - : _("More than one user was found with the same name. Select " - "the correct user from the list to add to the buddy list."), - fields, - _("OK"), G_CALLBACK(silcpurple_add_buddy_select_cb), - _("Cancel"), G_CALLBACK(silcpurple_add_buddy_select_cancel), - purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r); + _("Select correct user"), + r->pubkey_search + ? _("More than one user was found with the same public key. Select " + "the correct user from the list to add to the buddy list.") + : _("More than one user was found with the same name. Select " + "the correct user from the list to add to the buddy list."), + fields, + _("OK"), G_CALLBACK(silcpurple_add_buddy_select_cb), + _("Cancel"), G_CALLBACK(silcpurple_add_buddy_select_cancel), + purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r); } static void silcpurple_add_buddy_resolved(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context) + SilcClientConnection conn, + SilcStatus status, + SilcDList clients, + void *context) { SilcPurpleBuddyRes r = context; PurpleBuddy *b = r->b; SilcAttributePayload pub; SilcAttributeObjPk userpk; - unsigned char *pk; - SilcUInt32 pk_len; const char *filename; + SilcClientEntry client_entry = NULL; + SilcUInt16 cmd_ident; filename = purple_blist_node_get_string((PurpleBlistNode *)b, "public-key"); /* If the buddy is offline/nonexistent, we will require user to associate a public key with the buddy or the buddy cannot be added. */ - if (!clients_count) { + if (!clients) { if (r->init) { silc_free(r); return; @@ -1228,33 +1236,37 @@ /* If more than one client was found with nickname, we need to verify from user which one is the correct. */ - if (clients_count > 1 && !r->pubkey_search) { + if (silc_dlist_count(clients) > 1 && !r->pubkey_search) { if (r->init) { silc_free(r); return; } - silcpurple_add_buddy_select(r, clients, clients_count); + silcpurple_add_buddy_select(r, clients); return; } + silc_dlist_start(clients); + client_entry = silc_dlist_get(clients); + /* If we searched using public keys and more than one entry was found the same person is logged on multiple times. */ - if (clients_count > 1 && r->pubkey_search && b->name) { + if (silc_dlist_count(clients) > 1 && r->pubkey_search && b->name) { if (r->init) { /* Find the entry that closest matches to the buddy nickname. */ - int i; - for (i = 0; i < clients_count; i++) { - if (!strncasecmp(b->name, clients[i]->nickname, + SilcClientEntry entry; + silc_dlist_start(clients); + while ((entry = silc_dlist_get(clients))) { + if (!strncasecmp(b->name, entry->nickname, strlen(b->name))) { - clients[0] = clients[i]; + client_entry = entry; break; } } } else { /* Verify from user which one is correct */ - silcpurple_add_buddy_select(r, clients, clients_count); + silcpurple_add_buddy_select(r, clients); return; } } @@ -1262,61 +1274,60 @@ /* The client was found. Now get its public key and verify that before adding the buddy. */ memset(&userpk, 0, sizeof(userpk)); - b->proto_data = silc_memdup(clients[0]->id, sizeof(*clients[0]->id)); - r->client_id = *clients[0]->id; + b->proto_data = silc_memdup(&client_entry->id, sizeof(client_entry->id)); + r->client_id = client_entry->id; /* Get the public key from attributes, if not present then resolve it with GETKEY unless we have it cached already. */ - if (clients[0]->attrs && !clients[0]->public_key) { - pub = silcpurple_get_attr(clients[0]->attrs, - SILC_ATTRIBUTE_USER_PUBLIC_KEY); + if (client_entry->attrs && !client_entry->public_key) { + pub = silcpurple_get_attr(client_entry->attrs, + SILC_ATTRIBUTE_USER_PUBLIC_KEY); if (!pub || !silc_attribute_get_object(pub, (void *)&userpk, sizeof(userpk))) { /* Get public key with GETKEY */ - silc_client_command_call(client, conn, NULL, - "GETKEY", clients[0]->nickname, NULL); + cmd_ident = + silc_client_command_call(client, conn, NULL, + "GETKEY", client_entry->nickname, NULL); silc_client_command_pending(conn, SILC_COMMAND_GETKEY, - conn->cmd_ident, - (SilcCommandCb)silcpurple_add_buddy_getkey_cb, + cmd_ident, + silcpurple_add_buddy_getkey_cb, r); return; } - if (!silc_pkcs_public_key_decode(userpk.data, userpk.data_len, - &clients[0]->public_key)) + if (!silc_pkcs_public_key_alloc(SILC_PKCS_SILC, + userpk.data, userpk.data_len, + &client_entry->public_key)) return; silc_free(userpk.data); - } else if (filename && !clients[0]->public_key) { - if (!silc_pkcs_load_public_key(filename, &clients[0]->public_key, - SILC_PKCS_FILE_PEM) && - !silc_pkcs_load_public_key(filename, &clients[0]->public_key, - SILC_PKCS_FILE_BIN)) { + } else if (filename && !client_entry->public_key) { + if (!silc_pkcs_load_public_key(filename, &client_entry->public_key)) { /* Get public key with GETKEY */ - silc_client_command_call(client, conn, NULL, - "GETKEY", clients[0]->nickname, NULL); + cmd_ident = + silc_client_command_call(client, conn, NULL, + "GETKEY", client_entry->nickname, NULL); silc_client_command_pending(conn, SILC_COMMAND_GETKEY, - conn->cmd_ident, - (SilcCommandCb)silcpurple_add_buddy_getkey_cb, + cmd_ident, + silcpurple_add_buddy_getkey_cb, r); return; } - } else if (!clients[0]->public_key) { + } else if (!client_entry->public_key) { /* Get public key with GETKEY */ - silc_client_command_call(client, conn, NULL, - "GETKEY", clients[0]->nickname, NULL); + cmd_ident = + silc_client_command_call(client, conn, NULL, + "GETKEY", client_entry->nickname, NULL); silc_client_command_pending(conn, SILC_COMMAND_GETKEY, - conn->cmd_ident, - (SilcCommandCb)silcpurple_add_buddy_getkey_cb, + cmd_ident, + silcpurple_add_buddy_getkey_cb, r); return; } /* We have the public key, verify it. */ - pk = silc_pkcs_public_key_encode(clients[0]->public_key, &pk_len); - silcpurple_verify_public_key(client, conn, clients[0]->nickname, - SILC_SOCKET_TYPE_CLIENT, - pk, pk_len, SILC_SKE_PK_TYPE_SILC, - silcpurple_add_buddy_save, r); - silc_free(pk); + silcpurple_verify_public_key(client, conn, client_entry->nickname, + SILC_CONN_CLIENT, + client_entry->public_key, + silcpurple_add_buddy_save, r); } static void @@ -1344,10 +1355,7 @@ SilcPublicKey public_key; SilcAttributeObjPk userpk; - if (!silc_pkcs_load_public_key(filename, &public_key, - SILC_PKCS_FILE_PEM) && - !silc_pkcs_load_public_key(filename, &public_key, - SILC_PKCS_FILE_BIN)) + if (!silc_pkcs_load_public_key(filename, &public_key)) return; /* Get all attributes, and use the public key to search user */ @@ -1632,12 +1640,13 @@ sg->conn, buddy->proto_data); - if (client_entry && client_entry->send_key) { + if (client_entry && + silc_client_private_message_key_is_set(sg->client, + sg->conn, client_entry)) { act = purple_menu_action_new(_("Reset IM Key"), PURPLE_CALLBACK(silcpurple_buddy_resetkey), NULL, NULL); m = g_list_append(m, act); - } else { act = purple_menu_action_new(_("IM with Key Exchange"), PURPLE_CALLBACK(silcpurple_buddy_keyagr), @@ -1690,9 +1699,7 @@ SilcClientConnection conn = sg->conn; SilcMime mime; char type[32]; - unsigned char *icon; const char *t; - SilcAttributeObjMime obj; /* Remove */ if (!img) { @@ -1717,12 +1724,9 @@ silc_mime_add_field(mime, "Content-Type", type); silc_mime_add_data(mime, purple_imgstore_get_data(img), purple_imgstore_get_size(img)); - obj.mime = icon = silc_mime_encode(mime, &obj.mime_len); - if (obj.mime) - silc_client_attribute_add(client, conn, - SILC_ATTRIBUTE_USER_ICON, &obj, sizeof(obj)); + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_USER_ICON, mime, sizeof(*mime)); - silc_free(icon); silc_mime_free(mime); } #endif