5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "chat-protocols.h"
26 #include "servers-setup.h"
27 #include "channels-setup.h"
28 #include "silc-servers.h"
29 #include "silc-channels.h"
30 #include "silc-queries.h"
31 #include "silc-nicklist.h"
36 #include "fe-common/core/printtext.h"
37 #include "fe-common/core/fe-channels.h"
38 #include "fe-common/core/keyboard.h"
39 #include "fe-common/silc/module-formats.h"
42 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
43 SilcSocketType conn_type, unsigned char *pk,
44 uint32 pk_len, SilcSKEPKType pk_type,
45 SilcVerifyPublicKey completion, void *context);
47 void silc_say(SilcClient client, SilcClientConnection conn,
50 SILC_SERVER_REC *server;
54 server = conn == NULL ? NULL : conn->context;
57 str = g_strdup_vprintf(msg, va);
58 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
63 void silc_say_error(char *msg, ...)
69 str = g_strdup_vprintf(msg, va);
70 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
76 /* Message for a channel. The `sender' is the nickname of the sender
77 received in the packet. The `channel_name' is the name of the channel. */
80 silc_channel_message(SilcClient client, SilcClientConnection conn,
81 SilcClientEntry sender, SilcChannelEntry channel,
82 SilcMessageFlags flags, char *msg)
84 SILC_SERVER_REC *server;
86 SILC_CHANNEL_REC *chanrec;
88 server = conn == NULL ? NULL : conn->context;
89 chanrec = silc_channel_find_entry(server, channel);
91 nick = silc_nicklist_find(chanrec, sender);
93 if (flags & SILC_MESSAGE_FLAG_ACTION)
94 printformat_module("fe-common/silc", server, channel->channel_name,
95 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION, msg);
96 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
97 printformat_module("fe-common/silc", server, channel->channel_name,
98 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE, msg);
100 signal_emit("message public", 6, server, msg,
101 nick == NULL ? "[<unknown>]" : nick->nick,
102 nick == NULL ? NULL : nick->host,
103 chanrec->name, nick);
106 /* Private message to the client. The `sender' is the nickname of the
107 sender received in the packet. */
110 silc_private_message(SilcClient client, SilcClientConnection conn,
111 SilcClientEntry sender, SilcMessageFlags flags,
114 SILC_SERVER_REC *server;
116 server = conn == NULL ? NULL : conn->context;
117 signal_emit("message private", 4, server, msg,
118 sender->nickname ? sender->nickname : "[<unknown>]",
119 sender->username ? sender->username : NULL);
122 /* Notify message to the client. The notify arguments are sent in the
123 same order as servers sends them. The arguments are same as received
124 from the server except for ID's. If ID is received application receives
125 the corresponding entry to the ID. For example, if Client ID is received
126 application receives SilcClientEntry. Also, if the notify type is
127 for channel the channel entry is sent to application (even if server
128 does not send it). */
135 #define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
136 static NOTIFY_REC notifies[] = {
137 { SILC_NOTIFY_TYPE_NONE, NULL },
138 { SILC_NOTIFY_TYPE_INVITE, "invite" },
139 { SILC_NOTIFY_TYPE_JOIN, "join" },
140 { SILC_NOTIFY_TYPE_LEAVE, "leave" },
141 { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" },
142 { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" },
143 { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" },
144 { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" },
145 { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" },
146 { SILC_NOTIFY_TYPE_MOTD, "motd" },
147 { SILC_NOTIFY_TYPE_CHANNEL_CHANGE, "channel_change" },
148 { SILC_NOTIFY_TYPE_SERVER_SIGNOFF, "server_signoff" },
149 { SILC_NOTIFY_TYPE_KICKED, "kick" },
150 { SILC_NOTIFY_TYPE_KILLED, "kill" },
151 { SILC_NOTIFY_TYPE_UMODE_CHANGE, "umode" },
152 { SILC_NOTIFY_TYPE_BAN, "ban" },
155 void silc_notify(SilcClient client, SilcClientConnection conn,
156 SilcNotifyType type, ...)
158 SILC_SERVER_REC *server;
161 server = conn == NULL ? NULL : conn->context;
164 if (type == SILC_NOTIFY_TYPE_NONE) {
165 /* Some generic notice from server */
166 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
167 } else if (type < MAX_NOTIFY) {
168 /* Send signal about the notify event */
170 g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name);
171 signal_emit(signal, 2, server, va);
174 printtext(server, NULL, MSGLEVEL_CRAP, "Unknown notify type %d", type);
180 /* Called to indicate that connection was either successfully established
181 or connecting failed. This is also the first time application receives
182 the SilcClientConnection objecet which it should save somewhere. */
185 silc_connect(SilcClient client, SilcClientConnection conn, int success)
187 SILC_SERVER_REC *server = conn->context;
190 server->connected = TRUE;
191 signal_emit("event connected", 1, server);
193 server->connection_lost = TRUE;
194 server->conn->context = NULL;
195 server_disconnect(SERVER(server));
199 /* Called to indicate that connection was disconnected to the server. */
202 silc_disconnect(SilcClient client, SilcClientConnection conn)
204 SILC_SERVER_REC *server = conn->context;
206 server->conn->context = NULL;
208 server->connection_lost = TRUE;
209 server_disconnect(SERVER(server));
212 /* Command handler. This function is called always in the command function.
213 If error occurs it will be called as well. `conn' is the associated
214 client connection. `cmd_context' is the command context that was
215 originally sent to the command. `success' is FALSE if error occured
216 during command. `command' is the command being processed. It must be
217 noted that this is not reply from server. This is merely called just
218 after application has called the command. Just to tell application
219 that the command really was processed. */
222 silc_command(SilcClient client, SilcClientConnection conn,
223 SilcClientCommandContext cmd_context, int success,
228 /* Client info resolving callback when JOIN command reply is received.
229 This will cache all users on the channel. */
231 void silc_client_join_get_users(SilcClient client,
232 SilcClientConnection conn,
233 SilcClientEntry *clients,
234 uint32 clients_count,
237 SilcChannelEntry channel = (SilcChannelEntry)context;
239 SILC_SERVER_REC *server = conn->context;
240 SILC_CHANNEL_REC *chanrec;
241 SilcClientEntry founder = NULL;
247 chanrec = silc_channel_find(server, channel->channel_name);
251 silc_list_start(channel->clients);
252 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
253 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
254 founder = chu->client;
255 silc_nicklist_insert(chanrec, chu, FALSE);
258 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
259 nicklist_set_own(CHANNEL(chanrec), ownnick);
260 signal_emit("channel joined", 1, chanrec);
263 printformat_module("fe-common/silc", server, channel->channel_name,
264 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
265 channel->channel_name, chanrec->topic);
267 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
270 if (founder == conn->local_entry)
271 printformat_module("fe-common/silc",
272 server, channel->channel_name, MSGLEVEL_CRAP,
273 SILCTXT_CHANNEL_FOUNDER_YOU,
274 channel->channel_name);
276 printformat_module("fe-common/silc",
277 server, channel->channel_name, MSGLEVEL_CRAP,
278 SILCTXT_CHANNEL_FOUNDER,
279 channel->channel_name, founder->nickname);
283 /* Command reply handler. This function is called always in the command reply
284 function. If error occurs it will be called as well. Normal scenario
285 is that it will be called after the received command data has been parsed
286 and processed. The function is used to pass the received command data to
289 `conn' is the associated client connection. `cmd_payload' is the command
290 payload data received from server and it can be ignored. It is provided
291 if the application would like to re-parse the received command data,
292 however, it must be noted that the data is parsed already by the library
293 thus the payload can be ignored. `success' is FALSE if error occured.
294 In this case arguments are not sent to the application. `command' is the
295 command reply being processed. The function has variable argument list
296 and each command defines the number and type of arguments it passes to the
297 application (on error they are not sent). */
300 silc_command_reply(SilcClient client, SilcClientConnection conn,
301 SilcCommandPayload cmd_payload, int success,
302 SilcCommand command, SilcCommandStatus status, ...)
305 SILC_SERVER_REC *server = conn->context;
306 SILC_CHANNEL_REC *chanrec;
309 va_start(vp, status);
312 case SILC_COMMAND_WHOIS:
314 char buf[1024], *nickname, *username, *realname;
318 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
319 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
321 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
324 silc_say_error("%s: %s", tmp,
325 silc_client_command_status_message(status));
327 silc_say_error("%s", silc_client_command_status_message(status));
334 (void)va_arg(vp, SilcClientEntry);
335 nickname = va_arg(vp, char *);
336 username = va_arg(vp, char *);
337 realname = va_arg(vp, char *);
338 channels = va_arg(vp, SilcBuffer);
339 mode = va_arg(vp, uint32);
340 idle = va_arg(vp, uint32);
342 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
343 SILCTXT_WHOIS_USERINFO, nickname, username,
347 SilcDList list = silc_channel_payload_parse_list(channels);
349 SilcChannelPayload entry;
350 memset(buf, 0, sizeof(buf));
351 silc_dlist_start(list);
352 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
353 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
355 char *name = silc_channel_get_name(entry, &name_len);
358 strncat(buf, m, strlen(m));
359 strncat(buf, name, name_len);
360 strncat(buf, " ", 1);
364 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
365 SILCTXT_WHOIS_CHANNELS, buf);
366 silc_channel_payload_list_free(list);
371 memset(buf, 0, sizeof(buf));
373 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
374 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
375 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
377 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
378 "SILC Operator " : "[Unknown mode] ");
380 if (mode & SILC_UMODE_GONE)
383 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
384 SILCTXT_WHOIS_MODES, buf);
387 if (idle && nickname) {
388 memset(buf, 0, sizeof(buf));
389 snprintf(buf, sizeof(buf) - 1, "%lu %s",
390 idle > 60 ? (idle / 60) : idle,
391 idle > 60 ? "minutes" : "seconds");
393 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
394 SILCTXT_WHOIS_IDLE, buf);
399 case SILC_COMMAND_WHOWAS:
401 char *nickname, *username, *realname;
403 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
404 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
406 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
409 silc_say_error("%s: %s", tmp,
410 silc_client_command_status_message(status));
412 silc_say_error("%s", silc_client_command_status_message(status));
419 (void)va_arg(vp, SilcClientEntry);
420 nickname = va_arg(vp, char *);
421 username = va_arg(vp, char *);
422 realname = va_arg(vp, char *);
424 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
425 SILCTXT_WHOWAS_USERINFO, nickname, username,
426 realname ? realname : "");
430 case SILC_COMMAND_INVITE:
432 SilcChannelEntry channel;
438 /* XXX should use irssi routines */
440 channel = va_arg(vp, SilcChannelEntry);
441 invite_list = va_arg(vp, char *);
444 silc_say(client, conn, "%s invite list: %s", channel->channel_name,
447 silc_say(client, conn, "%s invite list not set",
448 channel->channel_name);
452 case SILC_COMMAND_JOIN:
454 char *channel, *mode, *topic;
456 SilcChannelEntry channel_entry;
457 SilcBuffer client_id_list;
460 channel = va_arg(vp, char *);
461 channel_entry = va_arg(vp, SilcChannelEntry);
462 modei = va_arg(vp, uint32);
463 (void)va_arg(vp, uint32);
464 (void)va_arg(vp, unsigned char *);
465 (void)va_arg(vp, unsigned char *);
466 (void)va_arg(vp, unsigned char *);
467 topic = va_arg(vp, char *);
468 (void)va_arg(vp, unsigned char *);
469 list_count = va_arg(vp, uint32);
470 client_id_list = va_arg(vp, SilcBuffer);
475 chanrec = silc_channel_find(server, channel);
476 if (chanrec != NULL && !success)
477 channel_destroy(CHANNEL(chanrec));
478 else if (chanrec == NULL && success)
479 chanrec = silc_channel_create(server, channel, TRUE);
482 g_free_not_null(chanrec->topic);
483 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
484 signal_emit("channel topic changed", 1, chanrec);
487 mode = silc_client_chmode(modei, channel_entry);
488 g_free_not_null(chanrec->mode);
489 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
490 signal_emit("channel mode changed", 1, chanrec);
492 /* Resolve the client information */
493 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
494 silc_client_join_get_users,
499 case SILC_COMMAND_NICK:
501 SilcClientEntry client = va_arg(vp, SilcClientEntry);
507 old = g_strdup(server->nick);
508 server_change_nick(SERVER(server), client->nickname);
509 nicklist_rename_unique(SERVER(server),
510 server->conn->local_entry, server->nick,
511 client, client->nickname);
513 signal_emit("message own_nick", 4, server, server->nick, old, "");
518 case SILC_COMMAND_LIST:
527 (void)va_arg(vp, SilcChannelEntry);
528 name = va_arg(vp, char *);
529 topic = va_arg(vp, char *);
530 usercount = va_arg(vp, int);
532 if (status == SILC_STATUS_LIST_START ||
533 status == SILC_STATUS_OK)
534 printformat_module("fe-common/silc", server, NULL,
535 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
537 snprintf(users, sizeof(users) - 1, "%d", usercount);
538 printformat_module("fe-common/silc", server, NULL,
539 MSGLEVEL_CRAP, SILCTXT_LIST,
540 name, users, topic ? topic : "");
544 case SILC_COMMAND_UMODE:
551 mode = va_arg(vp, uint32);
557 case SILC_COMMAND_OPER:
558 printformat_module("fe-common/silc", server, NULL,
559 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
562 case SILC_COMMAND_SILCOPER:
563 printformat_module("fe-common/silc", server, NULL,
564 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
567 case SILC_COMMAND_USERS:
569 SilcChannelEntry channel;
575 channel = va_arg(vp, SilcChannelEntry);
577 printformat_module("fe-common/silc", server, channel->channel_name,
578 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
579 channel->channel_name);
581 silc_list_start(channel->clients);
582 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
583 SilcClientEntry e = chu->client;
586 memset(stat, 0, sizeof(stat));
587 mode = silc_client_chumode_char(chu->mode);
588 if (e->mode & SILC_UMODE_GONE)
595 printformat_module("fe-common/silc", server, channel->channel_name,
596 MSGLEVEL_CRAP, SILCTXT_USERS,
597 e->nickname, stat, e->username,
598 e->realname ? e->realname : "");
605 case SILC_COMMAND_BAN:
607 SilcChannelEntry channel;
613 /* XXX should use irssi routines */
615 channel = va_arg(vp, SilcChannelEntry);
616 ban_list = va_arg(vp, char *);
619 silc_say(client, conn, "%s ban list: %s", channel->channel_name,
622 silc_say(client, conn, "%s ban list not set", channel->channel_name);
626 case SILC_COMMAND_GETKEY:
630 SilcPublicKey public_key;
634 id_type = va_arg(vp, uint32);
635 entry = va_arg(vp, void *);
636 public_key = va_arg(vp, SilcPublicKey);
638 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
640 if (id_type == SILC_ID_CLIENT) {
641 silc_verify_public_key_internal(client, conn, SILC_SOCKET_TYPE_CLIENT,
642 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
649 case SILC_COMMAND_TOPIC:
651 SilcChannelEntry channel;
657 channel = va_arg(vp, SilcChannelEntry);
658 topic = va_arg(vp, char *);
661 chanrec = silc_channel_find_entry(server, channel);
663 g_free_not_null(chanrec->topic);
664 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
665 signal_emit("channel topic changed", 1, chanrec);
667 printformat_module("fe-common/silc", server, channel->channel_name,
668 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
669 channel->channel_name, topic);
678 /* Internal routine to verify public key. If the `completion' is provided
679 it will be called to indicate whether public was verified or not. */
683 SilcClientConnection conn;
688 SilcSKEPKType pk_type;
689 SilcVerifyPublicKey completion;
693 static void verify_public_key_completion(const char *line, void *context)
695 PublicKeyVerify verify = (PublicKeyVerify)context;
697 if (line[0] == 'Y' || line[0] == 'y') {
698 /* Call the completion */
699 if (verify->completion)
700 verify->completion(TRUE, verify->context);
702 /* Save the key for future checking */
703 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
704 verify->pk_len, SILC_PKCS_FILE_PEM);
706 /* Call the completion */
707 if (verify->completion)
708 verify->completion(FALSE, verify->context);
710 silc_say(verify->client,
711 verify->conn, "Will not accept the %s key", verify->entity);
714 silc_free(verify->filename);
715 silc_free(verify->entity);
720 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
721 SilcSocketType conn_type, unsigned char *pk,
722 uint32 pk_len, SilcSKEPKType pk_type,
723 SilcVerifyPublicKey completion, void *context)
726 char file[256], filename[256], *fingerprint;
729 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
730 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
731 "server" : "client");
732 PublicKeyVerify verify;
734 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
735 silc_say(client, conn, "We don't support %s public key type %d",
738 completion(FALSE, context);
742 pw = getpwuid(getuid());
745 completion(FALSE, context);
749 memset(filename, 0, sizeof(filename));
750 memset(file, 0, sizeof(file));
752 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
753 conn_type == SILC_SOCKET_TYPE_ROUTER) {
754 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
755 conn->sock->hostname, conn->sock->port);
756 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
757 pw->pw_dir, entity, file);
759 /* Replace all whitespaces with `_'. */
760 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
761 for (i = 0; i < strlen(fingerprint); i++)
762 if (fingerprint[i] == ' ')
763 fingerprint[i] = '_';
765 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
766 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
767 pw->pw_dir, entity, file);
768 silc_free(fingerprint);
771 /* Take fingerprint of the public key */
772 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
774 verify = silc_calloc(1, sizeof(*verify));
775 verify->client = client;
777 verify->filename = strdup(filename);
778 verify->entity = strdup(entity);
780 verify->pk_len = pk_len;
781 verify->pk_type = pk_type;
782 verify->completion = completion;
783 verify->context = context;
785 /* Check whether this key already exists */
786 if (stat(filename, &st) < 0) {
787 /* Key does not exist, ask user to verify the key and save it */
789 silc_say(client, conn, "Received %s public key", entity);
790 silc_say(client, conn, "Fingerprint for the %s key is", entity);
791 silc_say(client, conn, "%s", fingerprint);
793 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
794 "Would you like to accept the key (y/n)? ", 0,
796 silc_free(fingerprint);
799 /* The key already exists, verify it. */
800 SilcPublicKey public_key;
801 unsigned char *encpk;
804 /* Load the key file */
805 if (!silc_pkcs_load_public_key(filename, &public_key,
807 if (!silc_pkcs_load_public_key(filename, &public_key,
808 SILC_PKCS_FILE_BIN)) {
809 silc_say(client, conn, "Received %s public key", entity);
810 silc_say(client, conn, "Fingerprint for the %s key is", entity);
811 silc_say(client, conn, "%s", fingerprint);
812 silc_say(client, conn, "Could not load your local copy of the %s key",
814 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
815 "Would you like to accept the key "
818 silc_free(fingerprint);
822 /* Encode the key data */
823 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
825 silc_say(client, conn, "Received %s public key", entity);
826 silc_say(client, conn, "Fingerprint for the %s key is", entity);
827 silc_say(client, conn, "%s", fingerprint);
828 silc_say(client, conn, "Your local copy of the %s key is malformed",
830 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
831 "Would you like to accept the key "
834 silc_free(fingerprint);
838 /* Compare the keys */
839 if (memcmp(encpk, pk, encpk_len)) {
840 silc_say(client, conn, "Received %s public key", entity);
841 silc_say(client, conn, "Fingerprint for the %s key is", entity);
842 silc_say(client, conn, "%s", fingerprint);
843 silc_say(client, conn, "%s key does not match with your local copy",
845 silc_say(client, conn,
846 "It is possible that the key has expired or changed");
847 silc_say(client, conn, "It is also possible that some one is performing "
848 "man-in-the-middle attack");
850 /* Ask user to verify the key and save it */
851 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
852 "Would you like to accept the key "
855 silc_free(fingerprint);
859 /* Local copy matched */
861 completion(TRUE, context);
862 silc_free(fingerprint);
866 /* Verifies received public key. The `conn_type' indicates which entity
867 (server, client etc.) has sent the public key. If user decides to trust
868 the key may be saved as trusted public key for later use. The
869 `completion' must be called after the public key has been verified. */
872 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
873 SilcSocketType conn_type, unsigned char *pk,
874 uint32 pk_len, SilcSKEPKType pk_type,
875 SilcVerifyPublicKey completion, void *context)
877 silc_verify_public_key_internal(client, conn, conn_type, pk,
879 completion, context);
882 /* Asks passphrase from user on the input line. */
885 SilcAskPassphrase completion;
889 void ask_passphrase_completion(const char *passphrase, void *context)
891 AskPassphrase p = (AskPassphrase)context;
892 p->completion((unsigned char *)passphrase,
893 passphrase ? strlen(passphrase) : 0, p->context);
897 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
898 SilcAskPassphrase completion, void *context)
900 AskPassphrase p = silc_calloc(1, sizeof(*p));
901 p->completion = completion;
902 p->context = context;
904 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
905 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
908 /* Find authentication method and authentication data by hostname and
909 port. The hostname may be IP address as well. The found authentication
910 method and authentication data is returned to `auth_meth', `auth_data'
911 and `auth_data_len'. The function returns TRUE if authentication method
912 is found and FALSE if not. `conn' may be NULL. */
914 int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
915 char *hostname, uint16 port,
916 SilcProtocolAuthMeth *auth_meth,
917 unsigned char **auth_data,
918 uint32 *auth_data_len)
921 /* XXX must resolve from configuration whether this connection has
922 any specific authentication data */
924 *auth_meth = SILC_AUTH_NONE;
931 /* Notifies application that failure packet was received. This is called
932 if there is some protocol active in the client. The `protocol' is the
933 protocol context. The `failure' is opaque pointer to the failure
934 indication. Note, that the `failure' is protocol dependant and application
935 must explicitly cast it to correct type. Usually `failure' is 32 bit
936 failure type (see protocol specs for all protocol failure types). */
939 silc_failure(SilcClient client, SilcClientConnection conn,
940 SilcProtocol protocol, void *failure)
942 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
943 SilcSKEStatus status = (SilcSKEStatus)failure;
945 if (status == SILC_SKE_STATUS_BAD_VERSION)
946 silc_say_error("You are running incompatible client version (it may be "
947 "too old or too new)");
948 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
949 silc_say_error("Server does not support your public key type");
950 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
951 silc_say_error("Server does not support one of your proposed KE group");
952 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
953 silc_say_error("Server does not support one of your proposed cipher");
954 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
955 silc_say_error("Server does not support one of your proposed PKCS");
956 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
957 silc_say_error("Server does not support one of your proposed "
959 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
960 silc_say_error("Server does not support one of your proposed HMAC");
961 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
962 silc_say_error("Incorrect signature");
965 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
966 uint32 err = (uint32)failure;
968 if (err == SILC_AUTH_FAILED)
969 silc_say(client, conn, "Authentication failed");
973 /* Asks whether the user would like to perform the key agreement protocol.
974 This is called after we have received an key agreement packet or an
975 reply to our key agreement packet. This returns TRUE if the user wants
976 the library to perform the key agreement protocol and FALSE if it is not
977 desired (application may start it later by calling the function
978 silc_client_perform_key_agreement). */
980 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
981 SilcClientEntry client_entry, char *hostname,
983 SilcKeyAgreementCallback *completion,
988 /* We will just display the info on the screen and return FALSE and user
989 will have to start the key agreement with a command. */
992 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
995 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES,
996 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
998 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES,
999 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1000 client_entry->nickname, hostname, portstr);
1008 /* SILC client operations */
1009 SilcClientOperations ops = {
1011 silc_channel_message,
1012 silc_private_message,
1018 silc_get_auth_method,
1019 silc_verify_public_key,
1020 silc_ask_passphrase,