#include "clientincludes.h"
+static bool
+silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
+ SilcSocketType conn_type, unsigned char *pk,
+ uint32 pk_len, SilcSKEPKType pk_type)
+{
+ int i;
+ char file[256], filename[256], *fingerprint;
+ struct passwd *pw;
+ struct stat st;
+ char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
+ conn_type == SILC_SOCKET_TYPE_ROUTER) ?
+ "server" : "client");
+
+ if (pk_type != SILC_SKE_PK_TYPE_SILC) {
+ silc_say(client, conn, "We don't support %s public key type %d",
+ entity, pk_type);
+ return FALSE;
+ }
+
+ pw = getpwuid(getuid());
+ if (!pw)
+ return FALSE;
+
+ memset(filename, 0, sizeof(filename));
+ memset(file, 0, sizeof(file));
+
+ if (conn_type == SILC_SOCKET_TYPE_SERVER ||
+ conn_type == SILC_SOCKET_TYPE_ROUTER) {
+ snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
+ conn->sock->hostname, conn->sock->port);
+ snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
+ pw->pw_dir, entity, file);
+ } else {
+ /* Replace all whitespaces with `_'. */
+ fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
+ for (i = 0; i < strlen(fingerprint); i++)
+ if (fingerprint[i] == ' ')
+ fingerprint[i] = '_';
+
+ snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
+ snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
+ pw->pw_dir, entity, file);
+ silc_free(fingerprint);
+ }
+
+ /* Take fingerprint of the public key */
+ fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
+
+ /* Check whether this key already exists */
+ if (stat(filename, &st) < 0) {
+
+ silc_say(client, conn, "Received %s public key", entity);
+ silc_say(client, conn, "Fingerprint for the %s key is", entity);
+ silc_say(client, conn, "%s", fingerprint);
+
+ /* Ask user to verify the key and save it */
+ if (silc_client_ask_yes_no(client,
+ "Would you like to accept the key (y/n)? "))
+ {
+ /* Save the key for future checking */
+ silc_pkcs_save_public_key_data(filename, pk, pk_len,
+ SILC_PKCS_FILE_PEM);
+ silc_free(fingerprint);
+ return TRUE;
+ }
+ } else {
+ /* The key already exists, verify it. */
+ SilcPublicKey public_key;
+ unsigned char *encpk;
+ uint32 encpk_len;
+
+ /* Load the key file */
+ if (!silc_pkcs_load_public_key(filename, &public_key,
+ SILC_PKCS_FILE_PEM))
+ if (!silc_pkcs_load_public_key(filename, &public_key,
+ SILC_PKCS_FILE_BIN)) {
+ silc_say(client, conn, "Received %s public key", entity);
+ silc_say(client, conn, "Fingerprint for the %s key is", entity);
+ silc_say(client, conn, "%s", fingerprint);
+ silc_say(client, conn, "Could not load your local copy of the %s key",
+ entity);
+ if (silc_client_ask_yes_no(client,
+ "Would you like to accept the key anyway (y/n)? "))
+ {
+ /* Save the key for future checking */
+ unlink(filename);
+ silc_pkcs_save_public_key_data(filename, pk, pk_len,
+ SILC_PKCS_FILE_PEM);
+ silc_free(fingerprint);
+ return TRUE;
+ }
+
+ silc_free(fingerprint);
+ return FALSE;
+ }
+
+ /* Encode the key data */
+ encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
+ if (!encpk) {
+ silc_say(client, conn, "Received %s public key", entity);
+ silc_say(client, conn, "Fingerprint for the %s key is", entity);
+ silc_say(client, conn, "%s", fingerprint);
+ silc_say(client, conn, "Your local copy of the %s key is malformed",
+ entity);
+ if (silc_client_ask_yes_no(client,
+ "Would you like to accept the key anyway (y/n)? "))
+ {
+ /* Save the key for future checking */
+ unlink(filename);
+ silc_pkcs_save_public_key_data(filename, pk, pk_len,
+ SILC_PKCS_FILE_PEM);
+ silc_free(fingerprint);
+ return TRUE;
+ }
+
+ silc_free(fingerprint);
+ return FALSE;
+ }
+
+ if (memcmp(encpk, pk, encpk_len)) {
+ silc_say(client, conn, "Received %s public key", entity);
+ silc_say(client, conn, "Fingerprint for the %s key is", entity);
+ silc_say(client, conn, "%s", fingerprint);
+ silc_say(client, conn, "%s key does not match with your local copy",
+ entity);
+ silc_say(client, conn,
+ "It is possible that the key has expired or changed");
+ silc_say(client, conn, "It is also possible that some one is performing "
+ "man-in-the-middle attack");
+
+ /* Ask user to verify the key and save it */
+ if (silc_client_ask_yes_no(client,
+ "Would you like to accept the key anyway (y/n)? "))
+ {
+ /* Save the key for future checking */
+ unlink(filename);
+ silc_pkcs_save_public_key_data(filename, pk, pk_len,
+ SILC_PKCS_FILE_PEM);
+ silc_free(fingerprint);
+ return TRUE;
+ }
+
+ silc_say(client, conn, "Will not accept the %s key", entity);
+ silc_free(fingerprint);
+ return FALSE;
+ }
+
+ /* Local copy matched */
+ silc_free(fingerprint);
+ return TRUE;
+ }
+
+ silc_say(client, conn, "Will not accept the %s key", entity);
+ silc_free(fingerprint);
+ return FALSE;
+}
+
+void silc_say(SilcClient client, SilcClientConnection conn,
+ char *msg, ...)
+{
+ va_list vp;
+ char message[2048];
+ SilcClientInternal app = (SilcClientInternal)client->application;
+
+ memset(message, 0, sizeof(message));
+ strncat(message, "\n*** ", 5);
+
+ va_start(vp, msg);
+ vsprintf(message + 5, msg, vp);
+ va_end(vp);
+
+ /* Print the message */
+ silc_print_to_window(app->screen->output_win[0], message);
+}
+
/* Prints a message with three star (*) sign before the actual message
on the current output window. This is used to print command outputs
and error messages. */
-void silc_say(SilcClient client, SilcClientConnection conn,
- char *msg, ...)
+void silc_op_say(SilcClient client, SilcClientConnection conn,
+ SilcClientMessageType type, char *msg, ...)
{
va_list vp;
char message[2048];
received in the packet. The `channel_name' is the name of the channel. */
void silc_channel_message(SilcClient client, SilcClientConnection conn,
- SilcClientEntry sender, SilcChannelEntry channel
- , char *msg)
+ SilcClientEntry sender, SilcChannelEntry channel,
+ SilcMessageFlags flags, char *msg)
{
/* Message from client */
if (conn && !strcmp(conn->current_channel->channel_name,
channel->channel_name))
- silc_print(client, "<%s> %s", sender ? sender->nickname : "[<unknown>]",
- msg);
+ if (flags & SILC_MESSAGE_FLAG_ACTION)
+ silc_print(client, "* %s %s", sender ? sender->nickname : "[<unknown>]",
+ msg);
+ else if (flags & SILC_MESSAGE_FLAG_NOTICE)
+ silc_print(client, "- %s %s", sender ? sender->nickname : "[<unknown>]",
+ msg);
+ else
+ silc_print(client, "<%s> %s", sender ? sender->nickname : "[<unknown>]",
+ msg);
else
- silc_print(client, "<%s:%s> %s", sender ? sender->nickname : "[<unknown>]",
- channel->channel_name, msg);
+ if (flags & SILC_MESSAGE_FLAG_ACTION)
+ silc_print(client, "* %s:%s %s", sender ? sender->nickname :
+ "[<unknown>]",
+ channel->channel_name, msg);
+ else if (flags & SILC_MESSAGE_FLAG_NOTICE)
+ silc_print(client, "- %s:%s %s", sender ? sender->nickname :
+ "[<unknown>]",
+ channel->channel_name, msg);
+ else
+ silc_print(client, "<%s:%s> %s", sender ? sender->nickname :
+ "[<unknown>]",
+ channel->channel_name, msg);
}
/* Private message to the client. The `sender' is the nickname of the
sender received in the packet. */
void silc_private_message(SilcClient client, SilcClientConnection conn,
- SilcClientEntry sender, char *msg)
+ SilcClientEntry sender, SilcMessageFlags flags,
+ char *msg)
{
silc_print(client, "*%s* %s", sender->nickname, msg);
}
SilcClientEntry client_entry, client_entry2;
SilcChannelEntry channel_entry;
char *tmp = NULL;
- unsigned int tmp_int;
+ uint32 tmp_int;
va_start(vp, type);
break;
case SILC_NOTIFY_TYPE_INVITE:
+ (void)va_arg(vp, SilcChannelEntry);
+ tmp = va_arg(vp, char *);
client_entry = va_arg(vp, SilcClientEntry);
- channel_entry = va_arg(vp, SilcChannelEntry);
snprintf(message, sizeof(message), "%s invites you to channel %s",
- client_entry->nickname, channel_entry->channel_name);
+ client_entry->nickname, tmp);
break;
case SILC_NOTIFY_TYPE_JOIN:
snprintf(message, sizeof(message), "%s (%s) has joined channel %s",
client_entry->nickname, client_entry->username,
channel_entry->channel_name);
+ if (client_entry == conn->local_entry) {
+ SilcChannelUser chu;
+
+ silc_list_start(channel_entry->clients);
+ while ((chu = silc_list_get(channel_entry->clients)) != SILC_LIST_END) {
+ if (chu->client == client_entry) {
+ if (app->screen->bottom_line->mode)
+ silc_free(app->screen->bottom_line->mode);
+ app->screen->bottom_line->mode = silc_client_chumode_char(chu->mode);
+ silc_screen_print_bottom_line(app->screen, 0);
+ break;
+ }
+ }
+ }
break;
case SILC_NOTIFY_TYPE_LEAVE:
case SILC_NOTIFY_TYPE_CMODE_CHANGE:
client_entry = va_arg(vp, SilcClientEntry);
- tmp = silc_client_chmode(va_arg(vp, unsigned int));
+ tmp_int = va_arg(vp, uint32);
+ (void)va_arg(vp, char *);
+ (void)va_arg(vp, char *);
channel_entry = va_arg(vp, SilcChannelEntry);
- if (tmp)
- snprintf(message, sizeof(message), "%s changed channel mode to +%s",
- client_entry->nickname, tmp);
- else
- snprintf(message, sizeof(message), "%s removed all channel modes",
- client_entry->nickname);
+
+ tmp = silc_client_chmode(tmp_int,
+ channel_entry->channel_key->cipher->name,
+ channel_entry->hmac->hmac->name);
+
+ if (tmp) {
+ if (client_entry) {
+ snprintf(message, sizeof(message), "%s changed channel mode to +%s",
+ client_entry->nickname, tmp);
+ } else {
+ snprintf(message, sizeof(message),
+ "channel mode was changed to +%s (forced by router)",
+ tmp);
+ }
+ } else {
+ if (client_entry) {
+ snprintf(message, sizeof(message), "%s removed all channel modes",
+ client_entry->nickname);
+ } else {
+ snprintf(message, sizeof(message),
+ "Removed all channel modes (forced by router)");
+ }
+ }
+
if (app->screen->bottom_line->channel_mode)
silc_free(app->screen->bottom_line->channel_mode);
app->screen->bottom_line->channel_mode = tmp;
case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
client_entry = va_arg(vp, SilcClientEntry);
- tmp_int = va_arg(vp, unsigned int);
+ tmp_int = va_arg(vp, uint32);
tmp = silc_client_chumode(tmp_int);
client_entry2 = va_arg(vp, SilcClientEntry);
channel_entry = va_arg(vp, SilcChannelEntry);
return;
case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
+ return;
break;
case SILC_NOTIFY_TYPE_KICKED:
}
break;
+ case SILC_NOTIFY_TYPE_KILLED:
+ client_entry = va_arg(vp, SilcClientEntry);
+ tmp = va_arg(vp, char *);
+ channel_entry = va_arg(vp, SilcChannelEntry);
+
+ if (client_entry == conn->local_entry) {
+ snprintf(message, sizeof(message),
+ "You have been killed from the SILC Network %s%s%s",
+ tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
+ } else {
+ snprintf(message, sizeof(message),
+ "%s%s%s has been killed from the SILC Network %s%s%s",
+ client_entry->nickname,
+ client_entry->server ? "@" : "",
+ client_entry->server ? client_entry->server : "",
+ tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
+ }
+ break;
+
+ case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
+ {
+ SilcClientEntry *clients;
+ uint32 clients_count;
+ int i;
+
+ (void)va_arg(vp, void *);
+ clients = va_arg(vp, SilcClientEntry *);
+ clients_count = va_arg(vp, uint32);
+
+ for (i = 0; i < clients_count; i++) {
+ if (clients[i]->server)
+ snprintf(message, sizeof(message), "Server signoff: %s@%s %s%s%s",
+ clients[i]->nickname, clients[i]->server,
+ tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
+ else
+ snprintf(message, sizeof(message), "Server signoff: %s %s%s%s",
+ clients[i]->nickname,
+ tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
+ silc_print(client, "*** %s", message);
+ memset(message, 0, sizeof(message));
+ }
+ return;
+ }
+
default:
break;
}
break;
case SILC_COMMAND_LEAVE:
-#if 0
- if (!strncmp(conn->current_channel->channel_name, name, strlen(name))) {
- app->screen->bottom_line->channel = NULL;
- silc_screen_print_bottom_line(app->screen, 0);
- }
-#endif
+ /* We won't talk anymore on this channel */
+ silc_say(client, conn, "You have left channel %s",
+ conn->current_channel->channel_name);
break;
}
void silc_client_show_users(SilcClient client,
SilcClientConnection conn,
SilcClientEntry *clients,
- unsigned int clients_count,
+ uint32 clients_count,
void *context)
{
SilcChannelEntry channel = (SilcChannelEntry)context;
k++;
}
- client->ops->say(client, conn, "Users on %s: %s", channel->channel_name,
+ silc_say(client, conn, "Users on %s: %s", channel->channel_name,
name_list);
silc_free(name_list);
}
{
char buf[1024], *nickname, *username, *realname;
int len;
- unsigned int idle;
+ uint32 idle, mode;
+ SilcBuffer channels;
- if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
+ if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
+ status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
char *tmp;
tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
3, NULL);
if (tmp)
- client->ops->say(client, conn, "%s: %s", tmp,
+ silc_say(client, conn, "%s: %s", tmp,
silc_client_command_status_message(status));
else
- client->ops->say(client, conn, "%s",
+ silc_say(client, conn, "%s",
silc_client_command_status_message(status));
break;
}
nickname = va_arg(vp, char *);
username = va_arg(vp, char *);
realname = va_arg(vp, char *);
- (void)va_arg(vp, void *);
- idle = va_arg(vp, unsigned int);
+ channels = va_arg(vp, SilcBuffer);
+ mode = va_arg(vp, uint32);
+ idle = va_arg(vp, uint32);
memset(buf, 0, sizeof(buf));
}
if (username) {
- strncat(buf, username, strlen(nickname));
+ strncat(buf, username, strlen(username));
}
if (realname) {
strncat(buf, ")", 1);
}
- client->ops->say(client, conn, "%s", buf);
+ silc_say(client, conn, "%s", buf);
+
+ if (channels) {
+ SilcDList list = silc_channel_payload_parse_list(channels);
+ if (list) {
+ SilcChannelPayload entry;
+
+ memset(buf, 0, sizeof(buf));
+ strcat(buf, "on channels: ");
+
+ silc_dlist_start(list);
+ while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
+ char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
+ uint32 name_len;
+ char *name = silc_channel_get_name(entry, &name_len);
+
+ if (m)
+ strncat(buf, m, strlen(m));
+ strncat(buf, name, name_len);
+ strncat(buf, " ", 1);
+ silc_free(m);
+ }
+
+ silc_say(client, conn, "%s", buf);
+ silc_channel_payload_list_free(list);
+ }
+ }
+
+ if (mode) {
+ if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
+ (mode & SILC_UMODE_ROUTER_OPERATOR))
+ silc_say(client, conn, "%s is %s", nickname,
+ (mode & SILC_UMODE_SERVER_OPERATOR) ?
+ "Server Operator" :
+ (mode & SILC_UMODE_ROUTER_OPERATOR) ?
+ "SILC Operator" : "[Unknown mode]");
+
+ if (mode & SILC_UMODE_GONE)
+ silc_say(client, conn, "%s is gone", nickname);
+ }
+
if (idle && nickname)
- client->ops->say(client, conn, "%s has been idle %d %s",
+ silc_say(client, conn, "%s has been idle %d %s",
nickname,
idle > 60 ? (idle / 60) : idle,
idle > 60 ? "minutes" : "seconds");
char buf[1024], *nickname, *username, *realname;
int len;
- if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
+ if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
+ status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
char *tmp;
tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
3, NULL);
if (tmp)
- client->ops->say(client, conn, "%s: %s", tmp,
+ silc_say(client, conn, "%s: %s", tmp,
silc_client_command_status_message(status));
else
- client->ops->say(client, conn, "%s",
+ silc_say(client, conn, "%s",
silc_client_command_status_message(status));
break;
}
strncat(buf, ")", 1);
}
- client->ops->say(client, conn, "%s", buf);
+ silc_say(client, conn, "%s", buf);
+ }
+ break;
+
+ case SILC_COMMAND_INVITE:
+ {
+ SilcChannelEntry channel;
+ char *invite_list;
+
+ if (!success)
+ return;
+
+ channel = va_arg(vp, SilcChannelEntry);
+ invite_list = va_arg(vp, char *);
+
+ if (invite_list)
+ silc_say(client, conn, "%s invite list: %s", channel->channel_name,
+ invite_list);
+ else
+ silc_say(client, conn, "%s invite list not set",
+ channel->channel_name);
}
break;
case SILC_COMMAND_JOIN:
{
- unsigned int mode;
+ uint32 mode;
char *topic;
SilcBuffer client_id_list;
- unsigned int list_count;
+ uint32 list_count;
SilcChannelEntry channel;
if (!success)
app->screen->bottom_line->channel = va_arg(vp, char *);
channel = va_arg(vp, SilcChannelEntry);
- mode = va_arg(vp, unsigned int);
- (void)va_arg(vp, unsigned int);
+ mode = va_arg(vp, uint32);
+ (void)va_arg(vp, uint32);
(void)va_arg(vp, unsigned char *);
(void)va_arg(vp, unsigned char *);
(void)va_arg(vp, unsigned char *);
topic = va_arg(vp, char *);
(void)va_arg(vp, unsigned char *);
- list_count = va_arg(vp, unsigned int);
+ list_count = va_arg(vp, uint32);
client_id_list = va_arg(vp, SilcBuffer);
if (topic)
- client->ops->say(client, conn, "Topic for %s: %s",
+ silc_say(client, conn, "Topic for %s: %s",
app->screen->bottom_line->channel, topic);
- app->screen->bottom_line->channel_mode = silc_client_chmode(mode);
+ app->screen->bottom_line->channel_mode =
+ silc_client_chmode(mode,
+ channel->channel_key->cipher->name,
+ channel->hmac->hmac->name);
silc_screen_print_bottom_line(app->screen, 0);
/* Resolve the client information */
}
break;
+ case SILC_COMMAND_LIST:
+ {
+ char *topic, *name;
+ int usercount;
+ unsigned char buf[256], tmp[16];
+ int i, len;
+
+ if (!success)
+ return;
+
+ (void)va_arg(vp, SilcChannelEntry);
+ name = va_arg(vp, char *);
+ topic = va_arg(vp, char *);
+ usercount = va_arg(vp, int);
+
+ if (status == SILC_STATUS_LIST_START ||
+ status == SILC_STATUS_OK)
+ silc_say(client, conn,
+ " Channel Users Topic");
+
+ memset(buf, 0, sizeof(buf));
+ strncat(buf, " ", 2);
+ len = strlen(name);
+ strncat(buf, name, len > 40 ? 40 : len);
+ if (len < 40)
+ for (i = 0; i < 40 - len; i++)
+ strcat(buf, " ");
+ strcat(buf, " ");
+
+ memset(tmp, 0, sizeof(tmp));
+ if (usercount) {
+ snprintf(tmp, sizeof(tmp), "%d", usercount);
+ strcat(buf, tmp);
+ }
+ len = strlen(tmp);
+ if (len < 10)
+ for (i = 0; i < 10 - len; i++)
+ strcat(buf, " ");
+ strcat(buf, " ");
+
+ if (topic) {
+ len = strlen(topic);
+ strncat(buf, topic, len);
+ }
+
+ silc_say(client, conn, "%s", buf);
+ }
+ break;
+
+ case SILC_COMMAND_UMODE:
+ {
+ uint32 mode;
+
+ if (!success)
+ return;
+
+ mode = va_arg(vp, uint32);
+
+ if (!mode && app->screen->bottom_line->umode) {
+ silc_free(app->screen->bottom_line->umode);
+ app->screen->bottom_line->umode = NULL;
+ }
+
+ if (mode & SILC_UMODE_SERVER_OPERATOR) {
+ if (app->screen->bottom_line->umode)
+ silc_free(app->screen->bottom_line->umode);
+ app->screen->bottom_line->umode = strdup("Server Operator");;
+ }
+
+ if (mode & SILC_UMODE_ROUTER_OPERATOR) {
+ if (app->screen->bottom_line->umode)
+ silc_free(app->screen->bottom_line->umode);
+ app->screen->bottom_line->umode = strdup("SILC Operator");;
+ }
+
+ silc_screen_print_bottom_line(app->screen, 0);
+ }
+ break;
+
+ case SILC_COMMAND_OPER:
+ if (status == SILC_STATUS_OK) {
+ conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
+ if (app->screen->bottom_line->umode)
+ silc_free(app->screen->bottom_line->umode);
+ app->screen->bottom_line->umode = strdup("Server Operator");;
+ silc_screen_print_bottom_line(app->screen, 0);
+ }
+ break;
+
+ case SILC_COMMAND_SILCOPER:
+ if (status == SILC_STATUS_OK) {
+ conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
+ if (app->screen->bottom_line->umode)
+ silc_free(app->screen->bottom_line->umode);
+ app->screen->bottom_line->umode = strdup("SILC Operator");;
+ silc_screen_print_bottom_line(app->screen, 0);
+ }
+ break;
+
case SILC_COMMAND_USERS:
- if (!success)
- return;
+ {
+ SilcChannelEntry channel;
+ int line_len;
+ char *line;
+
+ if (!success)
+ return;
- silc_list_start(conn->current_channel->clients);
- while ((chu = silc_list_get(conn->current_channel->clients))
- != SILC_LIST_END) {
- if (chu->client == conn->local_entry) {
- if (app->screen->bottom_line->mode)
- silc_free(app->screen->bottom_line->mode);
- app->screen->bottom_line->mode =
- silc_client_chumode_char(chu->mode);
- silc_screen_print_bottom_line(app->screen, 0);
- break;
+ channel = va_arg(vp, SilcChannelEntry);
+
+ /* There are two ways to do this, either parse the list (that
+ the command_reply sends (just take it with va_arg()) or just
+ traverse the channel's client list. I'll do the latter. See
+ JOIN command reply for example for the list. */
+
+ silc_say(client, conn, "Users on %s", channel->channel_name);
+
+ line = silc_calloc(1024, sizeof(*line));
+ line_len = 1024;
+ silc_list_start(channel->clients);
+ while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
+ SilcClientEntry e = chu->client;
+ int i, len1;
+ char *m, tmp[80];
+
+ memset(line, 0, line_len);
+
+ if (chu->client == conn->local_entry) {
+ /* Update status line */
+ if (app->screen->bottom_line->mode)
+ silc_free(app->screen->bottom_line->mode);
+ app->screen->bottom_line->mode =
+ silc_client_chumode_char(chu->mode);
+ silc_screen_print_bottom_line(app->screen, 0);
+ }
+
+ if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
+ silc_free(line);
+ line_len += strlen(e->nickname) + strlen(e->server) + 100;
+ line = silc_calloc(line_len, sizeof(*line));
+ }
+
+ memset(tmp, 0, sizeof(tmp));
+ m = silc_client_chumode_char(chu->mode);
+
+ strncat(line, " ", 1);
+ strncat(line, e->nickname, strlen(e->nickname));
+ strncat(line, e->server ? "@" : "", 1);
+
+ len1 = 0;
+ if (e->server)
+ len1 = strlen(e->server);
+ strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
+
+ len1 = strlen(line);
+ if (len1 >= 30) {
+ memset(&line[29], 0, len1 - 29);
+ } else {
+ for (i = 0; i < 30 - len1 - 1; i++)
+ strcat(line, " ");
+ }
+
+ if (e->mode & SILC_UMODE_GONE)
+ strcat(line, " G");
+ else
+ strcat(line, " H");
+ strcat(tmp, m ? m : "");
+ strncat(line, tmp, strlen(tmp));
+
+ if (strlen(tmp) < 5)
+ for (i = 0; i < 5 - strlen(tmp); i++)
+ strcat(line, " ");
+
+ strcat(line, e->username ? e->username : "");
+
+ silc_say(client, conn, "%s", line);
+
+ if (m)
+ silc_free(m);
}
+
+ silc_free(line);
+ }
+ break;
+
+ case SILC_COMMAND_BAN:
+ {
+ SilcChannelEntry channel;
+ char *ban_list;
+
+ if (!success)
+ return;
+
+ channel = va_arg(vp, SilcChannelEntry);
+ ban_list = va_arg(vp, char *);
+
+ if (ban_list)
+ silc_say(client, conn, "%s ban list: %s", channel->channel_name,
+ ban_list);
+ else
+ silc_say(client, conn, "%s ban list not set", channel->channel_name);
+ }
break;
+
+ case SILC_COMMAND_GETKEY:
+ {
+ SilcIdType id_type;
+ void *entry;
+ SilcPublicKey public_key;
+ unsigned char *pk;
+ uint32 pk_len;
+
+ id_type = va_arg(vp, uint32);
+ entry = va_arg(vp, void *);
+ public_key = va_arg(vp, SilcPublicKey);
+
+ pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+
+ if (id_type == SILC_ID_CLIENT) {
+ silc_verify_public_key_internal(client, conn,
+ SILC_SOCKET_TYPE_CLIENT,
+ pk, pk_len, SILC_SKE_PK_TYPE_SILC);
+ }
+
+ silc_free(pk);
}
+
+ case SILC_COMMAND_TOPIC:
+ {
+ SilcChannelEntry channel;
+ char *topic;
+
+ if (!success)
+ return;
+
+ channel = va_arg(vp, SilcChannelEntry);
+ topic = va_arg(vp, char *);
+
+ if (topic)
+ silc_say(client, conn,
+ "Topic on channel %s: %s", channel->channel_name,
+ topic);
+ }
+ break;
+
+ default:
+ break;
}
}
/* Asks passphrase from user on the input line. */
-unsigned char *silc_ask_passphrase(SilcClient client,
- SilcClientConnection conn)
+void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
+ SilcAskPassphrase completion, void *context)
{
SilcClientInternal app = (SilcClientInternal)conn->client->application;
char pass1[256], pass2[256];
- char *ret;
int try = 3;
while(try) {
try--;
}
- ret = silc_calloc(strlen(pass1), sizeof(char));
- memcpy(ret, pass1, strlen(pass1));
-
- memset(pass1, 0, sizeof(pass1));
- memset(pass2, 0, sizeof(pass2));
-
wattroff(app->screen->input_win, A_INVIS);
silc_screen_input_reset(app->screen);
- return ret;
+ /* Deliver the passphrase to the library */
+ completion(pass1, strlen(pass1), context);
+
+ memset(pass1, 0, sizeof(pass1));
+ memset(pass2, 0, sizeof(pass2));
}
-/* Verifies received public key. If user decides to trust the key it is
- saved as trusted server key for later use. If user does not trust the
- key this returns FALSE. */
+/* Verifies received public key. The `conn_type' indicates which entity
+ (server, client etc.) has sent the public key. If user decides to trust
+ the key may be saved as trusted public key for later use. The
+ `completion' must be called after the public key has been verified. */
-int silc_verify_server_key(SilcClient client,
- SilcClientConnection conn,
- unsigned char *pk, unsigned int pk_len,
- SilcSKEPKType pk_type)
+void silc_verify_public_key(SilcClient client, SilcClientConnection conn,
+ SilcSocketType conn_type, unsigned char *pk,
+ uint32 pk_len, SilcSKEPKType pk_type,
+ SilcVerifyPublicKey completion, void *context)
{
- SilcSocketConnection sock = conn->sock;
- char filename[256];
- char file[256];
- char *hostname, *fingerprint;
- struct passwd *pw;
- struct stat st;
-
- hostname = sock->hostname ? sock->hostname : sock->ip;
-
- if (pk_type != SILC_SKE_PK_TYPE_SILC) {
- silc_say(client, conn, "We don't support server %s key type", hostname);
- return FALSE;
- }
-
- pw = getpwuid(getuid());
- if (!pw)
- return FALSE;
-
- memset(filename, 0, sizeof(filename));
- memset(file, 0, sizeof(file));
- snprintf(file, sizeof(file) - 1, "serverkey_%s_%d.pub", hostname,
- sock->port);
- snprintf(filename, sizeof(filename) - 1, "%s/.silc/serverkeys/%s",
- pw->pw_dir, file);
-
- /* Check wheter this key already exists */
- if (stat(filename, &st) < 0) {
-
- fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
- silc_say(client, conn, "Received server %s public key", hostname);
- silc_say(client, conn, "Fingerprint for the server %s key is", hostname);
- silc_say(client, conn, "%s", fingerprint);
- silc_free(fingerprint);
-
- /* Ask user to verify the key and save it */
- if (silc_client_ask_yes_no(client,
- "Would you like to accept the key (y/n)? "))
- {
- /* Save the key for future checking */
- silc_pkcs_save_public_key_data(filename, pk, pk_len,
- SILC_PKCS_FILE_PEM);
- return TRUE;
- }
- } else {
- /* The key already exists, verify it. */
- SilcPublicKey public_key;
- unsigned char *encpk;
- unsigned int encpk_len;
-
- /* Load the key file */
- if (!silc_pkcs_load_public_key(filename, &public_key,
- SILC_PKCS_FILE_PEM))
- if (!silc_pkcs_load_public_key(filename, &public_key,
- SILC_PKCS_FILE_BIN)) {
- fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
- silc_say(client, conn, "Received server %s public key", hostname);
- silc_say(client, conn, "Fingerprint for the server %s key is", hostname);
- silc_say(client, conn, "%s", fingerprint);
- silc_free(fingerprint);
- silc_say(client, conn, "Could not load your local copy of the server %s key",
- hostname);
- if (silc_client_ask_yes_no(client,
- "Would you like to accept the key anyway (y/n)? "))
- {
- /* Save the key for future checking */
- unlink(filename);
- silc_pkcs_save_public_key_data(filename, pk, pk_len,
- SILC_PKCS_FILE_PEM);
- return TRUE;
- }
-
- return FALSE;
- }
-
- /* Encode the key data */
- encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
- if (!encpk) {
- fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
- silc_say(client, conn, "Received server %s public key", hostname);
- silc_say(client, conn, "Fingerprint for the server %s key is", hostname);
- silc_say(client, conn, "%s", fingerprint);
- silc_free(fingerprint);
- silc_say(client, conn, "Your local copy of the server %s key is malformed",
- hostname);
- if (silc_client_ask_yes_no(client,
- "Would you like to accept the key anyway (y/n)? "))
- {
- /* Save the key for future checking */
- unlink(filename);
- silc_pkcs_save_public_key_data(filename, pk, pk_len,
- SILC_PKCS_FILE_PEM);
- return TRUE;
- }
-
- return FALSE;
- }
-
- if (memcmp(encpk, pk, encpk_len)) {
- fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
- silc_say(client, conn, "Received server %s public key", hostname);
- silc_say(client, conn, "Fingerprint for the server %s key is", hostname);
- silc_say(client, conn, "%s", fingerprint);
- silc_free(fingerprint);
- silc_say(client, conn, "Server %s key does not match with your local copy",
- hostname);
- silc_say(client, conn, "It is possible that the key has expired or changed");
- silc_say(client, conn, "It is also possible that some one is performing "
- "man-in-the-middle attack");
-
- /* Ask user to verify the key and save it */
- if (silc_client_ask_yes_no(client,
- "Would you like to accept the key anyway (y/n)? "))
- {
- /* Save the key for future checking */
- unlink(filename);
- silc_pkcs_save_public_key_data(filename, pk, pk_len,
- SILC_PKCS_FILE_PEM);
- return TRUE;
- }
-
- silc_say(client, conn, "Will not accept server %s key", hostname);
- return FALSE;
- }
-
- /* Local copy matched */
- return TRUE;
+ if (silc_verify_public_key_internal(client, conn, conn_type, pk,
+ pk_len, pk_type)) {
+ completion(TRUE, context);
+ return;
}
- silc_say(client, conn, "Will not accept server %s key", hostname);
- return FALSE;
+ completion(FALSE, context);
}
/* Find authentication method and authentication data by hostname and
is found and FALSE if not. `conn' may be NULL. */
int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
- char *hostname, unsigned short port,
+ char *hostname, uint16 port,
SilcProtocolAuthMeth *auth_meth,
unsigned char **auth_data,
- unsigned int *auth_data_len)
+ uint32 *auth_data_len)
{
SilcClientInternal app = (SilcClientInternal)client->application;
- if (app->config->conns) {
+ if (app->config && app->config->conns) {
SilcClientConfigSectionConnection *conn = NULL;
/* Check if we find a match from user configured connections */
}
}
- return FALSE;
+ *auth_meth = SILC_AUTH_NONE;
+ *auth_data = NULL;
+ *auth_data_len = 0;
+
+ return TRUE;
}
/* Notifies application that failure packet was received. This is called
void silc_failure(SilcClient client, SilcClientConnection conn,
SilcProtocol protocol, void *failure)
{
+ if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
+ SilcSKEStatus status = (SilcSKEStatus)failure;
+
+ if (status == SILC_SKE_STATUS_BAD_VERSION)
+ silc_say(client, conn,
+ "You are running incompatible client version (it may be "
+ "too old or too new)");
+ if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
+ silc_say(client, conn, "Server does not support your public key type");
+ if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
+ silc_say(client, conn,
+ "Server does not support one of your proposed KE group");
+ if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
+ silc_say(client, conn,
+ "Server does not support one of your proposed cipher");
+ if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
+ silc_say(client, conn,
+ "Server does not support one of your proposed PKCS");
+ if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
+ silc_say(client, conn,
+ "Server does not support one of your proposed hash function");
+ if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
+ silc_say(client, conn,
+ "Server does not support one of your proposed HMAC");
+ if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
+ silc_say(client, conn, "Incorrect signature");
+ }
+
+ if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
+ uint32 err = (uint32)failure;
+ if (err == SILC_AUTH_FAILED)
+ silc_say(client, conn, "Authentication failed");
+ }
}
/* Asks whether the user would like to perform the key agreement protocol.
SilcKeyAgreementCallback *completion,
void **context)
{
+ char host[256];
+
+ /* We will just display the info on the screen and return FALSE and user
+ will have to start the key agreement with a command. */
+
+ if (hostname) {
+ memset(host, 0, sizeof(host));
+ snprintf(host, sizeof(host) - 1, "(%s on port %d)", hostname, port);
+ }
+
+ silc_say(client, conn, "%s wants to perform key agreement %s",
+ client_entry->nickname, hostname ? host : "");
+
+ *completion = NULL;
+ *context = NULL;
return FALSE;
}
/* SILC client operations */
SilcClientOperations ops = {
- say: silc_say,
- channel_message: silc_channel_message,
- private_message: silc_private_message,
- notify: silc_notify,
- command: silc_command,
- command_reply: silc_command_reply,
- connect: silc_connect,
- disconnect: silc_disconnect,
- get_auth_method: silc_get_auth_method,
- verify_server_key: silc_verify_server_key,
- ask_passphrase: silc_ask_passphrase,
- failure: silc_failure,
- key_agreement: silc_key_agreement,
+ silc_op_say,
+ silc_channel_message,
+ silc_private_message,
+ silc_notify,
+ silc_command,
+ silc_command_reply,
+ silc_connect,
+ silc_disconnect,
+ silc_get_auth_method,
+ silc_verify_public_key,
+ silc_ask_passphrase,
+ silc_failure,
+ silc_key_agreement,
};