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. */
79 void silc_channel_message(SilcClient client, SilcClientConnection conn,
80 SilcClientEntry sender, SilcChannelEntry channel,
81 SilcMessageFlags flags, char *msg)
83 SILC_SERVER_REC *server;
85 SILC_CHANNEL_REC *chanrec;
87 server = conn == NULL ? NULL : conn->context;
88 chanrec = silc_channel_find_entry(server, channel);
92 nick = silc_nicklist_find(chanrec, sender);
94 if (flags & SILC_MESSAGE_FLAG_ACTION)
95 printformat_module("fe-common/silc", server, channel->channel_name,
96 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
97 nick == NULL ? "[<unknown>]" : nick->nick, msg);
98 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
99 printformat_module("fe-common/silc", server, channel->channel_name,
100 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
101 nick == NULL ? "[<unknown>]" : nick->nick, msg);
103 signal_emit("message public", 6, server, msg,
104 nick == NULL ? "[<unknown>]" : nick->nick,
105 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
106 chanrec->name, nick);
109 /* Private message to the client. The `sender' is the nickname of the
110 sender received in the packet. */
112 void silc_private_message(SilcClient client, SilcClientConnection conn,
113 SilcClientEntry sender, SilcMessageFlags flags,
116 SILC_SERVER_REC *server;
118 server = conn == NULL ? NULL : conn->context;
119 signal_emit("message private", 4, server, msg,
120 sender->nickname ? sender->nickname : "[<unknown>]",
121 sender->username ? sender->username : NULL);
124 /* Notify message to the client. The notify arguments are sent in the
125 same order as servers sends them. The arguments are same as received
126 from the server except for ID's. If ID is received application receives
127 the corresponding entry to the ID. For example, if Client ID is received
128 application receives SilcClientEntry. Also, if the notify type is
129 for channel the channel entry is sent to application (even if server
130 does not send it). */
137 #define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
138 static NOTIFY_REC notifies[] = {
139 { SILC_NOTIFY_TYPE_NONE, NULL },
140 { SILC_NOTIFY_TYPE_INVITE, "invite" },
141 { SILC_NOTIFY_TYPE_JOIN, "join" },
142 { SILC_NOTIFY_TYPE_LEAVE, "leave" },
143 { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" },
144 { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" },
145 { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" },
146 { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" },
147 { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" },
148 { SILC_NOTIFY_TYPE_MOTD, "motd" },
149 { SILC_NOTIFY_TYPE_CHANNEL_CHANGE, "channel_change" },
150 { SILC_NOTIFY_TYPE_SERVER_SIGNOFF, "server_signoff" },
151 { SILC_NOTIFY_TYPE_KICKED, "kick" },
152 { SILC_NOTIFY_TYPE_KILLED, "kill" },
153 { SILC_NOTIFY_TYPE_UMODE_CHANGE, "umode" },
154 { SILC_NOTIFY_TYPE_BAN, "ban" },
157 void silc_notify(SilcClient client, SilcClientConnection conn,
158 SilcNotifyType type, ...)
160 SILC_SERVER_REC *server;
163 server = conn == NULL ? NULL : conn->context;
166 if (type == SILC_NOTIFY_TYPE_NONE) {
167 /* Some generic notice from server */
168 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
169 } else if (type < MAX_NOTIFY) {
170 /* Send signal about the notify event */
172 g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name);
173 signal_emit(signal, 2, server, va);
176 printformat_module("fe-common/silc", server, NULL,
177 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
183 /* Called to indicate that connection was either successfully established
184 or connecting failed. This is also the first time application receives
185 the SilcClientConnection objecet which it should save somewhere. */
187 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
189 SILC_SERVER_REC *server = conn->context;
192 server->connected = TRUE;
193 signal_emit("event connected", 1, server);
195 server->connection_lost = TRUE;
196 server->conn->context = NULL;
197 server_disconnect(SERVER(server));
201 /* Called to indicate that connection was disconnected to the server. */
203 void silc_disconnect(SilcClient client, SilcClientConnection conn)
205 SILC_SERVER_REC *server = conn->context;
207 server->conn->context = NULL;
209 server->connection_lost = TRUE;
210 server_disconnect(SERVER(server));
213 /* Command handler. This function is called always in the command function.
214 If error occurs it will be called as well. `conn' is the associated
215 client connection. `cmd_context' is the command context that was
216 originally sent to the command. `success' is FALSE if error occured
217 during command. `command' is the command being processed. It must be
218 noted that this is not reply from server. This is merely called just
219 after application has called the command. Just to tell application
220 that the command really was processed. */
222 void 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 static 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 channel = va_arg(vp, SilcChannelEntry);
439 invite_list = va_arg(vp, char *);
442 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
443 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
446 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
447 SILCTXT_CHANNEL_NO_INVITE_LIST,
448 channel->channel_name);
452 case SILC_COMMAND_JOIN:
454 char *channel, *mode, *topic;
456 SilcChannelEntry channel_entry;
457 SilcBuffer client_id_list;
463 channel = va_arg(vp, char *);
464 channel_entry = va_arg(vp, SilcChannelEntry);
465 modei = va_arg(vp, uint32);
466 (void)va_arg(vp, uint32);
467 (void)va_arg(vp, unsigned char *);
468 (void)va_arg(vp, unsigned char *);
469 (void)va_arg(vp, unsigned char *);
470 topic = va_arg(vp, char *);
471 (void)va_arg(vp, unsigned char *);
472 list_count = va_arg(vp, uint32);
473 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,
488 channel_entry->channel_key->cipher->name,
489 channel_entry->hmac->hmac->name);
490 g_free_not_null(chanrec->mode);
491 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
492 signal_emit("channel mode changed", 1, chanrec);
494 /* Resolve the client information */
495 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
496 silc_client_join_get_users,
501 case SILC_COMMAND_NICK:
503 SilcClientEntry client = va_arg(vp, SilcClientEntry);
509 old = g_strdup(server->nick);
510 server_change_nick(SERVER(server), client->nickname);
511 nicklist_rename_unique(SERVER(server),
512 server->conn->local_entry, server->nick,
513 client, client->nickname);
515 signal_emit("message own_nick", 4, server, server->nick, old, "");
520 case SILC_COMMAND_LIST:
529 (void)va_arg(vp, SilcChannelEntry);
530 name = va_arg(vp, char *);
531 topic = va_arg(vp, char *);
532 usercount = va_arg(vp, int);
534 if (status == SILC_STATUS_LIST_START ||
535 status == SILC_STATUS_OK)
536 printformat_module("fe-common/silc", server, NULL,
537 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
539 snprintf(users, sizeof(users) - 1, "%d", usercount);
540 printformat_module("fe-common/silc", server, NULL,
541 MSGLEVEL_CRAP, SILCTXT_LIST,
542 name, users, topic ? topic : "");
546 case SILC_COMMAND_UMODE:
553 mode = va_arg(vp, uint32);
555 if (mode & SILC_UMODE_SERVER_OPERATOR)
556 printformat_module("fe-common/silc", server, NULL,
557 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
559 if (mode & SILC_UMODE_ROUTER_OPERATOR)
560 printformat_module("fe-common/silc", server, NULL,
561 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
565 case SILC_COMMAND_OPER:
569 printformat_module("fe-common/silc", server, NULL,
570 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
573 case SILC_COMMAND_SILCOPER:
577 printformat_module("fe-common/silc", server, NULL,
578 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
581 case SILC_COMMAND_USERS:
583 SilcChannelEntry channel;
589 channel = va_arg(vp, SilcChannelEntry);
591 printformat_module("fe-common/silc", server, channel->channel_name,
592 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
593 channel->channel_name);
595 silc_list_start(channel->clients);
596 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
597 SilcClientEntry e = chu->client;
600 memset(stat, 0, sizeof(stat));
601 mode = silc_client_chumode_char(chu->mode);
602 if (e->mode & SILC_UMODE_GONE)
609 printformat_module("fe-common/silc", server, channel->channel_name,
610 MSGLEVEL_CRAP, SILCTXT_USERS,
611 e->nickname, stat, e->username,
612 e->realname ? e->realname : "");
619 case SILC_COMMAND_BAN:
621 SilcChannelEntry channel;
627 channel = va_arg(vp, SilcChannelEntry);
628 ban_list = va_arg(vp, char *);
631 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
632 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
635 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
636 SILCTXT_CHANNEL_NO_BAN_LIST,
637 channel->channel_name);
641 case SILC_COMMAND_GETKEY:
645 SilcPublicKey public_key;
652 id_type = va_arg(vp, uint32);
653 entry = va_arg(vp, void *);
654 public_key = va_arg(vp, SilcPublicKey);
656 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
658 if (id_type == SILC_ID_CLIENT)
659 silc_verify_public_key_internal(client, conn, SILC_SOCKET_TYPE_CLIENT,
660 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
666 case SILC_COMMAND_TOPIC:
668 SilcChannelEntry channel;
674 channel = va_arg(vp, SilcChannelEntry);
675 topic = va_arg(vp, char *);
678 chanrec = silc_channel_find_entry(server, channel);
680 g_free_not_null(chanrec->topic);
681 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
682 signal_emit("channel topic changed", 1, chanrec);
684 printformat_module("fe-common/silc", server, channel->channel_name,
685 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
686 channel->channel_name, topic);
688 printformat_module("fe-common/silc", server, channel->channel_name,
689 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
690 channel->channel_name);
700 /* Internal routine to verify public key. If the `completion' is provided
701 it will be called to indicate whether public was verified or not. */
705 SilcClientConnection conn;
710 SilcSKEPKType pk_type;
711 SilcVerifyPublicKey completion;
715 static void verify_public_key_completion(const char *line, void *context)
717 PublicKeyVerify verify = (PublicKeyVerify)context;
719 if (line[0] == 'Y' || line[0] == 'y') {
720 /* Call the completion */
721 if (verify->completion)
722 verify->completion(TRUE, verify->context);
724 /* Save the key for future checking */
725 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
726 verify->pk_len, SILC_PKCS_FILE_PEM);
728 /* Call the completion */
729 if (verify->completion)
730 verify->completion(FALSE, verify->context);
732 printformat_module("fe-common/silc", NULL, NULL,
733 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, verify->entity);
736 silc_free(verify->filename);
737 silc_free(verify->entity);
738 silc_free(verify->pk);
743 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
744 SilcSocketType conn_type, unsigned char *pk,
745 uint32 pk_len, SilcSKEPKType pk_type,
746 SilcVerifyPublicKey completion, void *context)
749 char file[256], filename[256], *fingerprint, *format;
752 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
753 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
754 "server" : "client");
755 PublicKeyVerify verify;
757 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
758 printformat_module("fe-common/silc", NULL, NULL,
759 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
762 completion(FALSE, context);
766 pw = getpwuid(getuid());
769 completion(FALSE, context);
773 memset(filename, 0, sizeof(filename));
774 memset(file, 0, sizeof(file));
776 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
777 conn_type == SILC_SOCKET_TYPE_ROUTER) {
778 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
779 conn->sock->hostname, conn->sock->port);
780 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
781 pw->pw_dir, entity, file);
783 /* Replace all whitespaces with `_'. */
784 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
785 for (i = 0; i < strlen(fingerprint); i++)
786 if (fingerprint[i] == ' ')
787 fingerprint[i] = '_';
789 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
790 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
791 pw->pw_dir, entity, file);
792 silc_free(fingerprint);
795 /* Take fingerprint of the public key */
796 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
798 verify = silc_calloc(1, sizeof(*verify));
799 verify->client = client;
801 verify->filename = strdup(filename);
802 verify->entity = strdup(entity);
803 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
804 memcpy(verify->pk, pk, pk_len);
805 verify->pk_len = pk_len;
806 verify->pk_type = pk_type;
807 verify->completion = completion;
808 verify->context = context;
810 /* Check whether this key already exists */
811 if (stat(filename, &st) < 0) {
812 /* Key does not exist, ask user to verify the key and save it */
814 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
815 SILCTXT_PUBKEY_RECEIVED, entity);
816 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
817 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
818 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
819 SILCTXT_PUBKEY_ACCEPT);
820 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
823 silc_free(fingerprint);
826 /* The key already exists, verify it. */
827 SilcPublicKey public_key;
828 unsigned char *encpk;
831 /* Load the key file */
832 if (!silc_pkcs_load_public_key(filename, &public_key,
834 if (!silc_pkcs_load_public_key(filename, &public_key,
835 SILC_PKCS_FILE_BIN)) {
836 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
837 SILCTXT_PUBKEY_RECEIVED, entity);
838 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
839 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
840 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
841 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
842 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
843 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
844 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
847 silc_free(fingerprint);
851 /* Encode the key data */
852 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
854 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
855 SILCTXT_PUBKEY_RECEIVED, entity);
856 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
857 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
858 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
859 SILCTXT_PUBKEY_MALFORMED, entity);
860 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
861 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
862 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
865 silc_free(fingerprint);
869 /* Compare the keys */
870 if (memcmp(encpk, pk, encpk_len)) {
871 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
872 SILCTXT_PUBKEY_RECEIVED, entity);
873 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
874 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
875 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
876 SILCTXT_PUBKEY_NO_MATCH, entity);
877 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
878 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
879 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
880 SILCTXT_PUBKEY_MITM_ATTACK, entity);
882 /* Ask user to verify the key and save it */
883 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
884 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
885 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
888 silc_free(fingerprint);
892 /* Local copy matched */
894 completion(TRUE, context);
895 silc_free(fingerprint);
899 /* Verifies received public key. The `conn_type' indicates which entity
900 (server, client etc.) has sent the public key. If user decides to trust
901 the key may be saved as trusted public key for later use. The
902 `completion' must be called after the public key has been verified. */
905 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
906 SilcSocketType conn_type, unsigned char *pk,
907 uint32 pk_len, SilcSKEPKType pk_type,
908 SilcVerifyPublicKey completion, void *context)
910 silc_verify_public_key_internal(client, conn, conn_type, pk,
912 completion, context);
915 /* Asks passphrase from user on the input line. */
918 SilcAskPassphrase completion;
922 void ask_passphrase_completion(const char *passphrase, void *context)
924 AskPassphrase p = (AskPassphrase)context;
925 p->completion((unsigned char *)passphrase,
926 passphrase ? strlen(passphrase) : 0, p->context);
930 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
931 SilcAskPassphrase completion, void *context)
933 AskPassphrase p = silc_calloc(1, sizeof(*p));
934 p->completion = completion;
935 p->context = context;
937 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
938 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
941 /* Find authentication method and authentication data by hostname and
942 port. The hostname may be IP address as well. The found authentication
943 method and authentication data is returned to `auth_meth', `auth_data'
944 and `auth_data_len'. The function returns TRUE if authentication method
945 is found and FALSE if not. `conn' may be NULL. */
947 int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
948 char *hostname, uint16 port,
949 SilcProtocolAuthMeth *auth_meth,
950 unsigned char **auth_data,
951 uint32 *auth_data_len)
954 SILC_SERVER_REC *server = conn ? conn->context : NULL;
956 /* XXX must resolve from configuration whether this connection has
957 any specific authentication data */
959 *auth_meth = SILC_AUTH_NONE;
964 printformat_module("fe-common/silc", server, NULL,
965 MSGLEVEL_MODES, SILCTXT_AUTH_METH_UNRESOLVED);
971 /* Notifies application that failure packet was received. This is called
972 if there is some protocol active in the client. The `protocol' is the
973 protocol context. The `failure' is opaque pointer to the failure
974 indication. Note, that the `failure' is protocol dependant and application
975 must explicitly cast it to correct type. Usually `failure' is 32 bit
976 failure type (see protocol specs for all protocol failure types). */
978 void silc_failure(SilcClient client, SilcClientConnection conn,
979 SilcProtocol protocol, void *failure)
981 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
982 SilcSKEStatus status = (SilcSKEStatus)failure;
984 if (status == SILC_SKE_STATUS_BAD_VERSION)
985 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
986 SILCTXT_KE_BAD_VERSION);
987 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
988 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
989 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
990 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
991 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
992 SILCTXT_KE_UNKNOWN_GROUP);
993 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
994 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
995 SILCTXT_KE_UNKNOWN_CIPHER);
996 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
997 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
998 SILCTXT_KE_UNKNOWN_PKCS);
999 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1000 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1001 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1002 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1003 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1004 SILCTXT_KE_UNKNOWN_HMAC);
1005 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1006 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1007 SILCTXT_KE_INCORRECT_SIGNATURE);
1010 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1011 uint32 err = (uint32)failure;
1013 if (err == SILC_AUTH_FAILED)
1014 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1015 SILCTXT_AUTH_FAILED);
1019 /* Asks whether the user would like to perform the key agreement protocol.
1020 This is called after we have received an key agreement packet or an
1021 reply to our key agreement packet. This returns TRUE if the user wants
1022 the library to perform the key agreement protocol and FALSE if it is not
1023 desired (application may start it later by calling the function
1024 silc_client_perform_key_agreement). */
1026 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1027 SilcClientEntry client_entry, char *hostname,
1029 SilcKeyAgreementCallback *completion,
1034 /* We will just display the info on the screen and return FALSE and user
1035 will have to start the key agreement with a command. */
1038 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1041 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES,
1042 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1044 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES,
1045 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1046 client_entry->nickname, hostname, portstr);
1054 /* SILC client operations */
1055 SilcClientOperations ops = {
1057 silc_channel_message,
1058 silc_private_message,
1064 silc_get_auth_method,
1065 silc_verify_public_key,
1066 silc_ask_passphrase,