void silcpurple_parse_attrs(SilcDList attrs, char **moodstr, char **statusstr, char **contactstr, char **langstr, char **devicestr, char **tzstr, char **geostr) { SilcAttributePayload attr; SilcAttributeMood mood = 0; SilcAttributeContact contact; SilcAttributeObjDevice device; SilcAttributeObjGeo geo; char tmp[1024]; GString *s; *moodstr = NULL; *statusstr = NULL; *contactstr = NULL; *langstr = NULL; *devicestr = NULL; *tzstr = NULL; *geostr = NULL; if (!attrs) return; s = g_string_new(""); attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_STATUS_MOOD); if (attr && silc_attribute_get_object(attr, &mood, sizeof(mood))) { if (mood & SILC_ATTRIBUTE_MOOD_HAPPY) g_string_append_printf(s, "[%s] ", _("Happy")); if (mood & SILC_ATTRIBUTE_MOOD_SAD) g_string_append_printf(s, "[%s] ", _("Sad")); if (mood & SILC_ATTRIBUTE_MOOD_ANGRY) g_string_append_printf(s, "[%s] ", _("Angry")); if (mood & SILC_ATTRIBUTE_MOOD_JEALOUS) g_string_append_printf(s, "[%s] ", _("Jealous")); if (mood & SILC_ATTRIBUTE_MOOD_ASHAMED) g_string_append_printf(s, "[%s] ", _("Ashamed")); if (mood & SILC_ATTRIBUTE_MOOD_INVINCIBLE) g_string_append_printf(s, "[%s] ", _("Invincible")); if (mood & SILC_ATTRIBUTE_MOOD_INLOVE) g_string_append_printf(s, "[%s] ", _("In Love")); if (mood & SILC_ATTRIBUTE_MOOD_SLEEPY) g_string_append_printf(s, "[%s] ", _("Sleepy")); if (mood & SILC_ATTRIBUTE_MOOD_BORED) g_string_append_printf(s, "[%s] ", _("Bored")); if (mood & SILC_ATTRIBUTE_MOOD_EXCITED) g_string_append_printf(s, "[%s] ", _("Excited")); if (mood & SILC_ATTRIBUTE_MOOD_ANXIOUS) g_string_append_printf(s, "[%s] ", _("Anxious")); } if (strlen(s->str)) { *moodstr = g_string_free(s, FALSE); g_strchomp(*moodstr); } else g_string_free(s, TRUE); attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_STATUS_FREETEXT); memset(tmp, 0, sizeof(tmp)); if (attr && silc_attribute_get_object(attr, tmp, sizeof(tmp))) *statusstr = g_strdup(tmp); s = g_string_new(""); attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_PREFERRED_CONTACT); if (attr && silc_attribute_get_object(attr, &contact, sizeof(contact))) { if (contact & SILC_ATTRIBUTE_CONTACT_CHAT) g_string_append_printf(s, "[%s] ", _("Chat")); if (contact & SILC_ATTRIBUTE_CONTACT_EMAIL) g_string_append_printf(s, "[%s] ", _("Email")); if (contact & SILC_ATTRIBUTE_CONTACT_CALL) g_string_append_printf(s, "[%s] ", _("Phone")); if (contact & SILC_ATTRIBUTE_CONTACT_PAGE) g_string_append_printf(s, "[%s] ", _("Paging")); if (contact & SILC_ATTRIBUTE_CONTACT_SMS) g_string_append_printf(s, "[%s] ", _("SMS")); if (contact & SILC_ATTRIBUTE_CONTACT_MMS) g_string_append_printf(s, "[%s] ", _("MMS")); if (contact & SILC_ATTRIBUTE_CONTACT_VIDEO) g_string_append_printf(s, "[%s] ", _("Video Conferencing")); } if (strlen(s->str)) { *contactstr = g_string_free(s, FALSE); g_strchomp(*contactstr); } else g_string_free(s, TRUE); attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_PREFERRED_LANGUAGE); memset(tmp, 0, sizeof(tmp)); if (attr && silc_attribute_get_object(attr, tmp, sizeof(tmp))) *langstr = g_strdup(tmp); s = g_string_new(""); attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_DEVICE_INFO); memset(&device, 0, sizeof(device)); if (attr && silc_attribute_get_object(attr, &device, sizeof(device))) { if (device.type == SILC_ATTRIBUTE_DEVICE_COMPUTER) g_string_append_printf(s, "%s: ", _("Computer")); if (device.type == SILC_ATTRIBUTE_DEVICE_MOBILE_PHONE) g_string_append_printf(s, "%s: ", _("Mobile Phone")); if (device.type == SILC_ATTRIBUTE_DEVICE_PDA) g_string_append_printf(s, "%s: ", _("PDA")); if (device.type == SILC_ATTRIBUTE_DEVICE_TERMINAL) g_string_append_printf(s, "%s: ", _("Terminal")); g_string_append_printf(s, "%s %s %s %s", device.manufacturer ? device.manufacturer : "", device.version ? device.version : "", device.model ? device.model : "", device.language ? device.language : ""); } if (strlen(s->str)) *devicestr = g_string_free(s, FALSE); else g_string_free(s, TRUE); attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_TIMEZONE); memset(tmp, 0, sizeof(tmp)); if (attr && silc_attribute_get_object(attr, tmp, sizeof(tmp))) *tzstr = g_strdup(tmp); attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_GEOLOCATION); memset(&geo, 0, sizeof(geo)); if (attr && silc_attribute_get_object(attr, &geo, sizeof(geo))) *geostr = g_strdup_printf("%s %s %s (%s)", geo.longitude ? geo.longitude : "", geo.latitude ? geo.latitude : "", geo.altitude ? geo.altitude : "", geo.accuracy ? geo.accuracy : ""); }
static void silcpurple_add_buddy_save(bool 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; #ifdef SILC_ATTRIBUTE_USER_ICON SilcAttributeObjMime usericon; #endif SilcAttributeObjPk serverpk, usersign, serversign; gboolean usign_success = TRUE, ssign_success = TRUE; char filename[512], filename2[512], *fingerprint = NULL, *tmp; SilcUInt32 len; int i; if (!success) { /* The user did not trust the public key. */ silcpurple_add_buddy_pk_no(r); silc_free(r); return; } if (r->offline) { /* User is offline. Associate the imported public key with this user. */ fingerprint = silc_hash_fingerprint(NULL, r->offline_pk, r->offline_pk_len); for (i = 0; i < strlen(fingerprint); i++) if (fingerprint[i] == ' ') fingerprint[i] = '_'; g_snprintf(filename, sizeof(filename) - 1, "%s" G_DIR_SEPARATOR_S "clientkeys" G_DIR_SEPARATOR_S "clientkey_%s.pub", silcpurple_silcdir(), fingerprint); purple_blist_node_set_string((PurpleBlistNode *)b, "public-key", filename); 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); silc_free(r); return; } /* Get the client entry. */ client_entry = silc_client_get_client_by_id(r->client, r->conn, &r->client_id); if (!client_entry) { 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)); /* Now that we have the public key and we trust it now we save the attributes of the buddy and update its status. */ if (client_entry->attrs) { silc_dlist_start(client_entry->attrs); while ((attr = silc_dlist_get(client_entry->attrs)) != SILC_LIST_END) { attribute = silc_attribute_get_attribute(attr); switch (attribute) { case SILC_ATTRIBUTE_USER_INFO: if (!silc_attribute_get_object(attr, (void *)&vcard, sizeof(vcard))) continue; break; case SILC_ATTRIBUTE_STATUS_MESSAGE: 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))) continue; break; #ifdef SILC_ATTRIBUTE_USER_ICON case SILC_ATTRIBUTE_USER_ICON: if (!silc_attribute_get_object(attr, (void *)&usericon, sizeof(usericon))) continue; break; #endif case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY: if (serverpk.type) continue; if (!silc_attribute_get_object(attr, (void *)&serverpk, sizeof(serverpk))) continue; break; case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE: if (usersign.data) continue; if (!silc_attribute_get_object(attr, (void *)&usersign, sizeof(usersign))) continue; break; case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE: if (serversign.data) continue; if (!silc_attribute_get_object(attr, (void *)&serversign, sizeof(serversign))) continue; break; default: break; } } } /* Verify the attribute signatures */ 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; } silc_free(verifyd); } if (serversign.data && purple_strequal(serverpk.type, "silc-rsa")) { SilcPublicKey public_key; SilcPKCS pkcs; 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); 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; } silc_pkcs_public_key_free(public_key); silc_free(verifyd); } } fingerprint = silc_fingerprint(client_entry->fingerprint, client_entry->fingerprint_len); for (i = 0; i < strlen(fingerprint); i++) if (fingerprint[i] == ' ') fingerprint[i] = '_'; if (usign_success || ssign_success) { struct passwd *pw; struct stat st; memset(filename2, 0, sizeof(filename2)); /* Filename for dir */ tmp = fingerprint + strlen(fingerprint) - 9; g_snprintf(filename, sizeof(filename) - 1, "%s" G_DIR_SEPARATOR_S "friends" G_DIR_SEPARATOR_S "%s", silcpurple_silcdir(), tmp); pw = getpwuid(getuid()); if (!pw) return; /* Create dir if it doesn't exist */ if ((g_stat(filename, &st)) == -1) { if (errno == ENOENT) { if (pw->pw_uid == geteuid()) { int ret = g_mkdir(filename, 0755); if (ret < 0) return; } } } /* Save VCard */ g_snprintf(filename2, sizeof(filename2) - 1, "%s" G_DIR_SEPARATOR_S "vcard", filename); if (vcard.full_name) { tmp = (char *)silc_vcard_encode(&vcard, &len); silc_file_writefile(filename2, tmp, len); silc_free(tmp); } /* Save status message */ if (message.mime) { 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); } /* Save extension data */ if (extension.mime) { 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); } #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 (purple_strequal(type, "image/jpeg") || purple_strequal(type, "image/gif") || purple_strequal(type, "image/bmp") || purple_strequal(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); } } silc_mime_free(m); } } #endif } /* Save the public key path to buddy properties, as it is used to identify the buddy in the network (and not the nickname). */ memset(filename, 0, sizeof(filename)); g_snprintf(filename, sizeof(filename) - 1, "%s" G_DIR_SEPARATOR_S "clientkeys" G_DIR_SEPARATOR_S "clientkey_%s.pub", silcpurple_silcdir(), fingerprint); purple_blist_node_set_string((PurpleBlistNode *)b, "public-key", filename); /* Update online status */ purple_prpl_got_user_status(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), SILCPURPLE_STATUS_ID_AVAILABLE, NULL); /* Finally, start watching this user so we receive its status changes from the server */ g_snprintf(filename2, sizeof(filename2) - 1, "+%s", filename); silc_client_command_call(r->client, r->conn, NULL, "WATCH", "-pubkey", filename2, NULL); silc_free(fingerprint); silc_free(r); }
static void silcpurple_add_buddy_resolved(SilcClient client, SilcClientConnection conn, SilcClientEntry *clients, SilcUInt32 clients_count, void *context) { SilcPurpleBuddyRes r = context; PurpleBuddy *b = r->b; SilcAttributePayload pub; SilcAttributeObjPk userpk; unsigned char *pk; SilcUInt32 pk_len; const char *filename; 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 (r->init) { silc_free(r); return; } r->offline = TRUE; /* If the user has already associated a public key, try loading it * before prompting the user to load it again */ if (filename != NULL) silcpurple_add_buddy_ask_import(r, filename); else silcpurple_add_buddy_ask_pk(r); return; } /* 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 (r->init) { silc_free(r); return; } silcpurple_add_buddy_select(r, clients, clients_count); return; } /* 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 (r->init) { /* Find the entry that closest matches to the buddy nickname. */ int i; for (i = 0; i < clients_count; i++) { if (!g_ascii_strncasecmp(b->name, clients[i]->nickname, strlen(b->name))) { clients[0] = clients[i]; break; } } } else { /* Verify from user which one is correct */ silcpurple_add_buddy_select(r, clients, clients_count); return; } } /* 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; /* 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 (!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); silc_client_command_pending(conn, SILC_COMMAND_GETKEY, conn->cmd_ident, (SilcCommandCb)silcpurple_add_buddy_getkey_cb, r); return; } if (!silc_pkcs_public_key_decode(userpk.data, userpk.data_len, &clients[0]->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)) { /* Get public key with GETKEY */ 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_add_buddy_getkey_cb, r); return; } } else if (!clients[0]->public_key) { /* Get public key with GETKEY */ 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_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); }
char *silcpurple_status_text(PurpleBuddy *b) { SilcPurple sg = b->account->gc->proto_data; SilcClient client = sg->client; SilcClientConnection conn = sg->conn; SilcClientID *client_id = b->proto_data; SilcClientEntry client_entry; SilcAttributePayload attr; SilcAttributeMood mood = 0; /* Get the client entry. */ client_entry = silc_client_get_client_by_id(client, conn, client_id); if (!client_entry) return NULL; /* If user is online, we show the mood status, if available. If user is offline or away that status is indicated. */ if (client_entry->mode & SILC_UMODE_DETACHED) return g_strdup(_("Detached")); if (client_entry->mode & SILC_UMODE_GONE) return g_strdup(_("Away")); if (client_entry->mode & SILC_UMODE_INDISPOSED) return g_strdup(_("Indisposed")); if (client_entry->mode & SILC_UMODE_BUSY) return g_strdup(_("Busy")); if (client_entry->mode & SILC_UMODE_PAGE) return g_strdup(_("Wake Me Up")); if (client_entry->mode & SILC_UMODE_HYPER) return g_strdup(_("Hyper Active")); if (client_entry->mode & SILC_UMODE_ROBOT) return g_strdup(_("Robot")); attr = silcpurple_get_attr(client_entry->attrs, SILC_ATTRIBUTE_STATUS_MOOD); if (attr && silc_attribute_get_object(attr, &mood, sizeof(mood))) { /* The mood is a bit mask, so we could show multiple moods, but let's show only one for now. */ if (mood & SILC_ATTRIBUTE_MOOD_HAPPY) return g_strdup(_("Happy")); if (mood & SILC_ATTRIBUTE_MOOD_SAD) return g_strdup(_("Sad")); if (mood & SILC_ATTRIBUTE_MOOD_ANGRY) return g_strdup(_("Angry")); if (mood & SILC_ATTRIBUTE_MOOD_JEALOUS) return g_strdup(_("Jealous")); if (mood & SILC_ATTRIBUTE_MOOD_ASHAMED) return g_strdup(_("Ashamed")); if (mood & SILC_ATTRIBUTE_MOOD_INVINCIBLE) return g_strdup(_("Invincible")); if (mood & SILC_ATTRIBUTE_MOOD_INLOVE) return g_strdup(_("In Love")); if (mood & SILC_ATTRIBUTE_MOOD_SLEEPY) return g_strdup(_("Sleepy")); if (mood & SILC_ATTRIBUTE_MOOD_BORED) return g_strdup(_("Bored")); if (mood & SILC_ATTRIBUTE_MOOD_EXCITED) return g_strdup(_("Excited")); if (mood & SILC_ATTRIBUTE_MOOD_ANXIOUS) return g_strdup(_("Anxious")); } return NULL; }
static char silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd) { SilcServer server = cmd->server; unsigned char *id_data, *umodes; char *nickname, *username, *realname, *tmp; unsigned char *fingerprint; SilcID id; SilcClientEntry client; char global = FALSE; char nick[128 + 1], servername[256 + 1], uname[128 + 1]; SilcUInt32 mode = 0, len, len2, id_len, flen; const char *hostname, *ip; silc_socket_stream_get_info(silc_packet_stream_get_stream(cmd->sock), NULL, &hostname, &ip, NULL); id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len); nickname = silc_argument_get_arg_type(cmd->args, 3, &len); username = silc_argument_get_arg_type(cmd->args, 4, &len); realname = silc_argument_get_arg_type(cmd->args, 5, &len); if (!id_data || !nickname || !username || !realname) return FALSE; tmp = silc_argument_get_arg_type(cmd->args, 7, &len); if (tmp) SILC_GET32_MSB(mode, tmp); if (!silc_id_payload_parse_id(id_data, id_len, &id)) return FALSE; fingerprint = silc_argument_get_arg_type(cmd->args, 9, &flen); /* Check if we have this client cached already. */ client = silc_idlist_find_client_by_id(server->local_list, SILC_ID_GET_ID(id), FALSE, NULL); if (!client) { client = silc_idlist_find_client_by_id(server->global_list, SILC_ID_GET_ID(id), FALSE, NULL); global = TRUE; } if (!client) { /* If router did not find such Client ID in its lists then this must be bogus client or some router in the net is buggy. */ if (server->server_type != SILC_SERVER) return FALSE; /* Take hostname out of nick string if it includes it. */ silc_parse_userfqdn(nickname, nick, sizeof(nick), servername, sizeof(servername)); /* We don't have that client anywhere, add it. The client is added to global list since server didn't have it in the lists so it must be global. This will check for valid nickname and username strings. */ client = silc_idlist_add_client(server->global_list, strdup(nick), username, strdup(realname), silc_id_dup(SILC_ID_GET_ID(id), SILC_ID_CLIENT), silc_packet_get_context(cmd->sock), NULL); if (!client) { SILC_LOG_ERROR(("Could not add new client to the ID Cache")); return FALSE; } client->data.status |= (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED); client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; client->mode = mode; client->servername = servername[0] ? strdup(servername) : NULL; SILC_LOG_DEBUG(("stat.clients %d->%d", server->stat.clients, server->stat.clients + 1)); server->stat.clients++; } else { /* We have the client already, update the data */ SILC_LOG_DEBUG(("Updating client data")); /* Check nickname */ silc_parse_userfqdn(nickname, nick, sizeof(nick), servername, sizeof(servername)); nickname = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8, 128, NULL); if (!nickname) { SILC_LOG_ERROR(("Malformed nickname '%s' received in WHOIS reply " "from %s", hostname ? hostname : "", nick)); return FALSE; } /* Check username */ silc_parse_userfqdn(username, uname, sizeof(uname), NULL, 0); if (!silc_identifier_verify(uname, strlen(uname), SILC_STRING_UTF8, 128)) { SILC_LOG_ERROR(("Malformed username '%s' received in WHOIS reply " "from %s", hostname ? hostname : "", tmp)); return FALSE; } /* Update entry */ silc_idcache_update_by_context(global ? server->global_list->clients : server->local_list->clients, client, NULL, nickname, TRUE); silc_free(client->nickname); silc_free(client->username); silc_free(client->userinfo); silc_free(client->servername); client->nickname = strdup(nick); client->username = strdup(username); client->userinfo = strdup(realname); client->servername = servername[0] ? strdup(servername) : NULL; client->mode = mode; client->data.status |= SILC_IDLIST_STATUS_RESOLVED; client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; } /* Save channel list if it was sent to us */ if (server->server_type == SILC_SERVER) { tmp = silc_argument_get_arg_type(cmd->args, 6, &len); umodes = silc_argument_get_arg_type(cmd->args, 10, &len2); if (tmp && umodes) { SilcBufferStruct channels_buf, umodes_buf; silc_buffer_set(&channels_buf, tmp, len); silc_buffer_set(&umodes_buf, umodes, len2); silc_server_save_user_channels(server, cmd->sock, client, &channels_buf, &umodes_buf); } else { silc_server_save_user_channels(server, cmd->sock, client, NULL, NULL); } } if (fingerprint && flen == sizeof(client->data.fingerprint)) memcpy(client->data.fingerprint, fingerprint, flen); /* Take Requested Attributes if set. */ tmp = silc_argument_get_arg_type(cmd->args, 11, &len); if (tmp) { silc_free(client->attrs); client->attrs = silc_memdup(tmp, len); client->attrs_len = len; /* Try to take public key from attributes if present and we don't have the key already. Do this only on normal server. Routers do GETKEY for all clients anyway. */ if (server->server_type != SILC_ROUTER && !client->data.public_key) { SilcAttributePayload attr; SilcAttributeObjPk pk; unsigned char f[SILC_HASH_MAXLEN]; SilcDList attrs = silc_attribute_payload_parse(tmp, len); SILC_LOG_DEBUG(("Take client public key from attributes")); if (attrs) { silc_dlist_start(attrs); while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) { if (silc_attribute_get_attribute(attr) == SILC_ATTRIBUTE_USER_PUBLIC_KEY) { if (!silc_attribute_get_object(attr, &pk, sizeof(pk))) continue; /* Take only SILC public keys */ if (strcmp(pk.type, "silc-rsa")) { silc_free(pk.type); silc_free(pk.data); continue; } /* Verify that the server provided fingerprint matches the key */ silc_hash_make(server->sha1hash, pk.data, pk.data_len, f); if (memcmp(f, client->data.fingerprint, sizeof(f))) { silc_free(pk.type); silc_free(pk.data); continue; } /* Save the public key. */ if (!silc_pkcs_public_key_alloc(SILC_PKCS_SILC, pk.data, pk.data_len, &client->data.public_key)) { silc_free(pk.type); silc_free(pk.data); continue; } SILC_LOG_DEBUG(("Saved client public key from attributes")); /* Add client's public key to repository */ if (!silc_server_get_public_key_by_client(server, client, NULL)) silc_skr_add_public_key_simple(server->repository, client->data.public_key, SILC_SKR_USAGE_IDENTIFICATION, client, NULL); silc_free(pk.type); silc_free(pk.data); break; } } silc_attribute_payload_list_free(attrs); } } } return TRUE; }