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,
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);
499 if (chanrec != NULL && !success)
500 channel_destroy(CHANNEL(chanrec));
501 else if (chanrec == NULL && success)
502 chanrec = silc_channel_create(server, channel, TRUE);
505 g_free_not_null(chanrec->topic);
506 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
507 signal_emit("channel topic changed", 1, chanrec);
510 mode = silc_client_chmode(modei,
511 channel_entry->channel_key->cipher->name,
512 channel_entry->hmac->hmac->name);
513 g_free_not_null(chanrec->mode);
514 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
515 signal_emit("channel mode changed", 1, chanrec);
517 /* Resolve the client information */
518 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
519 silc_client_join_get_users,
524 case SILC_COMMAND_NICK:
526 SilcClientEntry client = va_arg(vp, SilcClientEntry);
532 old = g_strdup(server->nick);
533 server_change_nick(SERVER(server), client->nickname);
534 nicklist_rename_unique(SERVER(server),
535 server->conn->local_entry, server->nick,
536 client, client->nickname);
538 signal_emit("message own_nick", 4, server, server->nick, old, "");
543 case SILC_COMMAND_LIST:
552 (void)va_arg(vp, SilcChannelEntry);
553 name = va_arg(vp, char *);
554 topic = va_arg(vp, char *);
555 usercount = va_arg(vp, int);
557 if (status == SILC_STATUS_LIST_START ||
558 status == SILC_STATUS_OK)
559 printformat_module("fe-common/silc", server, NULL,
560 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
562 snprintf(users, sizeof(users) - 1, "%d", usercount);
563 printformat_module("fe-common/silc", server, NULL,
564 MSGLEVEL_CRAP, SILCTXT_LIST,
565 name, users, topic ? topic : "");
569 case SILC_COMMAND_UMODE:
576 mode = va_arg(vp, uint32);
578 if (mode & SILC_UMODE_SERVER_OPERATOR)
579 printformat_module("fe-common/silc", server, NULL,
580 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
582 if (mode & SILC_UMODE_ROUTER_OPERATOR)
583 printformat_module("fe-common/silc", server, NULL,
584 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
588 case SILC_COMMAND_OPER:
592 printformat_module("fe-common/silc", server, NULL,
593 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
596 case SILC_COMMAND_SILCOPER:
600 printformat_module("fe-common/silc", server, NULL,
601 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
604 case SILC_COMMAND_USERS:
606 SilcChannelEntry channel;
612 channel = va_arg(vp, SilcChannelEntry);
614 printformat_module("fe-common/silc", server, channel->channel_name,
615 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
616 channel->channel_name);
618 silc_list_start(channel->clients);
619 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
620 SilcClientEntry e = chu->client;
623 memset(stat, 0, sizeof(stat));
624 mode = silc_client_chumode_char(chu->mode);
625 if (e->mode & SILC_UMODE_GONE)
632 printformat_module("fe-common/silc", server, channel->channel_name,
633 MSGLEVEL_CRAP, SILCTXT_USERS,
634 e->nickname, stat, e->username,
635 e->realname ? e->realname : "");
642 case SILC_COMMAND_BAN:
644 SilcChannelEntry channel;
650 channel = va_arg(vp, SilcChannelEntry);
651 ban_list = va_arg(vp, char *);
654 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
655 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
658 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
659 SILCTXT_CHANNEL_NO_BAN_LIST,
660 channel->channel_name);
664 case SILC_COMMAND_GETKEY:
668 SilcPublicKey public_key;
675 id_type = va_arg(vp, uint32);
676 entry = va_arg(vp, void *);
677 public_key = va_arg(vp, SilcPublicKey);
679 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
681 if (id_type == SILC_ID_CLIENT)
682 silc_verify_public_key_internal(client, conn, SILC_SOCKET_TYPE_CLIENT,
683 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
689 case SILC_COMMAND_TOPIC:
691 SilcChannelEntry channel;
697 channel = va_arg(vp, SilcChannelEntry);
698 topic = va_arg(vp, char *);
701 chanrec = silc_channel_find_entry(server, channel);
703 g_free_not_null(chanrec->topic);
704 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
705 signal_emit("channel topic changed", 1, chanrec);
707 printformat_module("fe-common/silc", server, channel->channel_name,
708 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
709 channel->channel_name, topic);
711 printformat_module("fe-common/silc", server, channel->channel_name,
712 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
713 channel->channel_name);
723 /* Internal routine to verify public key. If the `completion' is provided
724 it will be called to indicate whether public was verified or not. */
728 SilcClientConnection conn;
733 SilcSKEPKType pk_type;
734 SilcVerifyPublicKey completion;
738 static void verify_public_key_completion(const char *line, void *context)
740 PublicKeyVerify verify = (PublicKeyVerify)context;
742 if (line[0] == 'Y' || line[0] == 'y') {
743 /* Call the completion */
744 if (verify->completion)
745 verify->completion(TRUE, verify->context);
747 /* Save the key for future checking */
748 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
749 verify->pk_len, SILC_PKCS_FILE_PEM);
751 /* Call the completion */
752 if (verify->completion)
753 verify->completion(FALSE, verify->context);
755 printformat_module("fe-common/silc", NULL, NULL,
756 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, verify->entity);
759 silc_free(verify->filename);
760 silc_free(verify->entity);
761 silc_free(verify->pk);
766 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
767 SilcSocketType conn_type, unsigned char *pk,
768 uint32 pk_len, SilcSKEPKType pk_type,
769 SilcVerifyPublicKey completion, void *context)
772 char file[256], filename[256], *fingerprint, *format;
775 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
776 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
777 "server" : "client");
778 PublicKeyVerify verify;
780 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
781 printformat_module("fe-common/silc", NULL, NULL,
782 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
785 completion(FALSE, context);
789 pw = getpwuid(getuid());
792 completion(FALSE, context);
796 memset(filename, 0, sizeof(filename));
797 memset(file, 0, sizeof(file));
799 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
800 conn_type == SILC_SOCKET_TYPE_ROUTER) {
801 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
802 conn->sock->hostname, conn->sock->port);
803 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
804 pw->pw_dir, entity, file);
806 /* Replace all whitespaces with `_'. */
807 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
808 for (i = 0; i < strlen(fingerprint); i++)
809 if (fingerprint[i] == ' ')
810 fingerprint[i] = '_';
812 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
813 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
814 pw->pw_dir, entity, file);
815 silc_free(fingerprint);
818 /* Take fingerprint of the public key */
819 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
821 verify = silc_calloc(1, sizeof(*verify));
822 verify->client = client;
824 verify->filename = strdup(filename);
825 verify->entity = strdup(entity);
826 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
827 memcpy(verify->pk, pk, pk_len);
828 verify->pk_len = pk_len;
829 verify->pk_type = pk_type;
830 verify->completion = completion;
831 verify->context = context;
833 /* Check whether this key already exists */
834 if (stat(filename, &st) < 0) {
835 /* Key does not exist, ask user to verify the key and save it */
837 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
838 SILCTXT_PUBKEY_RECEIVED, entity);
839 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
840 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
841 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
842 SILCTXT_PUBKEY_ACCEPT);
843 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
846 silc_free(fingerprint);
849 /* The key already exists, verify it. */
850 SilcPublicKey public_key;
851 unsigned char *encpk;
854 /* Load the key file */
855 if (!silc_pkcs_load_public_key(filename, &public_key,
857 if (!silc_pkcs_load_public_key(filename, &public_key,
858 SILC_PKCS_FILE_BIN)) {
859 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
860 SILCTXT_PUBKEY_RECEIVED, entity);
861 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
862 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
863 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
864 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
865 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
866 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
867 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
870 silc_free(fingerprint);
874 /* Encode the key data */
875 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
877 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
878 SILCTXT_PUBKEY_RECEIVED, entity);
879 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
880 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
881 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
882 SILCTXT_PUBKEY_MALFORMED, entity);
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 /* Compare the keys */
893 if (memcmp(encpk, pk, encpk_len)) {
894 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
895 SILCTXT_PUBKEY_RECEIVED, entity);
896 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
897 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
898 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
899 SILCTXT_PUBKEY_NO_MATCH, entity);
900 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
901 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
902 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
903 SILCTXT_PUBKEY_MITM_ATTACK, entity);
905 /* Ask user to verify the key and save it */
906 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
907 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
908 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
911 silc_free(fingerprint);
915 /* Local copy matched */
917 completion(TRUE, context);
918 silc_free(fingerprint);
922 /* Verifies received public key. The `conn_type' indicates which entity
923 (server, client etc.) has sent the public key. If user decides to trust
924 the key may be saved as trusted public key for later use. The
925 `completion' must be called after the public key has been verified. */
928 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
929 SilcSocketType conn_type, unsigned char *pk,
930 uint32 pk_len, SilcSKEPKType pk_type,
931 SilcVerifyPublicKey completion, void *context)
933 silc_verify_public_key_internal(client, conn, conn_type, pk,
935 completion, context);
938 /* Asks passphrase from user on the input line. */
941 SilcAskPassphrase completion;
945 void ask_passphrase_completion(const char *passphrase, void *context)
947 AskPassphrase p = (AskPassphrase)context;
948 p->completion((unsigned char *)passphrase,
949 passphrase ? strlen(passphrase) : 0, p->context);
953 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
954 SilcAskPassphrase completion, void *context)
956 AskPassphrase p = silc_calloc(1, sizeof(*p));
957 p->completion = completion;
958 p->context = context;
960 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
961 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
964 /* Find authentication method and authentication data by hostname and
965 port. The hostname may be IP address as well. The found authentication
966 method and authentication data is returned to `auth_meth', `auth_data'
967 and `auth_data_len'. The function returns TRUE if authentication method
968 is found and FALSE if not. `conn' may be NULL. */
970 int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
971 char *hostname, uint16 port,
972 SilcProtocolAuthMeth *auth_meth,
973 unsigned char **auth_data,
974 uint32 *auth_data_len)
977 SILC_SERVER_REC *server = conn ? conn->context : NULL;
979 /* XXX must resolve from configuration whether this connection has
980 any specific authentication data */
982 *auth_meth = SILC_AUTH_NONE;
987 printformat_module("fe-common/silc", server, NULL,
988 MSGLEVEL_MODES, SILCTXT_AUTH_METH_UNRESOLVED);
994 /* Notifies application that failure packet was received. This is called
995 if there is some protocol active in the client. The `protocol' is the
996 protocol context. The `failure' is opaque pointer to the failure
997 indication. Note, that the `failure' is protocol dependant and application
998 must explicitly cast it to correct type. Usually `failure' is 32 bit
999 failure type (see protocol specs for all protocol failure types). */
1001 void silc_failure(SilcClient client, SilcClientConnection conn,
1002 SilcProtocol protocol, void *failure)
1004 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1005 SilcSKEStatus status = (SilcSKEStatus)failure;
1007 if (status == SILC_SKE_STATUS_BAD_VERSION)
1008 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1009 SILCTXT_KE_BAD_VERSION);
1010 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1011 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1012 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1013 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1014 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1015 SILCTXT_KE_UNKNOWN_GROUP);
1016 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1017 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1018 SILCTXT_KE_UNKNOWN_CIPHER);
1019 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1020 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1021 SILCTXT_KE_UNKNOWN_PKCS);
1022 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1023 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1024 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1025 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1026 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1027 SILCTXT_KE_UNKNOWN_HMAC);
1028 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1029 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1030 SILCTXT_KE_INCORRECT_SIGNATURE);
1033 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1034 uint32 err = (uint32)failure;
1036 if (err == SILC_AUTH_FAILED)
1037 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1038 SILCTXT_AUTH_FAILED);
1042 /* Asks whether the user would like to perform the key agreement protocol.
1043 This is called after we have received an key agreement packet or an
1044 reply to our key agreement packet. This returns TRUE if the user wants
1045 the library to perform the key agreement protocol and FALSE if it is not
1046 desired (application may start it later by calling the function
1047 silc_client_perform_key_agreement). */
1049 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1050 SilcClientEntry client_entry, char *hostname,
1052 SilcKeyAgreementCallback *completion,
1057 /* We will just display the info on the screen and return FALSE and user
1058 will have to start the key agreement with a command. */
1061 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1064 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES,
1065 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1067 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES,
1068 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1069 client_entry->nickname, hostname, portstr);
1077 /* SILC client operations */
1078 SilcClientOperations ops = {
1080 silc_channel_message,
1081 silc_private_message,
1087 silc_get_auth_method,
1088 silc_verify_public_key,
1089 silc_ask_passphrase,