+ silc_buffer_free(pk);
+ silc_server_command_free(cmd);
+}
+
+/* Server side of command SERVICE. */
+/* XXX currently this just sends empty reply back */
+
+SILC_SERVER_CMD_FUNC(service)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcUInt32 tmp_len, auth_len;
+ unsigned char *service_name, *auth;
+ SilcBool send_list = FALSE;
+ SilcUInt16 ident = silc_command_get_ident(cmd->payload);
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SERVICE, cmd, 0, 256);
+
+ /* Get requested service */
+ service_name = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (service_name && tmp_len) {
+ /* Verify service name */
+ if (!silc_identifier_verify(service_name, tmp_len,
+ SILC_STRING_UTF8, 256)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SERVICE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+ 0);
+ goto out;
+ }
+ }
+
+ /* Get authentication payload if present */
+ auth = silc_argument_get_arg_type(cmd->args, 2, &auth_len);
+ if (auth) {
+ /* XXX */
+ }
+
+
+ send_list = TRUE;
+
+ /* Send our service list back */
+ silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_SERVICE,
+ SILC_STATUS_OK, 0, ident, 0);
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+
+/* Private range commands, specific to this implementation */
+
+/* Server side command of CONNECT. Connects us to the specified remote
+ server or router. */
+
+SILC_SERVER_CMD_FUNC(connect)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = silc_packet_get_context(cmd->sock);
+ unsigned char *tmp, *host;
+ SilcUInt32 tmp_len;
+ SilcUInt32 port = SILC_PORT;
+
+ if (client->data.conn_type != SILC_CONN_CLIENT || !client)
+ goto out;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_CONNECT, cmd, 1, 2);
+
+ /* Check whether client has the permissions. */
+ if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
+ !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
+ SILC_STATUS_ERR_NO_SERVER_PRIV, 0);
+ goto out;
+ }
+
+ if (server->server_type == SILC_ROUTER && !server->backup_router &&
+ client->mode & SILC_UMODE_SERVER_OPERATOR) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
+ SILC_STATUS_ERR_NO_ROUTER_PRIV, 0);
+ goto out;
+ }
+
+ /* Get the remote server */
+ host = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!host) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+ 0);
+ goto out;
+ }
+
+ /* Get port */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (tmp)
+ SILC_GET32_MSB(port, tmp);
+
+ /* Create the connection. It is done with timeout and is async. */
+ silc_server_create_connection(server, FALSE, FALSE, host, port, NULL, NULL);
+
+ /* Send reply to the sender */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
+ SILC_STATUS_OK, 0);
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+/* Server side command of CLOSE. Closes connection to a specified server. */
+
+SILC_SERVER_CMD_FUNC(close)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = silc_packet_get_context(cmd->sock);
+ SilcServerEntry server_entry;
+ SilcPacketStream sock;
+ unsigned char *tmp;
+ SilcUInt32 tmp_len;
+ unsigned char *name;
+ SilcUInt32 port = SILC_PORT;
+
+ if (client->data.conn_type != SILC_CONN_CLIENT || !client)
+ goto out;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_CLOSE, cmd, 1, 2);
+
+ /* Check whether client has the permissions. */
+ if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
+ !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
+ SILC_STATUS_ERR_NO_SERVER_PRIV,
+ 0);
+ goto out;
+ }
+
+ /* Get the remote server */
+ name = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!name) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+ 0);
+ goto out;
+ }
+
+ /* Get port */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (tmp)
+ SILC_GET32_MSB(port, tmp);
+
+ server_entry = silc_idlist_find_server_by_conn(server->local_list,
+ name, port, TRUE, NULL);
+ if (!server_entry)
+ server_entry = silc_idlist_find_server_by_conn(server->global_list,
+ name, port, TRUE, NULL);
+ if (!server_entry) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
+ SILC_STATUS_ERR_NO_SERVER_ID, 0);
+ goto out;
+ }
+
+ if (server_entry == server->id_entry) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
+ SILC_STATUS_ERR_NO_SERVER_ID, 0);
+ goto out;
+ }
+
+ /* Send reply to the sender */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
+ SILC_STATUS_OK, 0);
+
+ /* Close the connection to the server */
+ sock = server_entry->connection;
+
+ if (server_entry->server_type == SILC_BACKUP_ROUTER) {
+ server->backup_closed = TRUE;
+ silc_server_backup_del(server, server_entry);
+ }
+
+ server->backup_noswitch = TRUE;
+ if (server->router == server_entry) {
+ server->id_entry->router = NULL;
+ server->router = NULL;
+ server->standalone = TRUE;
+ }
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_BANNED_FROM_SERVER,
+ "Closed by administrator");
+ silc_server_free_sock_user_data(server, sock, NULL);
+ server->backup_noswitch = FALSE;
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+/* Server side command of SHUTDOWN. Shutdowns the server and closes all
+ active connections. */
+
+SILC_SERVER_CMD_FUNC(shutdown)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = silc_packet_get_context(cmd->sock);
+
+ if (client->data.conn_type != SILC_CONN_CLIENT || !client)
+ goto out;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_SHUTDOWN, cmd, 0, 0);
+
+ /* Check whether client has the permission. */
+ if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
+ !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_SHUTDOWN,
+ SILC_STATUS_ERR_NO_SERVER_PRIV,
+ 0);
+ goto out;
+ }
+
+ /* Send reply to the sender */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_SHUTDOWN,
+ SILC_STATUS_OK, 0);
+
+ /* Then, gracefully, or not, bring the server down. */
+ silc_server_stop(server);
+ exit(0);
+
+ out: