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 SILC_LOG_DEBUG(("Start"));
89 server = conn == NULL ? NULL : conn->context;
90 chanrec = silc_channel_find_entry(server, channel);
94 nick = silc_nicklist_find(chanrec, sender);
96 /* We didn't find client but it clearly exists, add it. */
99 silc_list_start(channel->clients);
100 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
101 if (chu->client == sender) {
102 nick = silc_nicklist_insert(chanrec, chu, FALSE);
108 if (flags & SILC_MESSAGE_FLAG_ACTION)
109 printformat_module("fe-common/silc", server, channel->channel_name,
110 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
111 nick == NULL ? "[<unknown>]" : nick->nick, msg);
112 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
113 printformat_module("fe-common/silc", server, channel->channel_name,
114 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
115 nick == NULL ? "[<unknown>]" : nick->nick, msg);
117 signal_emit("message public", 6, server, msg,
118 nick == NULL ? "[<unknown>]" : nick->nick,
119 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
120 chanrec->name, nick);
123 /* Private message to the client. The `sender' is the nickname of the
124 sender received in the packet. */
126 void silc_private_message(SilcClient client, SilcClientConnection conn,
127 SilcClientEntry sender, SilcMessageFlags flags,
130 SILC_SERVER_REC *server;
133 SILC_LOG_DEBUG(("Start"));
135 server = conn == NULL ? NULL : conn->context;
136 memset(userhost, 0, sizeof(userhost));
137 if (sender->username)
138 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
139 sender->username, sender->hostname);
140 signal_emit("message private", 4, server, msg,
141 sender->nickname ? sender->nickname : "[<unknown>]",
142 sender->username ? userhost : NULL);
145 /* Notify message to the client. The notify arguments are sent in the
146 same order as servers sends them. The arguments are same as received
147 from the server except for ID's. If ID is received application receives
148 the corresponding entry to the ID. For example, if Client ID is received
149 application receives SilcClientEntry. Also, if the notify type is
150 for channel the channel entry is sent to application (even if server
151 does not send it). */
158 #define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
159 static NOTIFY_REC notifies[] = {
160 { SILC_NOTIFY_TYPE_NONE, NULL },
161 { SILC_NOTIFY_TYPE_INVITE, "invite" },
162 { SILC_NOTIFY_TYPE_JOIN, "join" },
163 { SILC_NOTIFY_TYPE_LEAVE, "leave" },
164 { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" },
165 { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" },
166 { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" },
167 { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" },
168 { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" },
169 { SILC_NOTIFY_TYPE_MOTD, "motd" },
170 { SILC_NOTIFY_TYPE_CHANNEL_CHANGE, "channel_change" },
171 { SILC_NOTIFY_TYPE_SERVER_SIGNOFF, "server_signoff" },
172 { SILC_NOTIFY_TYPE_KICKED, "kick" },
173 { SILC_NOTIFY_TYPE_KILLED, "kill" },
174 { SILC_NOTIFY_TYPE_UMODE_CHANGE, "umode" },
175 { SILC_NOTIFY_TYPE_BAN, "ban" },
178 void silc_notify(SilcClient client, SilcClientConnection conn,
179 SilcNotifyType type, ...)
181 SILC_SERVER_REC *server;
184 SILC_LOG_DEBUG(("Start"));
186 server = conn == NULL ? NULL : conn->context;
189 if (type == SILC_NOTIFY_TYPE_NONE) {
190 /* Some generic notice from server */
191 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
192 } else if (type < MAX_NOTIFY) {
193 /* Send signal about the notify event */
195 g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name);
196 signal_emit(signal, 2, server, va);
199 printformat_module("fe-common/silc", server, NULL,
200 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
206 /* Called to indicate that connection was either successfully established
207 or connecting failed. This is also the first time application receives
208 the SilcClientConnection object which it should save somewhere. */
210 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
212 SILC_SERVER_REC *server = conn->context;
214 if (!server && !success) {
215 silc_client_close_connection(client, NULL, conn);
220 server->connected = TRUE;
221 signal_emit("event connected", 1, server);
223 server->connection_lost = TRUE;
224 server->conn->context = NULL;
225 server_disconnect(SERVER(server));
229 /* Called to indicate that connection was disconnected to the server. */
231 void silc_disconnect(SilcClient client, SilcClientConnection conn)
233 SILC_SERVER_REC *server = conn->context;
235 SILC_LOG_DEBUG(("Start"));
238 nicklist_rename_unique(SERVER(server),
239 server->conn->local_entry, server->nick,
240 server->conn->local_entry,
241 silc_client->username);
242 silc_change_nick(server, silc_client->username);
245 server->conn->context = NULL;
247 server->connection_lost = TRUE;
248 server_disconnect(SERVER(server));
251 /* Command handler. This function is called always in the command function.
252 If error occurs it will be called as well. `conn' is the associated
253 client connection. `cmd_context' is the command context that was
254 originally sent to the command. `success' is FALSE if error occured
255 during command. `command' is the command being processed. It must be
256 noted that this is not reply from server. This is merely called just
257 after application has called the command. Just to tell application
258 that the command really was processed. */
260 void silc_command(SilcClient client, SilcClientConnection conn,
261 SilcClientCommandContext cmd_context, int success,
264 SILC_SERVER_REC *server = conn->context;
266 SILC_LOG_DEBUG(("Start"));
272 case SILC_COMMAND_INVITE:
273 printformat_module("fe-common/silc", server, NULL,
274 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
275 cmd_context->argv[2],
276 (cmd_context->argv[1][0] == '*' ?
277 (char *)conn->current_channel->channel_name :
278 (char *)cmd_context->argv[1]));
285 /* Client info resolving callback when JOIN command reply is received.
286 This will cache all users on the channel. */
288 static void silc_client_join_get_users(SilcClient client,
289 SilcClientConnection conn,
290 SilcClientEntry *clients,
291 uint32 clients_count,
294 SilcChannelEntry channel = (SilcChannelEntry)context;
296 SILC_SERVER_REC *server = conn->context;
297 SILC_CHANNEL_REC *chanrec;
298 SilcClientEntry founder = NULL;
304 chanrec = silc_channel_find(server, channel->channel_name);
308 silc_list_start(channel->clients);
309 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
310 if (!chu->client->nickname)
312 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
313 founder = chu->client;
314 silc_nicklist_insert(chanrec, chu, FALSE);
317 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
318 nicklist_set_own(CHANNEL(chanrec), ownnick);
319 signal_emit("channel joined", 1, chanrec);
322 printformat_module("fe-common/silc", server, channel->channel_name,
323 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
324 channel->channel_name, chanrec->topic);
326 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
329 if (founder == conn->local_entry)
330 printformat_module("fe-common/silc",
331 server, channel->channel_name, MSGLEVEL_CRAP,
332 SILCTXT_CHANNEL_FOUNDER_YOU,
333 channel->channel_name);
335 printformat_module("fe-common/silc",
336 server, channel->channel_name, MSGLEVEL_CRAP,
337 SILCTXT_CHANNEL_FOUNDER,
338 channel->channel_name, founder->nickname);
344 SilcClientConnection conn;
350 void silc_getkey_cb(bool success, void *context)
352 GetkeyContext getkey = (GetkeyContext)context;
353 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
354 char *name = (getkey->id_type == SILC_ID_CLIENT ?
355 ((SilcClientEntry)getkey->entry)->nickname :
356 ((SilcServerEntry)getkey->entry)->server_name);
359 printformat_module("fe-common/silc", NULL, NULL,
360 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
362 printformat_module("fe-common/silc", NULL, NULL,
363 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
366 silc_free(getkey->fingerprint);
370 /* Command reply handler. This function is called always in the command reply
371 function. If error occurs it will be called as well. Normal scenario
372 is that it will be called after the received command data has been parsed
373 and processed. The function is used to pass the received command data to
376 `conn' is the associated client connection. `cmd_payload' is the command
377 payload data received from server and it can be ignored. It is provided
378 if the application would like to re-parse the received command data,
379 however, it must be noted that the data is parsed already by the library
380 thus the payload can be ignored. `success' is FALSE if error occured.
381 In this case arguments are not sent to the application. `command' is the
382 command reply being processed. The function has variable argument list
383 and each command defines the number and type of arguments it passes to the
384 application (on error they are not sent). */
387 silc_command_reply(SilcClient client, SilcClientConnection conn,
388 SilcCommandPayload cmd_payload, int success,
389 SilcCommand command, SilcCommandStatus status, ...)
392 SILC_SERVER_REC *server = conn->context;
393 SILC_CHANNEL_REC *chanrec;
396 va_start(vp, status);
398 SILC_LOG_DEBUG(("Start"));
401 case SILC_COMMAND_WHOIS:
403 char buf[1024], *nickname, *username, *realname, *nick;
404 unsigned char *fingerprint;
407 SilcClientEntry client_entry;
409 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
410 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
412 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
415 silc_say_error("%s: %s", tmp,
416 silc_client_command_status_message(status));
423 client_entry = va_arg(vp, SilcClientEntry);
424 nickname = va_arg(vp, char *);
425 username = va_arg(vp, char *);
426 realname = va_arg(vp, char *);
427 channels = va_arg(vp, SilcBuffer);
428 mode = va_arg(vp, uint32);
429 idle = va_arg(vp, uint32);
430 fingerprint = va_arg(vp, unsigned char *);
432 silc_parse_userfqdn(nickname, &nick, NULL);
433 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
434 SILCTXT_WHOIS_USERINFO, nickname,
435 client_entry->username, client_entry->hostname,
436 nick, client_entry->nickname);
437 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
438 SILCTXT_WHOIS_REALNAME, realname);
442 SilcDList list = silc_channel_payload_parse_list(channels);
444 SilcChannelPayload entry;
445 memset(buf, 0, sizeof(buf));
446 silc_dlist_start(list);
447 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
448 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
450 char *name = silc_channel_get_name(entry, &name_len);
453 strncat(buf, m, strlen(m));
454 strncat(buf, name, name_len);
455 strncat(buf, " ", 1);
459 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
460 SILCTXT_WHOIS_CHANNELS, buf);
461 silc_channel_payload_list_free(list);
466 memset(buf, 0, sizeof(buf));
468 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
469 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
470 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
472 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
473 "SILC Operator " : "[Unknown mode] ");
475 if (mode & SILC_UMODE_GONE)
478 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
479 SILCTXT_WHOIS_MODES, buf);
482 if (idle && nickname) {
483 memset(buf, 0, sizeof(buf));
484 snprintf(buf, sizeof(buf) - 1, "%lu %s",
485 idle > 60 ? (idle / 60) : idle,
486 idle > 60 ? "minutes" : "seconds");
488 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
489 SILCTXT_WHOIS_IDLE, buf);
493 fingerprint = silc_fingerprint(fingerprint, 20);
494 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
495 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
496 silc_free(fingerprint);
501 case SILC_COMMAND_WHOWAS:
503 char *nickname, *username, *realname;
505 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
506 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
508 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
511 silc_say_error("%s: %s", tmp,
512 silc_client_command_status_message(status));
519 (void)va_arg(vp, SilcClientEntry);
520 nickname = va_arg(vp, char *);
521 username = va_arg(vp, char *);
522 realname = va_arg(vp, char *);
524 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
525 SILCTXT_WHOWAS_USERINFO, nickname, username,
526 realname ? realname : "");
530 case SILC_COMMAND_INVITE:
532 SilcChannelEntry channel;
534 SilcArgumentPayload args;
540 channel = va_arg(vp, SilcChannelEntry);
541 invite_list = va_arg(vp, char *);
543 args = silc_command_get_args(cmd_payload);
545 argc = silc_argument_get_arg_num(args);
548 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
549 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
552 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
553 SILCTXT_CHANNEL_NO_INVITE_LIST,
554 channel->channel_name);
558 case SILC_COMMAND_JOIN:
560 char *channel, *mode, *topic;
562 SilcChannelEntry channel_entry;
563 SilcBuffer client_id_list;
569 channel = va_arg(vp, char *);
570 channel_entry = va_arg(vp, SilcChannelEntry);
571 modei = va_arg(vp, uint32);
572 (void)va_arg(vp, uint32);
573 (void)va_arg(vp, unsigned char *);
574 (void)va_arg(vp, unsigned char *);
575 (void)va_arg(vp, unsigned char *);
576 topic = va_arg(vp, char *);
577 (void)va_arg(vp, unsigned char *);
578 list_count = va_arg(vp, uint32);
579 client_id_list = va_arg(vp, SilcBuffer);
581 chanrec = silc_channel_find(server, channel);
583 chanrec = silc_channel_create(server, channel, TRUE);
586 g_free_not_null(chanrec->topic);
587 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
588 signal_emit("channel topic changed", 1, chanrec);
591 mode = silc_client_chmode(modei,
592 channel_entry->channel_key ?
593 channel_entry->channel_key->cipher->name : "",
594 channel_entry->hmac ?
595 silc_hmac_get_name(channel_entry->hmac) : "");
596 g_free_not_null(chanrec->mode);
597 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
598 signal_emit("channel mode changed", 1, chanrec);
600 /* Resolve the client information */
601 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
602 silc_client_join_get_users,
607 case SILC_COMMAND_NICK:
609 SilcClientEntry client = va_arg(vp, SilcClientEntry);
615 old = g_strdup(server->nick);
616 server_change_nick(SERVER(server), client->nickname);
617 nicklist_rename_unique(SERVER(server),
618 server->conn->local_entry, server->nick,
619 client, client->nickname);
621 signal_emit("message own_nick", 4, server, server->nick, old, "");
626 case SILC_COMMAND_LIST:
635 (void)va_arg(vp, SilcChannelEntry);
636 name = va_arg(vp, char *);
637 topic = va_arg(vp, char *);
638 usercount = va_arg(vp, int);
640 if (status == SILC_STATUS_LIST_START ||
641 status == SILC_STATUS_OK)
642 printformat_module("fe-common/silc", server, NULL,
643 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
646 snprintf(users, sizeof(users) - 1, "N/A");
648 snprintf(users, sizeof(users) - 1, "%d", usercount);
649 printformat_module("fe-common/silc", server, NULL,
650 MSGLEVEL_CRAP, SILCTXT_LIST,
651 name, users, topic ? topic : "");
655 case SILC_COMMAND_UMODE:
662 mode = va_arg(vp, uint32);
664 if (mode & SILC_UMODE_SERVER_OPERATOR)
665 printformat_module("fe-common/silc", server, NULL,
666 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
668 if (mode & SILC_UMODE_ROUTER_OPERATOR)
669 printformat_module("fe-common/silc", server, NULL,
670 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
674 case SILC_COMMAND_OPER:
678 printformat_module("fe-common/silc", server, NULL,
679 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
682 case SILC_COMMAND_SILCOPER:
686 printformat_module("fe-common/silc", server, NULL,
687 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
690 case SILC_COMMAND_USERS:
692 SilcChannelEntry channel;
698 channel = va_arg(vp, SilcChannelEntry);
700 printformat_module("fe-common/silc", server, channel->channel_name,
701 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
702 channel->channel_name);
704 silc_list_start(channel->clients);
705 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
706 SilcClientEntry e = chu->client;
712 memset(stat, 0, sizeof(stat));
713 mode = silc_client_chumode_char(chu->mode);
714 if (e->mode & SILC_UMODE_GONE)
721 printformat_module("fe-common/silc", server, channel->channel_name,
722 MSGLEVEL_CRAP, SILCTXT_USERS,
724 e->username ? e->username : "",
725 e->hostname ? e->hostname : "",
726 e->realname ? e->realname : "");
733 case SILC_COMMAND_BAN:
735 SilcChannelEntry channel;
741 channel = va_arg(vp, SilcChannelEntry);
742 ban_list = va_arg(vp, char *);
745 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
746 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
749 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
750 SILCTXT_CHANNEL_NO_BAN_LIST,
751 channel->channel_name);
755 case SILC_COMMAND_GETKEY:
759 SilcPublicKey public_key;
762 GetkeyContext getkey;
767 id_type = va_arg(vp, uint32);
768 entry = va_arg(vp, void *);
769 public_key = va_arg(vp, SilcPublicKey);
772 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
774 getkey = silc_calloc(1, sizeof(*getkey));
775 getkey->entry = entry;
776 getkey->id_type = id_type;
777 getkey->client = client;
779 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
781 silc_verify_public_key_internal(client, conn,
782 (id_type == SILC_ID_CLIENT ?
783 SILC_SOCKET_TYPE_CLIENT :
784 SILC_SOCKET_TYPE_SERVER),
785 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
786 silc_getkey_cb, getkey);
789 printformat_module("fe-common/silc", server, NULL,
790 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
795 case SILC_COMMAND_TOPIC:
797 SilcChannelEntry channel;
803 channel = va_arg(vp, SilcChannelEntry);
804 topic = va_arg(vp, char *);
807 chanrec = silc_channel_find_entry(server, channel);
809 g_free_not_null(chanrec->topic);
810 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
811 signal_emit("channel topic changed", 1, chanrec);
813 printformat_module("fe-common/silc", server, channel->channel_name,
814 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
815 channel->channel_name, topic);
817 printformat_module("fe-common/silc", server, channel->channel_name,
818 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
819 channel->channel_name);
829 /* Internal routine to verify public key. If the `completion' is provided
830 it will be called to indicate whether public was verified or not. */
834 SilcClientConnection conn;
839 SilcSKEPKType pk_type;
840 SilcVerifyPublicKey completion;
844 static void verify_public_key_completion(const char *line, void *context)
846 PublicKeyVerify verify = (PublicKeyVerify)context;
848 if (line[0] == 'Y' || line[0] == 'y') {
849 /* Call the completion */
850 if (verify->completion)
851 verify->completion(TRUE, verify->context);
853 /* Save the key for future checking */
854 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
855 verify->pk_len, SILC_PKCS_FILE_PEM);
857 /* Call the completion */
858 if (verify->completion)
859 verify->completion(FALSE, verify->context);
861 printformat_module("fe-common/silc", NULL, NULL,
862 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, verify->entity);
865 silc_free(verify->filename);
866 silc_free(verify->entity);
867 silc_free(verify->pk);
872 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
873 SilcSocketType conn_type, unsigned char *pk,
874 uint32 pk_len, SilcSKEPKType pk_type,
875 SilcVerifyPublicKey completion, void *context)
878 char file[256], filename[256], *fingerprint, *babbleprint, *format;
881 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
882 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
883 "server" : "client");
884 PublicKeyVerify verify;
886 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
887 printformat_module("fe-common/silc", NULL, NULL,
888 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
891 completion(FALSE, context);
895 pw = getpwuid(getuid());
898 completion(FALSE, context);
902 memset(filename, 0, sizeof(filename));
903 memset(file, 0, sizeof(file));
905 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
906 conn_type == SILC_SOCKET_TYPE_ROUTER) {
907 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
908 conn->sock->hostname, conn->sock->port);
909 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
910 pw->pw_dir, entity, file);
912 /* Replace all whitespaces with `_'. */
913 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
914 for (i = 0; i < strlen(fingerprint); i++)
915 if (fingerprint[i] == ' ')
916 fingerprint[i] = '_';
918 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
919 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
920 pw->pw_dir, entity, file);
921 silc_free(fingerprint);
924 /* Take fingerprint of the public key */
925 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
926 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
928 verify = silc_calloc(1, sizeof(*verify));
929 verify->client = client;
931 verify->filename = strdup(filename);
932 verify->entity = strdup(entity);
933 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
934 memcpy(verify->pk, pk, pk_len);
935 verify->pk_len = pk_len;
936 verify->pk_type = pk_type;
937 verify->completion = completion;
938 verify->context = context;
940 /* Check whether this key already exists */
941 if (stat(filename, &st) < 0) {
942 /* Key does not exist, ask user to verify the key and save it */
944 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
945 SILCTXT_PUBKEY_RECEIVED, entity);
946 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
947 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
948 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
949 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
950 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
951 SILCTXT_PUBKEY_ACCEPT);
952 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
955 silc_free(fingerprint);
958 /* The key already exists, verify it. */
959 SilcPublicKey public_key;
960 unsigned char *encpk;
963 /* Load the key file */
964 if (!silc_pkcs_load_public_key(filename, &public_key,
966 if (!silc_pkcs_load_public_key(filename, &public_key,
967 SILC_PKCS_FILE_BIN)) {
968 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
969 SILCTXT_PUBKEY_RECEIVED, entity);
970 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
971 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
972 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
973 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
974 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
975 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
976 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
977 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
978 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
981 silc_free(fingerprint);
985 /* Encode the key data */
986 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
988 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
989 SILCTXT_PUBKEY_RECEIVED, entity);
990 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
991 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
992 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
993 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
994 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
995 SILCTXT_PUBKEY_MALFORMED, entity);
996 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
997 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
998 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1001 silc_free(fingerprint);
1005 /* Compare the keys */
1006 if (memcmp(encpk, pk, encpk_len)) {
1007 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1008 SILCTXT_PUBKEY_RECEIVED, entity);
1009 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1010 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1011 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1012 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1013 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1014 SILCTXT_PUBKEY_NO_MATCH, entity);
1015 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1016 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1017 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1018 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1020 /* Ask user to verify the key and save it */
1021 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1022 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1023 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1026 silc_free(fingerprint);
1030 /* Local copy matched */
1032 completion(TRUE, context);
1033 silc_free(fingerprint);
1037 /* Verifies received public key. The `conn_type' indicates which entity
1038 (server, client etc.) has sent the public key. If user decides to trust
1039 the key may be saved as trusted public key for later use. The
1040 `completion' must be called after the public key has been verified. */
1043 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1044 SilcSocketType conn_type, unsigned char *pk,
1045 uint32 pk_len, SilcSKEPKType pk_type,
1046 SilcVerifyPublicKey completion, void *context)
1048 silc_verify_public_key_internal(client, conn, conn_type, pk,
1050 completion, context);
1053 /* Asks passphrase from user on the input line. */
1056 SilcAskPassphrase completion;
1060 void ask_passphrase_completion(const char *passphrase, void *context)
1062 AskPassphrase p = (AskPassphrase)context;
1063 p->completion((unsigned char *)passphrase,
1064 passphrase ? strlen(passphrase) : 0, p->context);
1068 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1069 SilcAskPassphrase completion, void *context)
1071 AskPassphrase p = silc_calloc(1, sizeof(*p));
1072 p->completion = completion;
1073 p->context = context;
1075 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1076 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1080 SilcGetAuthMeth completion;
1082 } *InternalGetAuthMethod;
1084 /* Callback called when we've received the authentication method information
1085 from the server after we've requested it. This will get the authentication
1086 data from the user if needed. */
1088 static void silc_get_auth_method_callback(SilcClient client,
1089 SilcClientConnection conn,
1090 SilcAuthMethod auth_meth,
1093 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1095 SILC_LOG_DEBUG(("Start"));
1097 switch (auth_meth) {
1098 case SILC_AUTH_NONE:
1099 /* No authentication required. */
1100 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1102 case SILC_AUTH_PASSWORD:
1103 /* Do not ask the passphrase from user, the library will ask it if
1104 we do not provide it here. */
1105 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1107 case SILC_AUTH_PUBLIC_KEY:
1108 /* Do not get the authentication data now, the library will generate
1109 it using our default key, if we do not provide it here. */
1110 /* XXX In the future when we support multiple local keys and multiple
1111 local certificates we will need to ask from user which one to use. */
1112 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1116 silc_free(internal);
1119 /* Find authentication method and authentication data by hostname and
1120 port. The hostname may be IP address as well. The found authentication
1121 method and authentication data is returned to `auth_meth', `auth_data'
1122 and `auth_data_len'. The function returns TRUE if authentication method
1123 is found and FALSE if not. `conn' may be NULL. */
1125 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1126 char *hostname, uint16 port,
1127 SilcGetAuthMeth completion, void *context)
1129 InternalGetAuthMethod internal;
1131 SILC_LOG_DEBUG(("Start"));
1133 /* XXX must resolve from configuration whether this connection has
1134 any specific authentication data */
1136 /* If we do not have this connection configured by the user in a
1137 configuration file then resolve the authentication method from the
1138 server for this session. */
1139 internal = silc_calloc(1, sizeof(*internal));
1140 internal->completion = completion;
1141 internal->context = context;
1143 silc_client_request_authentication_method(client, conn,
1144 silc_get_auth_method_callback,
1148 /* Notifies application that failure packet was received. This is called
1149 if there is some protocol active in the client. The `protocol' is the
1150 protocol context. The `failure' is opaque pointer to the failure
1151 indication. Note, that the `failure' is protocol dependant and application
1152 must explicitly cast it to correct type. Usually `failure' is 32 bit
1153 failure type (see protocol specs for all protocol failure types). */
1155 void silc_failure(SilcClient client, SilcClientConnection conn,
1156 SilcProtocol protocol, void *failure)
1158 SILC_LOG_DEBUG(("Start"));
1160 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1161 SilcSKEStatus status = (SilcSKEStatus)failure;
1163 if (status == SILC_SKE_STATUS_BAD_VERSION)
1164 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1165 SILCTXT_KE_BAD_VERSION);
1166 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1167 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1168 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1169 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1170 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1171 SILCTXT_KE_UNKNOWN_GROUP);
1172 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1173 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1174 SILCTXT_KE_UNKNOWN_CIPHER);
1175 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1176 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1177 SILCTXT_KE_UNKNOWN_PKCS);
1178 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1179 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1180 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1181 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1182 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1183 SILCTXT_KE_UNKNOWN_HMAC);
1184 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1185 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1186 SILCTXT_KE_INCORRECT_SIGNATURE);
1187 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1188 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1189 SILCTXT_KE_INVALID_COOKIE);
1192 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1193 uint32 err = (uint32)failure;
1195 if (err == SILC_AUTH_FAILED)
1196 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1197 SILCTXT_AUTH_FAILED);
1201 /* Asks whether the user would like to perform the key agreement protocol.
1202 This is called after we have received an key agreement packet or an
1203 reply to our key agreement packet. This returns TRUE if the user wants
1204 the library to perform the key agreement protocol and FALSE if it is not
1205 desired (application may start it later by calling the function
1206 silc_client_perform_key_agreement). */
1208 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1209 SilcClientEntry client_entry, const char *hostname,
1210 uint16 port, SilcKeyAgreementCallback *completion,
1215 SILC_LOG_DEBUG(("Start"));
1217 /* We will just display the info on the screen and return FALSE and user
1218 will have to start the key agreement with a command. */
1221 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1224 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1225 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1227 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1228 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1229 client_entry->nickname, hostname, portstr);
1237 void silc_ftp(SilcClient client, SilcClientConnection conn,
1238 SilcClientEntry client_entry, uint32 session_id,
1239 const char *hostname, uint16 port)
1241 SILC_SERVER_REC *server;
1243 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1245 SILC_LOG_DEBUG(("Start"));
1247 server = conn->context;
1249 ftp->client_entry = client_entry;
1250 ftp->session_id = session_id;
1253 silc_dlist_add(server->ftp_sessions, ftp);
1254 server->current_session = ftp;
1257 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1260 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1261 SILCTXT_FILE_REQUEST, client_entry->nickname);
1263 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1264 SILCTXT_FILE_REQUEST_HOST,
1265 client_entry->nickname, hostname, portstr);
1268 /* SILC client operations */
1269 SilcClientOperations ops = {
1271 silc_channel_message,
1272 silc_private_message,
1278 silc_get_auth_method,
1279 silc_verify_public_key,
1280 silc_ask_passphrase,