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,
48 SilcClientMessageType type, char *msg, ...)
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,
226 SILC_SERVER_REC *server = conn->context;
232 case SILC_COMMAND_INVITE:
233 printformat_module("fe-common/silc", server, NULL,
234 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
235 cmd_context->argv[2],
236 (cmd_context->argv[1][0] == '*' ?
237 (char *)conn->current_channel->channel_name :
238 (char *)cmd_context->argv[1]));
245 /* Client info resolving callback when JOIN command reply is received.
246 This will cache all users on the channel. */
248 static void silc_client_join_get_users(SilcClient client,
249 SilcClientConnection conn,
250 SilcClientEntry *clients,
251 uint32 clients_count,
254 SilcChannelEntry channel = (SilcChannelEntry)context;
256 SILC_SERVER_REC *server = conn->context;
257 SILC_CHANNEL_REC *chanrec;
258 SilcClientEntry founder = NULL;
264 chanrec = silc_channel_find(server, channel->channel_name);
268 silc_list_start(channel->clients);
269 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
270 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
271 founder = chu->client;
272 silc_nicklist_insert(chanrec, chu, FALSE);
275 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
276 nicklist_set_own(CHANNEL(chanrec), ownnick);
277 signal_emit("channel joined", 1, chanrec);
280 printformat_module("fe-common/silc", server, channel->channel_name,
281 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
282 channel->channel_name, chanrec->topic);
284 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
287 if (founder == conn->local_entry)
288 printformat_module("fe-common/silc",
289 server, channel->channel_name, MSGLEVEL_CRAP,
290 SILCTXT_CHANNEL_FOUNDER_YOU,
291 channel->channel_name);
293 printformat_module("fe-common/silc",
294 server, channel->channel_name, MSGLEVEL_CRAP,
295 SILCTXT_CHANNEL_FOUNDER,
296 channel->channel_name, founder->nickname);
300 /* Command reply handler. This function is called always in the command reply
301 function. If error occurs it will be called as well. Normal scenario
302 is that it will be called after the received command data has been parsed
303 and processed. The function is used to pass the received command data to
306 `conn' is the associated client connection. `cmd_payload' is the command
307 payload data received from server and it can be ignored. It is provided
308 if the application would like to re-parse the received command data,
309 however, it must be noted that the data is parsed already by the library
310 thus the payload can be ignored. `success' is FALSE if error occured.
311 In this case arguments are not sent to the application. `command' is the
312 command reply being processed. The function has variable argument list
313 and each command defines the number and type of arguments it passes to the
314 application (on error they are not sent). */
317 silc_command_reply(SilcClient client, SilcClientConnection conn,
318 SilcCommandPayload cmd_payload, int success,
319 SilcCommand command, SilcCommandStatus status, ...)
322 SILC_SERVER_REC *server = conn->context;
323 SILC_CHANNEL_REC *chanrec;
326 va_start(vp, status);
329 case SILC_COMMAND_WHOIS:
331 char buf[1024], *nickname, *username, *realname;
335 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
336 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
338 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
341 silc_say_error("%s: %s", tmp,
342 silc_client_command_status_message(status));
344 silc_say_error("%s", silc_client_command_status_message(status));
351 (void)va_arg(vp, SilcClientEntry);
352 nickname = va_arg(vp, char *);
353 username = va_arg(vp, char *);
354 realname = va_arg(vp, char *);
355 channels = va_arg(vp, SilcBuffer);
356 mode = va_arg(vp, uint32);
357 idle = va_arg(vp, uint32);
359 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
360 SILCTXT_WHOIS_USERINFO, nickname, username,
364 SilcDList list = silc_channel_payload_parse_list(channels);
366 SilcChannelPayload entry;
367 memset(buf, 0, sizeof(buf));
368 silc_dlist_start(list);
369 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
370 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
372 char *name = silc_channel_get_name(entry, &name_len);
375 strncat(buf, m, strlen(m));
376 strncat(buf, name, name_len);
377 strncat(buf, " ", 1);
381 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
382 SILCTXT_WHOIS_CHANNELS, buf);
383 silc_channel_payload_list_free(list);
388 memset(buf, 0, sizeof(buf));
390 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
391 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
392 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
394 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
395 "SILC Operator " : "[Unknown mode] ");
397 if (mode & SILC_UMODE_GONE)
400 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
401 SILCTXT_WHOIS_MODES, buf);
404 if (idle && nickname) {
405 memset(buf, 0, sizeof(buf));
406 snprintf(buf, sizeof(buf) - 1, "%lu %s",
407 idle > 60 ? (idle / 60) : idle,
408 idle > 60 ? "minutes" : "seconds");
410 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
411 SILCTXT_WHOIS_IDLE, buf);
416 case SILC_COMMAND_WHOWAS:
418 char *nickname, *username, *realname;
420 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
421 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
423 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
426 silc_say_error("%s: %s", tmp,
427 silc_client_command_status_message(status));
429 silc_say_error("%s", silc_client_command_status_message(status));
436 (void)va_arg(vp, SilcClientEntry);
437 nickname = va_arg(vp, char *);
438 username = va_arg(vp, char *);
439 realname = va_arg(vp, char *);
441 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
442 SILCTXT_WHOWAS_USERINFO, nickname, username,
443 realname ? realname : "");
447 case SILC_COMMAND_INVITE:
449 SilcChannelEntry channel;
451 SilcArgumentPayload args;
457 channel = va_arg(vp, SilcChannelEntry);
458 invite_list = va_arg(vp, char *);
460 args = silc_command_get_args(cmd_payload);
462 argc = silc_argument_get_arg_num(args);
465 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
466 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
469 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
470 SILCTXT_CHANNEL_NO_INVITE_LIST,
471 channel->channel_name);
475 case SILC_COMMAND_JOIN:
477 char *channel, *mode, *topic;
479 SilcChannelEntry channel_entry;
480 SilcBuffer client_id_list;
486 channel = va_arg(vp, char *);
487 channel_entry = va_arg(vp, SilcChannelEntry);
488 modei = va_arg(vp, uint32);
489 (void)va_arg(vp, uint32);
490 (void)va_arg(vp, unsigned char *);
491 (void)va_arg(vp, unsigned char *);
492 (void)va_arg(vp, unsigned char *);
493 topic = va_arg(vp, char *);
494 (void)va_arg(vp, unsigned char *);
495 list_count = va_arg(vp, uint32);
496 client_id_list = va_arg(vp, SilcBuffer);
498 chanrec = silc_channel_find(server, channel);
500 chanrec = silc_channel_create(server, channel, TRUE);
503 g_free_not_null(chanrec->topic);
504 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
505 signal_emit("channel topic changed", 1, chanrec);
508 mode = silc_client_chmode(modei,
509 channel_entry->channel_key->cipher->name,
510 channel_entry->hmac->hmac->name);
511 g_free_not_null(chanrec->mode);
512 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
513 signal_emit("channel mode changed", 1, chanrec);
515 /* Resolve the client information */
516 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
517 silc_client_join_get_users,
522 case SILC_COMMAND_NICK:
524 SilcClientEntry client = va_arg(vp, SilcClientEntry);
530 old = g_strdup(server->nick);
531 server_change_nick(SERVER(server), client->nickname);
532 nicklist_rename_unique(SERVER(server),
533 server->conn->local_entry, server->nick,
534 client, client->nickname);
536 signal_emit("message own_nick", 4, server, server->nick, old, "");
541 case SILC_COMMAND_LIST:
550 (void)va_arg(vp, SilcChannelEntry);
551 name = va_arg(vp, char *);
552 topic = va_arg(vp, char *);
553 usercount = va_arg(vp, int);
555 if (status == SILC_STATUS_LIST_START ||
556 status == SILC_STATUS_OK)
557 printformat_module("fe-common/silc", server, NULL,
558 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
560 snprintf(users, sizeof(users) - 1, "%d", usercount);
561 printformat_module("fe-common/silc", server, NULL,
562 MSGLEVEL_CRAP, SILCTXT_LIST,
563 name, users, topic ? topic : "");
567 case SILC_COMMAND_UMODE:
574 mode = va_arg(vp, uint32);
576 if (mode & SILC_UMODE_SERVER_OPERATOR)
577 printformat_module("fe-common/silc", server, NULL,
578 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
580 if (mode & SILC_UMODE_ROUTER_OPERATOR)
581 printformat_module("fe-common/silc", server, NULL,
582 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
586 case SILC_COMMAND_OPER:
590 printformat_module("fe-common/silc", server, NULL,
591 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
594 case SILC_COMMAND_SILCOPER:
598 printformat_module("fe-common/silc", server, NULL,
599 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
602 case SILC_COMMAND_USERS:
604 SilcChannelEntry channel;
610 channel = va_arg(vp, SilcChannelEntry);
612 printformat_module("fe-common/silc", server, channel->channel_name,
613 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
614 channel->channel_name);
616 silc_list_start(channel->clients);
617 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
618 SilcClientEntry e = chu->client;
621 memset(stat, 0, sizeof(stat));
622 mode = silc_client_chumode_char(chu->mode);
623 if (e->mode & SILC_UMODE_GONE)
630 printformat_module("fe-common/silc", server, channel->channel_name,
631 MSGLEVEL_CRAP, SILCTXT_USERS,
632 e->nickname, stat, e->username,
633 e->realname ? e->realname : "");
640 case SILC_COMMAND_BAN:
642 SilcChannelEntry channel;
648 channel = va_arg(vp, SilcChannelEntry);
649 ban_list = va_arg(vp, char *);
652 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
653 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
656 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
657 SILCTXT_CHANNEL_NO_BAN_LIST,
658 channel->channel_name);
662 case SILC_COMMAND_GETKEY:
666 SilcPublicKey public_key;
673 id_type = va_arg(vp, uint32);
674 entry = va_arg(vp, void *);
675 public_key = va_arg(vp, SilcPublicKey);
677 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
679 if (id_type == SILC_ID_CLIENT)
680 silc_verify_public_key_internal(client, conn, SILC_SOCKET_TYPE_CLIENT,
681 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
687 case SILC_COMMAND_TOPIC:
689 SilcChannelEntry channel;
695 channel = va_arg(vp, SilcChannelEntry);
696 topic = va_arg(vp, char *);
699 chanrec = silc_channel_find_entry(server, channel);
701 g_free_not_null(chanrec->topic);
702 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
703 signal_emit("channel topic changed", 1, chanrec);
705 printformat_module("fe-common/silc", server, channel->channel_name,
706 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
707 channel->channel_name, topic);
709 printformat_module("fe-common/silc", server, channel->channel_name,
710 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
711 channel->channel_name);
721 /* Internal routine to verify public key. If the `completion' is provided
722 it will be called to indicate whether public was verified or not. */
726 SilcClientConnection conn;
731 SilcSKEPKType pk_type;
732 SilcVerifyPublicKey completion;
736 static void verify_public_key_completion(const char *line, void *context)
738 PublicKeyVerify verify = (PublicKeyVerify)context;
740 if (line[0] == 'Y' || line[0] == 'y') {
741 /* Call the completion */
742 if (verify->completion)
743 verify->completion(TRUE, verify->context);
745 /* Save the key for future checking */
746 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
747 verify->pk_len, SILC_PKCS_FILE_PEM);
749 /* Call the completion */
750 if (verify->completion)
751 verify->completion(FALSE, verify->context);
753 printformat_module("fe-common/silc", NULL, NULL,
754 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, verify->entity);
757 silc_free(verify->filename);
758 silc_free(verify->entity);
759 silc_free(verify->pk);
764 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
765 SilcSocketType conn_type, unsigned char *pk,
766 uint32 pk_len, SilcSKEPKType pk_type,
767 SilcVerifyPublicKey completion, void *context)
770 char file[256], filename[256], *fingerprint, *format;
773 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
774 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
775 "server" : "client");
776 PublicKeyVerify verify;
778 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
779 printformat_module("fe-common/silc", NULL, NULL,
780 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
783 completion(FALSE, context);
787 pw = getpwuid(getuid());
790 completion(FALSE, context);
794 memset(filename, 0, sizeof(filename));
795 memset(file, 0, sizeof(file));
797 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
798 conn_type == SILC_SOCKET_TYPE_ROUTER) {
799 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
800 conn->sock->hostname, conn->sock->port);
801 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
802 pw->pw_dir, entity, file);
804 /* Replace all whitespaces with `_'. */
805 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
806 for (i = 0; i < strlen(fingerprint); i++)
807 if (fingerprint[i] == ' ')
808 fingerprint[i] = '_';
810 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
811 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
812 pw->pw_dir, entity, file);
813 silc_free(fingerprint);
816 /* Take fingerprint of the public key */
817 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
819 verify = silc_calloc(1, sizeof(*verify));
820 verify->client = client;
822 verify->filename = strdup(filename);
823 verify->entity = strdup(entity);
824 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
825 memcpy(verify->pk, pk, pk_len);
826 verify->pk_len = pk_len;
827 verify->pk_type = pk_type;
828 verify->completion = completion;
829 verify->context = context;
831 /* Check whether this key already exists */
832 if (stat(filename, &st) < 0) {
833 /* Key does not exist, ask user to verify the key and save it */
835 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
836 SILCTXT_PUBKEY_RECEIVED, entity);
837 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
838 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
839 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
840 SILCTXT_PUBKEY_ACCEPT);
841 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
844 silc_free(fingerprint);
847 /* The key already exists, verify it. */
848 SilcPublicKey public_key;
849 unsigned char *encpk;
852 /* Load the key file */
853 if (!silc_pkcs_load_public_key(filename, &public_key,
855 if (!silc_pkcs_load_public_key(filename, &public_key,
856 SILC_PKCS_FILE_BIN)) {
857 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
858 SILCTXT_PUBKEY_RECEIVED, entity);
859 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
860 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
861 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
862 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
863 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
864 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
865 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
868 silc_free(fingerprint);
872 /* Encode the key data */
873 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
875 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
876 SILCTXT_PUBKEY_RECEIVED, entity);
877 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
878 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
879 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
880 SILCTXT_PUBKEY_MALFORMED, entity);
881 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
882 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
883 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
886 silc_free(fingerprint);
890 /* Compare the keys */
891 if (memcmp(encpk, pk, encpk_len)) {
892 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
893 SILCTXT_PUBKEY_RECEIVED, entity);
894 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
895 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
896 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
897 SILCTXT_PUBKEY_NO_MATCH, entity);
898 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
899 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
900 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
901 SILCTXT_PUBKEY_MITM_ATTACK, entity);
903 /* Ask user to verify the key and save it */
904 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
905 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
906 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
909 silc_free(fingerprint);
913 /* Local copy matched */
915 completion(TRUE, context);
916 silc_free(fingerprint);
920 /* Verifies received public key. The `conn_type' indicates which entity
921 (server, client etc.) has sent the public key. If user decides to trust
922 the key may be saved as trusted public key for later use. The
923 `completion' must be called after the public key has been verified. */
926 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
927 SilcSocketType conn_type, unsigned char *pk,
928 uint32 pk_len, SilcSKEPKType pk_type,
929 SilcVerifyPublicKey completion, void *context)
931 silc_verify_public_key_internal(client, conn, conn_type, pk,
933 completion, context);
936 /* Asks passphrase from user on the input line. */
939 SilcAskPassphrase completion;
943 void ask_passphrase_completion(const char *passphrase, void *context)
945 AskPassphrase p = (AskPassphrase)context;
946 p->completion((unsigned char *)passphrase,
947 passphrase ? strlen(passphrase) : 0, p->context);
951 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
952 SilcAskPassphrase completion, void *context)
954 AskPassphrase p = silc_calloc(1, sizeof(*p));
955 p->completion = completion;
956 p->context = context;
958 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
959 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
962 /* Find authentication method and authentication data by hostname and
963 port. The hostname may be IP address as well. The found authentication
964 method and authentication data is returned to `auth_meth', `auth_data'
965 and `auth_data_len'. The function returns TRUE if authentication method
966 is found and FALSE if not. `conn' may be NULL. */
968 int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
969 char *hostname, uint16 port,
970 SilcProtocolAuthMeth *auth_meth,
971 unsigned char **auth_data,
972 uint32 *auth_data_len)
975 SILC_SERVER_REC *server = conn ? conn->context : NULL;
977 /* XXX must resolve from configuration whether this connection has
978 any specific authentication data */
980 *auth_meth = SILC_AUTH_NONE;
985 printformat_module("fe-common/silc", server, NULL,
986 MSGLEVEL_MODES, SILCTXT_AUTH_METH_UNRESOLVED);
992 /* Notifies application that failure packet was received. This is called
993 if there is some protocol active in the client. The `protocol' is the
994 protocol context. The `failure' is opaque pointer to the failure
995 indication. Note, that the `failure' is protocol dependant and application
996 must explicitly cast it to correct type. Usually `failure' is 32 bit
997 failure type (see protocol specs for all protocol failure types). */
999 void silc_failure(SilcClient client, SilcClientConnection conn,
1000 SilcProtocol protocol, void *failure)
1002 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1003 SilcSKEStatus status = (SilcSKEStatus)failure;
1005 if (status == SILC_SKE_STATUS_BAD_VERSION)
1006 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1007 SILCTXT_KE_BAD_VERSION);
1008 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1009 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1010 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1011 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1012 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1013 SILCTXT_KE_UNKNOWN_GROUP);
1014 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1015 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1016 SILCTXT_KE_UNKNOWN_CIPHER);
1017 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1018 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1019 SILCTXT_KE_UNKNOWN_PKCS);
1020 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1021 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1022 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1023 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1024 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1025 SILCTXT_KE_UNKNOWN_HMAC);
1026 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1027 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1028 SILCTXT_KE_INCORRECT_SIGNATURE);
1031 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1032 uint32 err = (uint32)failure;
1034 if (err == SILC_AUTH_FAILED)
1035 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1036 SILCTXT_AUTH_FAILED);
1040 /* Asks whether the user would like to perform the key agreement protocol.
1041 This is called after we have received an key agreement packet or an
1042 reply to our key agreement packet. This returns TRUE if the user wants
1043 the library to perform the key agreement protocol and FALSE if it is not
1044 desired (application may start it later by calling the function
1045 silc_client_perform_key_agreement). */
1047 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1048 SilcClientEntry client_entry, char *hostname,
1050 SilcKeyAgreementCallback *completion,
1055 /* We will just display the info on the screen and return FALSE and user
1056 will have to start the key agreement with a command. */
1059 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1062 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES,
1063 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1065 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES,
1066 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1067 client_entry->nickname, hostname, portstr);
1075 /* SILC client operations */
1076 SilcClientOperations ops = {
1078 silc_channel_message,
1079 silc_private_message,
1085 silc_get_auth_method,
1086 silc_verify_public_key,
1087 silc_ask_passphrase,