X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=apps%2Firssi%2Fsrc%2Fsilc%2Fcore%2Fclient_ops.c;h=79be2e8c7b4eef61cc9c1e9d7bbbcd1e63e4c332;hb=017dec75a98209fbef49eb496c2269b0c49e736d;hp=ca4f64317649bcccf4b2bdf4efdd94c9da0698e1;hpb=a8fc75f5bc7b03a7d13f9cbd77fe65de14956e48;p=silc.git diff --git a/apps/irssi/src/silc/core/client_ops.c b/apps/irssi/src/silc/core/client_ops.c index ca4f6431..79be2e8c 100644 --- a/apps/irssi/src/silc/core/client_ops.c +++ b/apps/irssi/src/silc/core/client_ops.c @@ -45,7 +45,7 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn, SilcVerifyPublicKey completion, void *context); void silc_say(SilcClient client, SilcClientConnection conn, - char *msg, ...) + SilcClientMessageType type, char *msg, ...) { SILC_SERVER_REC *server; va_list va; @@ -76,10 +76,9 @@ void silc_say_error(char *msg, ...) /* Message for a channel. The `sender' is the nickname of the sender 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, - SilcMessageFlags flags, char *msg) +void silc_channel_message(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcChannelEntry channel, + SilcMessageFlags flags, char *msg) { SILC_SERVER_REC *server; SILC_NICK_REC *nick; @@ -87,28 +86,31 @@ silc_channel_message(SilcClient client, SilcClientConnection conn, server = conn == NULL ? NULL : conn->context; chanrec = silc_channel_find_entry(server, channel); + if (!chanrec) + return; nick = silc_nicklist_find(chanrec, sender); if (flags & SILC_MESSAGE_FLAG_ACTION) printformat_module("fe-common/silc", server, channel->channel_name, - MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION, msg); + MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION, + nick == NULL ? "[]" : nick->nick, msg); else if (flags & SILC_MESSAGE_FLAG_NOTICE) printformat_module("fe-common/silc", server, channel->channel_name, - MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE, msg); + MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE, + nick == NULL ? "[]" : nick->nick, msg); else signal_emit("message public", 6, server, msg, nick == NULL ? "[]" : nick->nick, - nick == NULL ? NULL : nick->host, + nick == NULL ? "" : nick->host == NULL ? "" : nick->host, chanrec->name, nick); } /* 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, SilcMessageFlags flags, +void silc_private_message(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcMessageFlags flags, char *msg) { SILC_SERVER_REC *server; @@ -153,7 +155,7 @@ static NOTIFY_REC notifies[] = { }; void silc_notify(SilcClient client, SilcClientConnection conn, - SilcNotifyType type, ...) + SilcNotifyType type, ...) { SILC_SERVER_REC *server; va_list va; @@ -171,7 +173,8 @@ void silc_notify(SilcClient client, SilcClientConnection conn, signal_emit(signal, 2, server, va); } else { /* Unknown notify */ - printtext(server, NULL, MSGLEVEL_CRAP, "Unknown notify type %d", type); + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type); } va_end(va); @@ -181,11 +184,15 @@ void silc_notify(SilcClient client, SilcClientConnection conn, or connecting failed. This is also the first time application receives the SilcClientConnection objecet which it should save somewhere. */ -void -silc_connect(SilcClient client, SilcClientConnection conn, int success) +void silc_connect(SilcClient client, SilcClientConnection conn, int success) { SILC_SERVER_REC *server = conn->context; + if (!server && !success) { + silc_client_close_connection(client, NULL, conn); + return; + } + if (success) { server->connected = TRUE; signal_emit("event connected", 1, server); @@ -198,8 +205,7 @@ silc_connect(SilcClient client, SilcClientConnection conn, int success) /* Called to indicate that connection was disconnected to the server. */ -void -silc_disconnect(SilcClient client, SilcClientConnection conn) +void silc_disconnect(SilcClient client, SilcClientConnection conn) { SILC_SERVER_REC *server = conn->context; @@ -218,21 +224,37 @@ silc_disconnect(SilcClient client, SilcClientConnection conn) after application has called the command. Just to tell application that the command really was processed. */ -void -silc_command(SilcClient client, SilcClientConnection conn, - SilcClientCommandContext cmd_context, int success, - SilcCommand command) +void silc_command(SilcClient client, SilcClientConnection conn, + SilcClientCommandContext cmd_context, int success, + SilcCommand command) { + SILC_SERVER_REC *server = conn->context; + + if (!success) + return; + + switch(command) { + case SILC_COMMAND_INVITE: + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING, + cmd_context->argv[2], + (cmd_context->argv[1][0] == '*' ? + (char *)conn->current_channel->channel_name : + (char *)cmd_context->argv[1])); + break; + default: + break; + } } /* Client info resolving callback when JOIN command reply is received. This will cache all users on the channel. */ -void silc_client_join_get_users(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - uint32 clients_count, - void *context) +static void silc_client_join_get_users(SilcClient client, + SilcClientConnection conn, + SilcClientEntry *clients, + uint32 clients_count, + void *context) { SilcChannelEntry channel = (SilcChannelEntry)context; SilcChannelUser chu; @@ -311,9 +333,10 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, switch(command) { case SILC_COMMAND_WHOIS: { - char buf[1024], *nickname, *username, *realname; + char buf[1024], *nickname, *username, *realname, *nick; uint32 idle, mode; SilcBuffer channels; + SilcClientEntry client_entry; if (status == SILC_STATUS_ERR_NO_SUCH_NICK || status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) { @@ -331,7 +354,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, if (!success) return; - (void)va_arg(vp, SilcClientEntry); + client_entry = va_arg(vp, SilcClientEntry); nickname = va_arg(vp, char *); username = va_arg(vp, char *); realname = va_arg(vp, char *); @@ -339,9 +362,14 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, mode = va_arg(vp, uint32); idle = va_arg(vp, uint32); + silc_parse_userfqdn(nickname, &nick, NULL); + printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, + SILCTXT_WHOIS_USERINFO, nickname, + client_entry->username, client_entry->hostname, + nick, client_entry->nickname); printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, - SILCTXT_WHOIS_USERINFO, nickname, username, - realname); + SILCTXT_WHOIS_REALNAME, realname); + silc_free(nick); if (channels) { SilcDList list = silc_channel_payload_parse_list(channels); @@ -431,21 +459,27 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, { SilcChannelEntry channel; char *invite_list; + SilcArgumentPayload args; + int argc = 0; if (!success) return; - /* XXX should use irssi routines */ - channel = va_arg(vp, SilcChannelEntry); invite_list = va_arg(vp, char *); - + + args = silc_command_get_args(cmd_payload); + if (args) + argc = silc_argument_get_arg_num(args); + 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); + printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, + SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name, + invite_list); + else if (argc == 3) + printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, + SILCTXT_CHANNEL_NO_INVITE_LIST, + channel->channel_name); } break; @@ -457,6 +491,9 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, SilcBuffer client_id_list; uint32 list_count; + if (!success) + return; + channel = va_arg(vp, char *); channel_entry = va_arg(vp, SilcChannelEntry); modei = va_arg(vp, uint32); @@ -469,22 +506,19 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, list_count = va_arg(vp, uint32); client_id_list = va_arg(vp, SilcBuffer); - if (!success) - return; - chanrec = silc_channel_find(server, channel); - if (chanrec != NULL && !success) - channel_destroy(CHANNEL(chanrec)); - else if (chanrec == NULL && success) + if (!chanrec) chanrec = silc_channel_create(server, channel, TRUE); - + if (topic) { g_free_not_null(chanrec->topic); chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic); signal_emit("channel topic changed", 1, chanrec); } - mode = silc_client_chmode(modei, channel_entry); + mode = silc_client_chmode(modei, + channel_entry->channel_key->cipher->name, + channel_entry->hmac->hmac->name); g_free_not_null(chanrec->mode); chanrec->mode = g_strdup(mode == NULL ? "" : mode); signal_emit("channel mode changed", 1, chanrec); @@ -519,14 +553,11 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, { char *topic, *name; int usercount; - unsigned char buf[256], tmp[16]; - int i, len; + char users[20]; if (!success) return; - /* XXX should use irssi routines */ - (void)va_arg(vp, SilcChannelEntry); name = va_arg(vp, char *); topic = va_arg(vp, char *); @@ -534,35 +565,13 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, 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); + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_LIST_HEADER); + + snprintf(users, sizeof(users) - 1, "%d", usercount); + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_LIST, + name, users, topic ? topic : ""); } break; @@ -575,93 +584,67 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, mode = va_arg(vp, uint32); - /* XXX todo */ + if (mode & SILC_UMODE_SERVER_OPERATOR) + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_SERVER_OPER); + + if (mode & SILC_UMODE_ROUTER_OPERATOR) + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER); } break; case SILC_COMMAND_OPER: - silc_say(client, conn, "You are now server operator"); + if (!success) + return; + + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_SERVER_OPER); break; case SILC_COMMAND_SILCOPER: - silc_say(client, conn, "You are now SILC operator"); + if (!success) + return; + + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER); break; case SILC_COMMAND_USERS: { SilcChannelEntry channel; SilcChannelUser chu; - int line_len; - char *line; if (!success) return; 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; + printformat_module("fe-common/silc", server, channel->channel_name, + MSGLEVEL_CRAP, SILCTXT_USERS_HEADER, + channel->channel_name); + 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 (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, " "); - } + char stat[5], *mode; + memset(stat, 0, sizeof(stat)); + mode = silc_client_chumode_char(chu->mode); if (e->mode & SILC_UMODE_GONE) - strcat(line, " G"); + strcat(stat, "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); + strcat(stat, "H"); + if (mode) + strcat(stat, mode); + + printformat_module("fe-common/silc", server, channel->channel_name, + MSGLEVEL_CRAP, SILCTXT_USERS, + e->nickname, stat, e->username, + e->realname ? e->realname : ""); + if (mode) + silc_free(mode); } - - silc_free(line); } break; @@ -673,16 +656,17 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, if (!success) return; - /* XXX should use irssi routines */ - 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); + printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, + SILCTXT_CHANNEL_BAN_LIST, channel->channel_name, + ban_list); else - silc_say(client, conn, "%s ban list not set", channel->channel_name); + printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, + SILCTXT_CHANNEL_NO_BAN_LIST, + channel->channel_name); } break; @@ -694,20 +678,29 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, unsigned char *pk; uint32 pk_len; + if (!success) + return; + 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, + + if (public_key) { + pk = silc_pkcs_public_key_encode(public_key, &pk_len); + + silc_verify_public_key_internal(client, conn, + (id_type == SILC_ID_CLIENT ? + SILC_SOCKET_TYPE_CLIENT : + SILC_SOCKET_TYPE_SERVER), pk, pk_len, SILC_SKE_PK_TYPE_SILC, NULL, NULL); + silc_free(pk); + } else { + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY); } - - silc_free(pk); } + break; case SILC_COMMAND_TOPIC: { @@ -730,9 +723,14 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, printformat_module("fe-common/silc", server, channel->channel_name, MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC, channel->channel_name, topic); + } else { + printformat_module("fe-common/silc", server, channel->channel_name, + MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET, + channel->channel_name); } } break; + } va_end(vp); @@ -770,12 +768,13 @@ static void verify_public_key_completion(const char *line, void *context) if (verify->completion) verify->completion(FALSE, verify->context); - silc_say(verify->client, - verify->conn, "Will not accept the %s key", verify->entity); + printformat_module("fe-common/silc", NULL, NULL, + MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, verify->entity); } silc_free(verify->filename); silc_free(verify->entity); + silc_free(verify->pk); silc_free(verify); } @@ -786,7 +785,7 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn, SilcVerifyPublicKey completion, void *context) { int i; - char file[256], filename[256], *fingerprint; + char file[256], filename[256], *fingerprint, *format; struct passwd *pw; struct stat st; char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER || @@ -795,8 +794,9 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn, PublicKeyVerify verify; if (pk_type != SILC_SKE_PK_TYPE_SILC) { - silc_say(client, conn, "We don't support %s public key type %d", - entity, pk_type); + printformat_module("fe-common/silc", NULL, NULL, + MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED, + entity, pk_type); if (completion) completion(FALSE, context); return; @@ -839,7 +839,8 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn, verify->conn = conn; verify->filename = strdup(filename); verify->entity = strdup(entity); - verify->pk = pk; + verify->pk = silc_calloc(pk_len, sizeof(*verify->pk)); + memcpy(verify->pk, pk, pk_len); verify->pk_len = pk_len; verify->pk_type = pk_type; verify->completion = completion; @@ -849,13 +850,15 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn, if (stat(filename, &st) < 0) { /* Key does not exist, ask user to verify the key and save it */ - 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); - + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_RECEIVED, entity); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint); + format = format_get_text("fe-common/silc", NULL, NULL, NULL, + SILCTXT_PUBKEY_ACCEPT); keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion, - "Would you like to accept the key (y/n)? ", 0, - verify); + format, 0, verify); + g_free(format); silc_free(fingerprint); return; } else { @@ -869,15 +872,17 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn, 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); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_RECEIVED, entity); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_COULD_NOT_LOAD, entity); + format = format_get_text("fe-common/silc", NULL, NULL, NULL, + SILCTXT_PUBKEY_ACCEPT_ANYWAY); keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion, - "Would you like to accept the key " - "anyway (y/n)? ", 0, - verify); + format, 0, verify); + g_free(format); silc_free(fingerprint); return; } @@ -885,36 +890,40 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn, /* 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); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_RECEIVED, entity); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_MALFORMED, entity); + format = format_get_text("fe-common/silc", NULL, NULL, NULL, + SILCTXT_PUBKEY_ACCEPT_ANYWAY); keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion, - "Would you like to accept the key " - "anyway (y/n)? ", 0, - verify); + format, 0, verify); + g_free(format); silc_free(fingerprint); return; } /* Compare the keys */ 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"); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_RECEIVED, entity); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_NO_MATCH, entity); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_MAYBE_EXPIRED, entity); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_MITM_ATTACK, entity); /* Ask user to verify the key and save it */ + format = format_get_text("fe-common/silc", NULL, NULL, NULL, + SILCTXT_PUBKEY_ACCEPT_ANYWAY); keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion, - "Would you like to accept the key " - "anyway (y/n)? ", 0, - verify); + format, 0, verify); + g_free(format); silc_free(fingerprint); return; } @@ -958,7 +967,7 @@ void ask_passphrase_completion(const char *passphrase, void *context) } void silc_ask_passphrase(SilcClient client, SilcClientConnection conn, - SilcAskPassphrase completion, void *context) + SilcAskPassphrase completion, void *context) { AskPassphrase p = silc_calloc(1, sizeof(*p)); p->completion = completion; @@ -968,27 +977,69 @@ void silc_ask_passphrase(SilcClient client, SilcClientConnection conn, "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p); } +typedef struct { + SilcGetAuthMeth completion; + void *context; +} *InternalGetAuthMethod; + +/* Callback called when we've received the authentication method information + from the server after we've requested it. This will get the authentication + data from the user if needed. */ + +static void silc_get_auth_method_callback(SilcClient client, + SilcClientConnection conn, + SilcAuthMethod auth_meth, + void *context) +{ + InternalGetAuthMethod internal = (InternalGetAuthMethod)context; + + switch (auth_meth) { + case SILC_AUTH_NONE: + /* No authentication required. */ + (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context); + break; + case SILC_AUTH_PASSWORD: + /* Do not ask the passphrase from user, the library will ask it if + we do not provide it here. */ + (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context); + break; + case SILC_AUTH_PUBLIC_KEY: + /* Do not get the authentication data now, the library will generate + it using our default key, if we do not provide it here. */ + /* XXX In the future when we support multiple local keys and multiple + local certificates we will need to ask from user which one to use. */ + (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context); + break; + } + + silc_free(internal); +} + /* Find authentication method and authentication data by hostname and port. The hostname may be IP address as well. The found authentication method and authentication data is returned to `auth_meth', `auth_data' and `auth_data_len'. The function returns TRUE if authentication method is found and FALSE if not. `conn' may be NULL. */ -int silc_get_auth_method(SilcClient client, SilcClientConnection conn, - char *hostname, uint16 port, - SilcProtocolAuthMeth *auth_meth, - unsigned char **auth_data, - uint32 *auth_data_len) +void silc_get_auth_method(SilcClient client, SilcClientConnection conn, + char *hostname, uint16 port, + SilcGetAuthMeth completion, void *context) { + InternalGetAuthMethod internal; /* XXX must resolve from configuration whether this connection has any specific authentication data */ - *auth_meth = SILC_AUTH_NONE; - *auth_data = NULL; - *auth_data_len = 0; + /* If we do not have this connection configured by the user in a + configuration file then resolve the authentication method from the + server for this session. */ + internal = silc_calloc(1, sizeof(*internal)); + internal->completion = completion; + internal->context = context; - return TRUE; + silc_client_request_authentication_method(client, conn, + silc_get_auth_method_callback, + internal); } /* Notifies application that failure packet was received. This is called @@ -998,38 +1049,47 @@ int silc_get_auth_method(SilcClient client, SilcClientConnection conn, must explicitly cast it to correct type. Usually `failure' is 32 bit failure type (see protocol specs for all protocol failure types). */ -void -silc_failure(SilcClient client, SilcClientConnection conn, - SilcProtocol protocol, void *failure) +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_error("You are running incompatible client version (it may be " - "too old or too new)"); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_KE_BAD_VERSION); if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) - silc_say_error("Server does not support your public key type"); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY); if (status == SILC_SKE_STATUS_UNKNOWN_GROUP) - silc_say_error("Server does not support one of your proposed KE group"); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_KE_UNKNOWN_GROUP); if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER) - silc_say_error("Server does not support one of your proposed cipher"); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_KE_UNKNOWN_CIPHER); if (status == SILC_SKE_STATUS_UNKNOWN_PKCS) - silc_say_error("Server does not support one of your proposed PKCS"); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_KE_UNKNOWN_PKCS); if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION) - silc_say_error("Server does not support one of your proposed " - "hash function"); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_KE_UNKNOWN_HASH_FUNCTION); if (status == SILC_SKE_STATUS_UNKNOWN_HMAC) - silc_say_error("Server does not support one of your proposed HMAC"); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_KE_UNKNOWN_HMAC); if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE) - silc_say_error("Incorrect signature"); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_KE_INCORRECT_SIGNATURE); + if (status == SILC_SKE_STATUS_INVALID_COOKIE) + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_KE_INVALID_COOKIE); } if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) { uint32 err = (uint32)failure; if (err == SILC_AUTH_FAILED) - silc_say(client, conn, "Authentication failed"); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_AUTH_FAILED); } } @@ -1046,7 +1106,7 @@ int silc_key_agreement(SilcClient client, SilcClientConnection conn, SilcKeyAgreementCallback *completion, void **context) { - char portstr[6]; + char portstr[12]; /* We will just display the info on the screen and return FALSE and user will have to start the key agreement with a command. */