5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2000 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.
21 #include "clientincludes.h"
23 /* Prints a message with three star (*) sign before the actual message
24 on the current output window. This is used to print command outputs
25 and error messages. */
27 void silc_say(SilcClient client, SilcClientConnection conn,
32 SilcClientInternal app = (SilcClientInternal)client->application;
34 memset(message, 0, sizeof(message));
35 strncat(message, "\n*** ", 5);
38 vsprintf(message + 5, msg, vp);
41 /* Print the message */
42 silc_print_to_window(app->screen->output_win[0], message);
45 /* Message for a channel. The `sender' is the nickname of the sender
46 received in the packet. The `channel_name' is the name of the channel. */
48 void silc_channel_message(SilcClient client, SilcClientConnection conn,
49 char *sender, char *channel_name, char *msg)
51 /* Message from client */
52 if (!strcmp(conn->current_channel->channel_name, channel_name))
53 silc_print(client, "<%s> %s", sender, msg);
55 silc_print(client, "<%s:%s> %s", sender, channel_name, msg);
58 /* Private message to the client. The `sender' is the nickname of the
59 sender received in the packet. */
61 void silc_private_message(SilcClient client, SilcClientConnection conn,
62 char *sender, char *msg)
64 silc_print(client, "*%s* %s", sender, msg);
67 /* Command handler. This function is called always in the command function.
68 If error occurs it will be called as well. `conn' is the associated
69 client connection. `cmd_context' is the command context that was
70 originally sent to the command. `success' is FALSE if error occured
71 during command. `command' is the command being processed. It must be
72 noted that this is not reply from server. This is merely called just
73 after application has called the command. Just to tell application
74 that the command really was processed. */
76 void silc_command(SilcClient client, SilcClientConnection conn,
77 SilcClientCommandContext cmd_context, int success,
80 SilcClientInternal app = (SilcClientInternal)client->application;
87 case SILC_COMMAND_QUIT:
88 app->screen->bottom_line->channel = NULL;
89 silc_screen_print_bottom_line(app->screen, 0);
92 case SILC_COMMAND_LEAVE:
94 if (!strncmp(conn->current_channel->channel_name, name, strlen(name))) {
95 app->screen->bottom_line->channel = NULL;
96 silc_screen_print_bottom_line(app->screen, 0);
104 /* Command reply handler. This function is called always in the command reply
105 function. If error occurs it will be called as well. Normal scenario
106 is that it will be called after the received command data has been parsed
107 and processed. The function is used to pass the received command data to
110 `conn' is the associated client connection. `cmd_payload' is the command
111 payload data received from server and it can be ignored. It is provided
112 if the application would like to re-parse the received command data,
113 however, it must be noted that the data is parsed already by the library
114 thus the payload can be ignored. `success' is FALSE if error occured.
115 In this case arguments are not sent to the application. `command' is the
116 command reply being processed. The function has variable argument list
117 and each command defines the number and type of arguments it passes to the
118 application (on error they are not sent). */
120 void silc_command_reply(SilcClient client, SilcClientConnection conn,
121 SilcCommandPayload cmd_payload, int success,
122 SilcCommand command, ...)
124 SilcClientInternal app = (SilcClientInternal)client->application;
130 va_start(vp, command);
135 case SILC_COMMAND_JOIN:
136 app->screen->bottom_line->channel = va_arg(vp, char *);
137 silc_screen_print_bottom_line(app->screen, 0);
140 case SILC_COMMAND_NICK:
141 app->screen->bottom_line->nickname = va_arg(vp, char *);
142 silc_screen_print_bottom_line(app->screen, 0);
148 /* Called to indicate that connection was either successfully established
149 or connecting failed. This is also the first time application receives
150 the SilcClientConnection objecet which it should save somewhere. */
152 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
154 SilcClientInternal app = (SilcClientInternal)client->application;
157 app->screen->bottom_line->connection = conn->remote_host;
158 silc_screen_print_bottom_line(app->screen, 0);
163 /* Called to indicate that connection was disconnected to the server. */
165 void silc_disconnect(SilcClient client, SilcClientConnection conn)
167 SilcClientInternal app = (SilcClientInternal)client->application;
169 app->screen->bottom_line->connection = NULL;
170 silc_screen_print_bottom_line(app->screen, 0);
173 /* Asks passphrase from user on the input line. */
175 unsigned char *silc_ask_passphrase(SilcClient client,
176 SilcClientConnection conn)
178 SilcClientInternal app = (SilcClientInternal)conn->client->application;
179 char pass1[256], pass2[256];
186 wattroff(app->screen->input_win, A_INVIS);
187 silc_screen_input_print_prompt(app->screen, "Passphrase: ");
188 wattron(app->screen->input_win, A_INVIS);
191 memset(pass1, 0, sizeof(pass1));
192 wgetnstr(app->screen->input_win, pass1, sizeof(pass1));
194 /* Print retype prompt */
195 wattroff(app->screen->input_win, A_INVIS);
196 silc_screen_input_print_prompt(app->screen, "Retype passphrase: ");
197 wattron(app->screen->input_win, A_INVIS);
200 memset(pass2, 0, sizeof(pass2));
201 wgetnstr(app->screen->input_win, pass2, sizeof(pass2));
203 if (!strncmp(pass1, pass2, strlen(pass2)))
209 ret = silc_calloc(strlen(pass1), sizeof(char));
210 memcpy(ret, pass1, strlen(pass1));
212 memset(pass1, 0, sizeof(pass1));
213 memset(pass2, 0, sizeof(pass2));
215 wattroff(app->screen->input_win, A_INVIS);
216 silc_screen_input_reset(app->screen);
221 /* Verifies received public key. If user decides to trust the key it is
222 saved as trusted server key for later use. If user does not trust the
223 key this returns FALSE. */
225 int silc_verify_server_key(SilcClient client,
226 SilcClientConnection conn,
227 unsigned char *pk, unsigned int pk_len,
228 SilcSKEPKType pk_type)
230 SilcSocketConnection sock = conn->sock;
233 char *hostname, *fingerprint;
237 hostname = sock->hostname ? sock->hostname : sock->ip;
239 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
240 silc_say(client, conn, "We don't support server %s key type", hostname);
244 pw = getpwuid(getuid());
248 memset(filename, 0, sizeof(filename));
249 memset(file, 0, sizeof(file));
250 snprintf(file, sizeof(file) - 1, "serverkey_%s_%d.pub", hostname,
252 snprintf(filename, sizeof(filename) - 1, "%s/.silc/serverkeys/%s",
255 /* Check wheter this key already exists */
256 if (stat(filename, &st) < 0) {
258 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
259 silc_say(client, conn, "Received server %s public key", hostname);
260 silc_say(client, conn, "Fingerprint for the server %s key is", hostname);
261 silc_say(client, conn, "%s", fingerprint);
262 silc_free(fingerprint);
264 /* Ask user to verify the key and save it */
265 if (silc_client_ask_yes_no(client,
266 "Would you like to accept the key (y/n)? "))
268 /* Save the key for future checking */
269 silc_pkcs_save_public_key_data(filename, pk, pk_len,
274 /* The key already exists, verify it. */
275 SilcPublicKey public_key;
276 unsigned char *encpk;
277 unsigned int encpk_len;
279 /* Load the key file */
280 if (!silc_pkcs_load_public_key(filename, &public_key,
282 if (!silc_pkcs_load_public_key(filename, &public_key,
283 SILC_PKCS_FILE_BIN)) {
284 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
285 silc_say(client, conn, "Received server %s public key", hostname);
286 silc_say(client, conn, "Fingerprint for the server %s key is", hostname);
287 silc_say(client, conn, "%s", fingerprint);
288 silc_free(fingerprint);
289 silc_say(client, conn, "Could not load your local copy of the server %s key",
291 if (silc_client_ask_yes_no(client,
292 "Would you like to accept the key anyway (y/n)? "))
294 /* Save the key for future checking */
296 silc_pkcs_save_public_key_data(filename, pk, pk_len,
304 /* Encode the key data */
305 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
307 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
308 silc_say(client, conn, "Received server %s public key", hostname);
309 silc_say(client, conn, "Fingerprint for the server %s key is", hostname);
310 silc_say(client, conn, "%s", fingerprint);
311 silc_free(fingerprint);
312 silc_say(client, conn, "Your local copy of the server %s key is malformed",
314 if (silc_client_ask_yes_no(client,
315 "Would you like to accept the key anyway (y/n)? "))
317 /* Save the key for future checking */
319 silc_pkcs_save_public_key_data(filename, pk, pk_len,
327 if (memcmp(encpk, pk, encpk_len)) {
328 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
329 silc_say(client, conn, "Received server %s public key", hostname);
330 silc_say(client, conn, "Fingerprint for the server %s key is", hostname);
331 silc_say(client, conn, "%s", fingerprint);
332 silc_free(fingerprint);
333 silc_say(client, conn, "Server %s key does not match with your local copy",
335 silc_say(client, conn, "It is possible that the key has expired or changed");
336 silc_say(client, conn, "It is also possible that some one is performing "
337 "man-in-the-middle attack");
339 /* Ask user to verify the key and save it */
340 if (silc_client_ask_yes_no(client,
341 "Would you like to accept the key anyway (y/n)? "))
343 /* Save the key for future checking */
345 silc_pkcs_save_public_key_data(filename, pk, pk_len,
350 silc_say(client, conn, "Will not accept server %s key", hostname);
354 /* Local copy matched */
358 silc_say(client, conn, "Will not accept server %s key", hostname);
362 /* Find authentication method and authentication data by hostname and
363 port. The hostname may be IP address as well. The found authentication
364 method and authentication data is returned to `auth_meth', `auth_data'
365 and `auth_data_len'. The function returns TRUE if authentication method
366 is found and FALSE if not. `conn' may be NULL. */
368 int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
369 char *hostname, unsigned short port,
370 SilcProtocolAuthMeth *auth_meth,
371 unsigned char **auth_data,
372 unsigned int *auth_data_len)
374 SilcClientInternal app = (SilcClientInternal)client->application;
376 if (app->config->conns) {
377 SilcClientConfigSectionConnection *conn = NULL;
379 /* Check if we find a match from user configured connections */
380 conn = silc_client_config_find_connection(app->config,
384 /* Match found. Use the configured authentication method */
385 *auth_meth = conn->auth_meth;
387 if (conn->auth_data) {
388 *auth_data = strdup(conn->auth_data);
389 *auth_data_len = strlen(conn->auth_data);
399 /* SILC client operations */
400 SilcClientOperations ops = {
402 channel_message: silc_channel_message,
403 private_message: silc_private_message,
404 command: silc_command,
405 command_reply: silc_command_reply,
406 connect: silc_connect,
407 disconnect: silc_disconnect,
408 get_auth_method: silc_get_auth_method,
409 verify_server_key: silc_verify_server_key,
410 ask_passphrase: silc_ask_passphrase,