-Sun Apr 8 15:30:56 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+Sun Apr 8 19:30:56 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
* Made the key generation options to the silcd program. Added
-C option, equivalent to client's option.
* Added new [ServerKeys] config section to the server. It
configures the server's public and private key.
+ * Defined generic Public Key Payload into the protocol
+ specification to send specific type of public keys and
+ certificates.
+
+ * Defined new command SILC_COMMAND_GETKEY to fetch a client's
+ public key or certificate.
+
+ * Implemented the GETKEY command to the server and to the
+ client library and on user interface.
+
Sun Apr 8 01:37:21 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
* Made preliminary `make install' work.
This command is used to send for example informational
notice messages to the channel.
+ /GETKEY <nickname>
+
+ Fetches remote client's public key.
+
Features
========
more (silcpkcs.h).
-TODO in the protocol before SILC 0.x
-====================================
-
- o New commands and features in the commands
- (draft-riikonen-silc-spec-xx.txt):
-
- o Define GETKEY command to fetch the public key of a server
- and/or a client in the SILC Network.
- o Define SENDKEY command to send your public key to a client
- in the network. Sending to the server must not be done due
- to various security reasons (the server must not trust the
- public keys blindly without third party verification; that's
- why SENDKEY is not for servers).
-
-
TODO After 1.0
==============
}
break;
+ case SILC_COMMAND_GETKEY:
+ {
+ SilcIdType id_type;
+ void *entry;
+ SilcPublicKey public_key;
+ unsigned char *pk;
+ uint32 pk_len;
+
+ id_type = va_arg(vp, SilcIdType);
+ 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(client, conn, SILC_SOCKET_TYPE_CLIENT,
+ pk, pk_len, SILC_SKE_PK_TYPE_SILC);
+ }
+
+ silc_free(pk);
+ }
+
default:
break;
}
void silc_disconnect(SilcClient client, SilcClientConnection conn);
unsigned char *silc_ask_passphrase(SilcClient client,
SilcClientConnection conn);
-int silc_verify_server_key(SilcClient client, SilcClientConnection conn,
+int silc_verify_public_key(SilcClient client,
+ SilcClientConnection conn,
+ SilcSocketType conn_type,
unsigned char *pk, uint32 pk_len,
SilcSKEPKType pk_type);
int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
private messages are not really commands, they are message packets,
however, on user interface it is convenient to show them as commands
as that is the common way of sending private messages (like in IRC). */
-/* XXX supports only one destination */
SILC_CLIENT_LCMD_FUNC(msg)
{
SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG_STRICT | SILC_CF_REG),
SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(getkey, GETKEY, SILC_CF_LAG | SILC_CF_REG),
{ NULL, 0 },
};
out:
silc_server_command_free(cmd);
}
+
+/* Server side of command GETKEY. This fetches the client's public key
+ from the server where to the client is connected. */
+
+SILC_SERVER_CMD_FUNC(getkey)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcBuffer packet;
+ SilcClientEntry client;
+ SilcServerEntry server_entry;
+ SilcClientID *client_id = NULL;
+ SilcServerID *server_id = NULL;
+ SilcIDPayload idp = NULL;
+ uint16 ident = silc_command_get_ident(cmd->payload);
+ unsigned char *tmp;
+ uint32 tmp_len;
+ SilcBuffer pk;
+ SilcIdType id_type;
+
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ idp = silc_id_payload_parse_data(tmp, tmp_len);
+ if (!idp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ id_type = silc_id_payload_get_type(idp);
+ if (id_type == SILC_ID_CLIENT) {
+ client_id = silc_id_payload_get_id(idp);
+
+ /* If the client is not found from local list there is no chance it
+ would be locally connected client so send the command further. */
+ client = silc_idlist_find_client_by_id(server->local_list,
+ client_id, NULL);
+
+ if ((!client && !cmd->pending && !server->standalone) ||
+ (client && !client->connection)) {
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
+ SilcSocketConnection dest_sock;
+
+ dest_sock = silc_server_get_client_route(server, NULL, 0,
+ client_id, NULL);
+ if (!dest_sock)
+ goto out;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ silc_server_packet_send(server, dest_sock,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_GETKEY,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_destructor,
+ silc_server_command_getkey,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+ return;
+ }
+
+ if (!client && cmd->pending) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+ goto out;
+ }
+
+ /* The client is locally connected, just get the public key and
+ send it back. */
+ tmp = silc_pkcs_public_key_encode(client->data.public_key, &tmp_len);
+ pk = silc_buffer_alloc(4 + tmp_len);
+ silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
+ silc_buffer_format(pk,
+ SILC_STR_UI_SHORT(tmp_len),
+ SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
+ SILC_STR_UI_XNSTRING(tmp, tmp_len),
+ SILC_STR_END);
+ silc_free(tmp);
+
+ } else if (id_type == SILC_ID_SERVER) {
+ server_id = silc_id_payload_get_id(idp);
+
+ /* If the server is not found from local list there is no chance it
+ would be locally connected server so send the command further. */
+ server_entry = silc_idlist_find_server_by_id(server->local_list,
+ server_id, NULL);
+
+ if ((!server_entry && !cmd->pending && !server->standalone) ||
+ (server_entry && !server_entry->connection)) {
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ silc_server_packet_send(server, server->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_GETKEY,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_destructor,
+ silc_server_command_getkey,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+ return;
+ }
+
+ if (!server_entry && cmd->pending) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
+ SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
+ goto out;
+ }
+
+ /* The client is locally connected, just get the public key and
+ send it back. */
+ tmp = silc_pkcs_public_key_encode(server_entry->data.public_key, &tmp_len);
+ pk = silc_buffer_alloc(4 + tmp_len);
+ silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
+ silc_buffer_format(pk,
+ SILC_STR_UI_SHORT(tmp_len),
+ SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
+ SILC_STR_UI_XNSTRING(tmp, tmp_len),
+ SILC_STR_END);
+ silc_free(tmp);
+ } else {
+ goto out;
+ }
+
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_GETKEY,
+ SILC_STATUS_OK, ident, 2,
+ 2, tmp, tmp_len,
+ 3, pk->data, pk->len);
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+ silc_buffer_free(pk);
+
+ out:
+ if (idp)
+ silc_id_payload_free(idp);
+ silc_free(client_id);
+ silc_free(server_id);
+ silc_server_command_free(cmd);
+}
SILC_SERVER_CMD_FUNC(silcoper);
SILC_SERVER_CMD_FUNC(leave);
SILC_SERVER_CMD_FUNC(users);
+SILC_SERVER_CMD_FUNC(getkey);
#endif
SILC_SERVER_CMD_REPLY(motd, MOTD),
SILC_SERVER_CMD_REPLY(join, JOIN),
SILC_SERVER_CMD_REPLY(users, USERS),
+ SILC_SERVER_CMD_REPLY(getkey, GETKEY),
{ NULL, 0 },
};
out:
SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
- if (channel_id)
- silc_free(channel_id);
+ silc_free(channel_id);
+ silc_server_command_reply_free(cmd);
+}
+
+SILC_SERVER_CMD_REPLY_FUNC(getkey)
+{
+ SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
+ SilcServer server = cmd->server;
+ SilcCommandStatus status;
+ SilcClientEntry client = NULL;
+ SilcServerEntry server_entry = NULL;
+ SilcClientID *client_id = NULL;
+ SilcServerID *server_id = NULL;
+ SilcSKEPKType type;
+ unsigned char *tmp, *pk;
+ uint32 len;
+ uint16 pk_len;
+ SilcIDPayload idp = NULL;
+ SilcIdType id_type;
+ SilcPublicKey public_key = NULL;
+
+ COMMAND_CHECK_STATUS;
+
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!tmp)
+ goto out;
+ idp = silc_id_payload_parse_data(tmp, len);
+ if (!idp)
+ goto out;
+
+ /* Get the public key payload */
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+ if (!tmp)
+ goto out;
+
+ /* Decode the public key */
+
+ SILC_GET16_MSB(pk_len, tmp);
+ SILC_GET16_MSB(type, tmp + 2);
+ pk = tmp + 4;
+
+ if (type != SILC_SKE_PK_TYPE_SILC)
+ goto out;
+
+ if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
+ goto out;
+
+ id_type = silc_id_payload_get_type(idp);
+ if (id_type == SILC_ID_CLIENT) {
+ client_id = silc_id_payload_get_id(idp);
+
+ client = silc_idlist_find_client_by_id(server->local_list, client_id,
+ NULL);
+ if (!client) {
+ client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, NULL);
+ if (!client)
+ goto out;
+ }
+
+ client->data.public_key = public_key;
+ } else if (id_type == SILC_ID_SERVER) {
+ server_id = silc_id_payload_get_id(idp);
+
+ server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
+ NULL);
+ if (!server_entry) {
+ server_entry = silc_idlist_find_server_by_id(server->global_list,
+ server_id, NULL);
+ if (!server_entry)
+ goto out;
+ }
+
+ server_entry->data.public_key = public_key;
+ } else {
+ goto out;
+ }
+
+ out:
+ SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
+ SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
+ if (idp)
+ silc_id_payload_free(idp);
+ silc_free(client_id);
+ silc_free(server_id);
+ if (public_key)
+ silc_pkcs_public_key_free(public_key);
silc_server_command_reply_free(cmd);
}
SILC_SERVER_CMD_REPLY_FUNC(motd);
SILC_SERVER_CMD_REPLY_FUNC(join);
SILC_SERVER_CMD_REPLY_FUNC(users);
+SILC_SERVER_CMD_REPLY_FUNC(getkey);
#endif
}
}
-/* Lookups route to the client indicated by `id' client ID. The connection
+/* Lookups route to the client indicated by the `id_data'. The connection
object and internal data object is returned. Returns NULL if route
could not be found to the client. If the `client_id' is specified then
it is used and the `id_data' is ignored. */
/* We are of course in this case the client's router thus the real
"router" of the client is the server who owns the client. Thus
we will send the packet to that server. */
- *idata = (SilcIDListData)client->router;
+ if (idata)
+ *idata = (SilcIDListData)client->router;
return client->router->connection;
}
/* Seems that client really is directly connected to us */
- *idata = (SilcIDListData)client;
+ if (idata)
+ *idata = (SilcIDListData)client;
return client->connection;
}
server our action is to send the packet to our router. */
if (server->server_type == SILC_SERVER && !server->standalone) {
silc_free(id);
- *idata = (SilcIDListData)server->router;
+ if (idata)
+ *idata = (SilcIDListData)server->router;
return server->router->connection;
}
dst_sock = silc_server_route_get(server, id, SILC_ID_CLIENT);
silc_free(id);
- *idata = (SilcIDListData)dst_sock->user_data;
+ if (idata)
+ *idata = (SilcIDListData)dst_sock->user_data;
return dst_sock;
}
}
sending SILC_PACKET_FAILURE message and the connection should
be closed immediately.
+o Public Key (or certicicate) (variable length) - The
+ public key or certificate.
+
o Public Data Length (2 bytes) - The length of the Public Data
field, not including any other field.
2.3.2.1 ID Payload .................................. 16
2.3.2.2 Argument Payload ............................ 16
2.3.2.3 Channel Payload ............................. XXX
+ 2.3.2.4 Public Key Payload .......................... XXX
2.3.3 Disconnect Payload .................................. 17
2.3.4 Success Payload ..................................... 18
2.3.5 Failure Payload ..................................... 18
Figure 3: ID Payload
Figure 4: Argument Payload
Figure 5: Channel Payload
-Figure 6: Disconnect Payload
-Figure 7: Success Payload
-Figure 8: Failure Payload
-Figure 9: Reject Payload
-Figure 10: Notify Payload
-Figure 11: Error Payload
-Figure 12: Channel Message Payload
-Figure 13: Channel Key Payload
-Figure 14: Private Message Payload
-Figure 15: Private Message Key Payload
-Figure 16: Command Payload
-Figure 17: Connection Auth Request Payload
-Figure 18: New Client Payload
-Figure 19: New Server Payload
-Figure 20: Key Agreement Payload
-Figure 21: Cell Routers Payload
+Figure 6: Public Key Payload
+Figure 7: Disconnect Payload
+Figure 8: Success Payload
+Figure 9: Failure Payload
+Figure 10: Reject Payload
+Figure 11: Notify Payload
+Figure 12: Error Payload
+Figure 13: Channel Message Payload
+Figure 14: Channel Key Payload
+Figure 15: Private Message Payload
+Figure 16: Private Message Key Payload
+Figure 17: Command Payload
+Figure 18: Connection Auth Request Payload
+Figure 19: New Client Payload
+Figure 20: New Server Payload
+Figure 21: Key Agreement Payload
+Figure 22: Cell Routers Payload
.ti 0
.in 3
+.ti 0
+2.3.2.4 Public Key Payload
+
+Generic Public Key Payload may be used to send different types of
+public keys and certificates.
+
+The following diagram represents the Channel Payload Payload.
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Public Key Length | Public Key Type |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ Public Key of the party (or certificate) ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 6: Public Key Payload
+
+
+.in 6
+o Public Key Length (2 bytes) - The length of the Public Key
+ (or certificate) field, not including any other field.
+
+o Public Key Type (2 bytes) - The public key (or certificate)
+ type. This field indicates the type of the public key in
+ the packet. See the [SILC3] for defined public key types.
+
+o Public Key (or certicicate) (variable length) - The
+ public key or certificate.
+.in 3
+
+
.ti 0
2.3.3 Disconnect Payload
.in 3
.ce
-Figure 6: Disconnect Payload
+Figure 7: Disconnect Payload
.in 3
.ce
-Figure 7: Success Payload
+Figure 8: Success Payload
.in 6
.in 3
.ce
-Figure 8: Failure Payload
+Figure 9: Failure Payload
.in 6
.in 3
.ce
-Figure 9: Reject Payload
+Figure 10: Reject Payload
.in 6
.in 3
.ce
-Figure 10: Notify Payload
+Figure 11: Notify Payload
.in 6
.in 3
.ce
-Figure 11: Error Payload
+Figure 12: Error Payload
.in 6
.in 3
.ce
-Figure 12: Channel Message Payload
+Figure 13: Channel Message Payload
.in 6
.in 3
.ce
-Figure 13: Channel Key Payload
+Figure 14: Channel Key Payload
.in 3
.ce
-Figure 14: Private Message Payload
+Figure 15: Private Message Payload
.in 6
.in 3
.ce
-Figure 15: Private Message Key Payload
+Figure 16: Private Message Key Payload
.in 3
.ce
-Figure 16: Command Payload
+Figure 17: Command Payload
.in 6
.in 3
.ce
-Figure 17: Connection Auth Request Payload
+Figure 18: Connection Auth Request Payload
.in 6
.in 3
.ce
-Figure 18: New Client Payload
+Figure 19: New Client Payload
.in 6
.in 3
.ce
-Figure 19: New Server Payload
+Figure 20: New Server Payload
.in 6
.in 3
.ce
-Figure 20: Key Agreement Payload
+Figure 21: Key Agreement Payload
.in 6
.in 3
.ce
-Figure 21: Cell Routers Payload
+Figure 22: Cell Routers Payload
.in 6
SILC_STATUS_ERR_NOT_ON_CHANNEL
+ 26 SILC_COMMAND_GETKEY
+
+ Max Arguments: 1
+ Arguments: (1) <ID Payload>
+
+ This command is used to fetch the public key of the client or
+ server indicated by the <ID Payload>. The public key is fetched
+ from the server where to the client is connected.
+
+ Reply messages to the command:
+
+ Max Arguments: 3
+ Arguments: (1) <Status Payload> (2) <ID Payload>
+ (3) <Public Key Payload>
+
+ This command replies with the client's or server's ID and with
+ the <Public Key Payload>.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+ SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+
+
27 - 199
Currently undefined commands.
"The algorithm was not supported." The server does not support the
requested algorithm.
+
+ 47 SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+
+ "No such Server ID". Server ID provided does not exist.
+
.in 3
SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 3),
SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
SILC_CLIENT_CMD(users, USERS, "USERS", SILC_CF_LAG | SILC_CF_REG, 2),
+ SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", SILC_CF_LAG | SILC_CF_REG, 2),
{ NULL, 0, NULL, 0, 0 },
};
out:
silc_client_command_free(cmd);
}
+
+/* Command GETKEY. Used to fetch remote client's public key. */
+
+SILC_CLIENT_CMD_FUNC(getkey)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClientConnection conn = cmd->conn;
+ SilcClient client = cmd->client;
+ SilcClientEntry client_entry = NULL;
+ uint32 num = 0;
+ char *nickname = NULL, *server = NULL;
+ SilcBuffer idp, buffer;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ if (cmd->argc < 2) {
+ client->ops->say(client, conn, "Usage: /GETKEY <nickname>");
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ /* Parse the typed nickname. */
+ if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
+ client->ops->say(client, conn, "Bad nickname");
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ /* Find client entry */
+ client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
+ TRUE);
+ if (!client_entry) {
+ /* Client entry not found, it was requested thus mark this to be
+ pending command. */
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident,
+ silc_client_command_destructor,
+ silc_client_command_getkey,
+ silc_client_command_dup(cmd));
+ cmd->pending = 1;
+ return;
+ }
+
+ idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
+ 1, idp->data, idp->len);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+ silc_buffer_free(idp);
+
+ /* Notify application */
+ COMMAND;
+
+ out:
+ silc_client_command_free(cmd);
+}
SILC_CLIENT_CMD_FUNC(silcoper);
SILC_CLIENT_CMD_FUNC(leave);
SILC_CLIENT_CMD_FUNC(users);
+SILC_CLIENT_CMD_FUNC(getkey);
#endif
SILC_CLIENT_CMD_REPLY(cmode, CMODE),
SILC_CLIENT_CMD_REPLY(cumode, CUMODE),
SILC_CLIENT_CMD_REPLY(kick, KICK),
+ SILC_CLIENT_CMD_REPLY(ban, BAN),
SILC_CLIENT_CMD_REPLY(close, CLOSE),
SILC_CLIENT_CMD_REPLY(shutdown, SHUTDOWN),
SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
SILC_CLIENT_CMD_REPLY(leave, LEAVE),
SILC_CLIENT_CMD_REPLY(users, USERS),
- SILC_CLIENT_CMD_REPLY(ban, BAN),
+ SILC_CLIENT_CMD_REPLY(getkey, GETKEY),
{ NULL, 0 },
};
{ STAT(BAD_CHANNEL), "Bad channel name" },
{ STAT(AUTH_FAILED), "Authentication failed" },
{ STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
+ { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
{ 0, NULL }
};
silc_client_command_reply_free(cmd);
}
+SILC_CLIENT_CMD_REPLY_FUNC(ban)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcCommandStatus status;
+ SilcIDCacheEntry id_cache = NULL;
+ SilcChannelEntry channel;
+ SilcChannelID *channel_id;
+ unsigned char *tmp;
+ uint32 len;
+
+ tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ SILC_GET16_MSB(status, tmp);
+ if (status != SILC_STATUS_OK) {
+ cmd->client->ops->say(cmd->client, conn,
+ "%s", silc_client_command_status_message(status));
+ COMMAND_REPLY_ERROR;
+ goto out;
+ }
+
+ /* Take Channel ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!tmp)
+ goto out;
+
+ channel_id = silc_id_payload_parse_id(tmp, len);
+ if (!channel_id)
+ goto out;
+
+ /* Get the channel entry */
+ if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+ SILC_ID_CHANNEL, &id_cache)) {
+ silc_free(channel_id);
+ COMMAND_REPLY_ERROR;
+ goto out;
+ }
+
+ channel = (SilcChannelEntry)id_cache->context;
+
+ /* Get the ban list */
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+
+ /* Notify application */
+ COMMAND_REPLY((ARGS, channel, tmp));
+
+ /* Execute any pending command callbacks */
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
+
+ out:
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
+ silc_client_command_reply_free(cmd);
+}
+
SILC_CLIENT_CMD_REPLY_FUNC(close)
{
SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
silc_client_command_reply_free(cmd);
}
-SILC_CLIENT_CMD_REPLY_FUNC(ban)
+/* Received command reply to GETKEY command. WE've received the remote
+ client's public key. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(getkey)
{
SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
SilcCommandStatus status;
- SilcIDCacheEntry id_cache = NULL;
- SilcChannelEntry channel;
- SilcChannelID *channel_id;
- unsigned char *tmp;
+ SilcIDCacheEntry id_cache;
+ SilcIDPayload idp = NULL;
+ SilcClientID *client_id = NULL;
+ SilcClientEntry client_entry;
+ SilcSKEPKType type;
+ unsigned char *tmp, *pk;
uint32 len;
+ uint16 pk_len;
+ SilcIdType id_type;
+ SilcPublicKey public_key = NULL;
+
+ SILC_LOG_DEBUG(("Start"));
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
SILC_GET16_MSB(status, tmp);
goto out;
}
- /* Take Channel ID */
tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
if (!tmp)
goto out;
+ idp = silc_id_payload_parse_data(tmp, len);
+ if (!idp)
+ goto out;
- channel_id = silc_id_payload_parse_id(tmp, len);
- if (!channel_id)
+ /* Get the public key payload */
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+ if (!tmp)
goto out;
- /* Get the channel entry */
- if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
- SILC_ID_CHANNEL, &id_cache)) {
- silc_free(channel_id);
- COMMAND_REPLY_ERROR;
+ /* Decode the public key */
+
+ SILC_GET16_MSB(pk_len, tmp);
+ SILC_GET16_MSB(type, tmp + 2);
+ pk = tmp + 4;
+
+ if (type != SILC_SKE_PK_TYPE_SILC)
goto out;
- }
-
- channel = (SilcChannelEntry)id_cache->context;
- /* Get the ban list */
- tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+ if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
+ goto out;
- /* Notify application */
- COMMAND_REPLY((ARGS, channel, tmp));
+ id_type = silc_id_payload_get_type(idp);
+ if (id_type == SILC_ID_CLIENT) {
+ client_id = silc_id_payload_get_id(idp);
- /* Execute any pending command callbacks */
- SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
+ if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
+ SILC_ID_CLIENT, &id_cache))
+ goto out;
+
+ client_entry = (SilcClientEntry)id_cache->context;
+
+ /* Notify application */
+ COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
+ } else if (id_type == SILC_ID_SERVER) {
+ /* XXX we don't have server entries at all */
+ goto out;
+ } else {
+ goto out;
+ }
out:
- SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
+ if (idp)
+ silc_id_payload_free(idp);
+ if (public_key)
+ silc_pkcs_public_key_free(public_key);
+ silc_free(client_id);
silc_client_command_reply_free(cmd);
}
SILC_CLIENT_CMD_REPLY_FUNC(cmode);
SILC_CLIENT_CMD_REPLY_FUNC(cumode);
SILC_CLIENT_CMD_REPLY_FUNC(kick);
+SILC_CLIENT_CMD_REPLY_FUNC(ban);
SILC_CLIENT_CMD_REPLY_FUNC(close);
SILC_CLIENT_CMD_REPLY_FUNC(shutdown);
SILC_CLIENT_CMD_REPLY_FUNC(silcoper);
SILC_CLIENT_CMD_REPLY_FUNC(leave);
SILC_CLIENT_CMD_REPLY_FUNC(users);
-SILC_CLIENT_CMD_REPLY_FUNC(ban);
+SILC_CLIENT_CMD_REPLY_FUNC(getkey);
#endif
#define SILC_COMMAND_SILCOPER 23
#define SILC_COMMAND_LEAVE 24
#define SILC_COMMAND_USERS 25
+#define SILC_COMMAND_GETKEY 26
/* Reserved */
#define SILC_COMMAND_RESERVED 255
#define SILC_STATUS_ERR_BAD_CHANNEL 44
#define SILC_STATUS_ERR_AUTH_FAILED 45
#define SILC_STATUS_ERR_UNKNOWN_ALGORITHM 46
+#define SILC_STATUS_ERR_NO_SUCH_SERVER_ID 47
/* Prototypes */
SilcCommandPayload silc_command_payload_parse(SilcBuffer buffer);