From 83c73dffa89141bc59e62436abb63b3d3efca6bb Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Mon, 22 Oct 2001 21:30:12 +0000 Subject: [PATCH] udpates. --- CHANGES | 34 ++ .../irssi/src/fe-common/silc/module-formats.c | 16 + .../irssi/src/fe-common/silc/module-formats.h | 14 + apps/irssi/src/silc/core/client_ops.c | 28 +- apps/irssi/src/silc/core/silc-channels.c | 34 +- apps/irssi/src/silc/core/silc-servers.c | 332 ++++++++++++++++-- apps/irssi/src/silc/core/silc-servers.h | 13 + apps/silcd/server.c | 31 +- apps/silcd/server.h | 2 +- includes/clientlibincludes.h | 1 - lib/silcclient/client.c | 50 ++- lib/silcclient/client_ftp.c | 168 ++++++++- lib/silcclient/client_ftp.h | 23 -- lib/silcclient/client_internal.h | 5 + lib/silcclient/client_notify.c | 4 +- lib/silcclient/idlist.c | 5 +- lib/silcclient/idlist.h | 1 + lib/silcclient/protocol.c | 36 +- lib/silcclient/protocol.h | 3 +- lib/silccore/silcpacket.c | 15 +- lib/silccore/silcpacket.h | 12 +- lib/silcsftp/sftp_server.c | 165 ++++++++- lib/silcsftp/silcsftp.h | 105 ++++++ lib/silcutil/silcnet.c | 22 ++ lib/silcutil/silcnet.h | 13 + lib/silcutil/silcschedule.c | 4 +- lib/silcutil/silcutil.c | 16 +- lib/silcutil/silcutil.h | 1 + 28 files changed, 1020 insertions(+), 133 deletions(-) delete mode 100644 lib/silcclient/client_ftp.h diff --git a/CHANGES b/CHANGES index 3072f8c5..7bc474dd 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,37 @@ +Mon Oct 22 16:35:05 EDT 2001 Pekka Riikonen + + * Added silc_net_localip to return local host's IP address. + Affected file lib/silcutil/silcnet.[ch]. + + * If key exchange or rekey protocol is active for a connection + parse all packets syncronously since there might be packets + in packet queue that we are not able to process without first + processing packets before them. Affected file silcd/server, + lib/silcclient/client.c. + + * SilcPacketParserCallback now returns TRUE or FALSE to indicate + whether library should continue processing the packet. + Affected file lib/silccore/silcpacket.h. + + * Added SilcSFTPMonitor callback, SilcSFTPMonitors and + SilcSFTPMonitorData to SFTP server to monitor various + SFTP client requests. Affected file lib/silcsftp/silcsftp.h, + lib/silcsftp/sftp_server.c. + + * Added silc_file_size to return file size. Affected file + lib/silcutil/silcutil.[ch]. + + * Implemented the file transfer support for the client library. + Added preliminary support for simple client to client one-file + transmission. Affected file lib/silcclient/client_ftp.c, + lib/silccilent/client.[ch]. + + * Added new local command FILE to the Irssi SILC Client. + It is used to perform the file transfer. It has subcommands + SEND, RECEIVE, SHOW and CLOSE. Affected files + irssi/src/silc/core/client_ops.c, + irssi/src/silc/core/silc-server.[ch]. + Mon Oct 22 12:50:08 EDT 2001 Pekka Riikonen * Relay the SILC_PACKET_FTP in the server. Affected files diff --git a/apps/irssi/src/fe-common/silc/module-formats.c b/apps/irssi/src/fe-common/silc/module-formats.c index aef9af93..19ae4cb3 100644 --- a/apps/irssi/src/fe-common/silc/module-formats.c +++ b/apps/irssi/src/fe-common/silc/module-formats.c @@ -116,5 +116,21 @@ FORMAT_REC fecommon_silc_formats[] = { { "unset_away", "You are no longer marked as being away", 0 }, { "auth_meth_unresolved", "Could not resolve authentication method to use, assume no authentication", 0 }, + /* File transfer messages */ + { NULL, "FileTransfer", 0 }, + + { "file_send", "File transfer request sent to {nick $0} for $1", 2, { 0, 0 } }, + { "file_transmit", "Transmitting file {hilight $0} [$1kB] to {nick $2}", 3, { 0, 0, 0 } }, + { "file_transmitted", "Transmitted file {hilight $0} [$1kB] to {nick $2} [{hilight $3kB/s}]", 4, { 0, 0, 0, 0 } }, + { "file_receive", "Receiving file {hilight $0} [$1kB] from {nick $2}", 3, { 0, 0 } }, + { "file_received", "Received file {hilight $0} [$1kB] from {nick $2} [{hilight $3kB/s}]", 4, { 0, 0 } }, + { "file_request", "File transfer request from {nick $0}", 1, { 0 } }, + { "file_request_host", "File transfer request from {nick $0} [$1 port $2]", 3, { 0, 0, 0 } }, + { "file_key_exchange", "Negotiating keys for file transfer with {nick $0}", 1, { 0 } }, + { "file_na", "No file transfers available", 0 }, + { "file_client_na", "No file transfer offered by {nick $0}", 1, { 0 } }, + { "file_show_header", "File transfers", 0 }, + { "file_show_line", " $0 $1 ($2)", 3, { 0, 0, 0 } }, + { NULL, NULL, 0 } }; diff --git a/apps/irssi/src/fe-common/silc/module-formats.h b/apps/irssi/src/fe-common/silc/module-formats.h index 9ec9b8ef..89726a55 100644 --- a/apps/irssi/src/fe-common/silc/module-formats.h +++ b/apps/irssi/src/fe-common/silc/module-formats.h @@ -110,6 +110,20 @@ enum { SILCTXT_UNSET_AWAY, SILCTXT_AUTH_METH_UNRESOLVED, + SILCTXT_FILL_5, + + SILCTXT_FILE_SEND, + SILCTXT_FILE_TRANSMIT, + SILCTXT_FILE_TRANSMITTED, + SILCTXT_FILE_RECEIVE, + SILCTXT_FILE_RECEIVED, + SILCTXT_FILE_REQUEST, + SILCTXT_FILE_REQUEST_HOST, + SILCTXT_FILE_KEY_EXCHANGE, + SILCTXT_FILE_NA, + SILCTXT_FILE_CLIENT_NA, + SILCTXT_FILE_SHOW_HEADER, + SILCTXT_FILE_SHOW_LINE, }; extern FORMAT_REC fecommon_silc_formats[]; diff --git a/apps/irssi/src/silc/core/client_ops.c b/apps/irssi/src/silc/core/client_ops.c index 03c60cf6..9923412e 100644 --- a/apps/irssi/src/silc/core/client_ops.c +++ b/apps/irssi/src/silc/core/client_ops.c @@ -1204,10 +1204,10 @@ int silc_key_agreement(SilcClient client, SilcClientConnection conn, snprintf(portstr, sizeof(portstr) - 1, "%d", port); if (!hostname) - printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES, + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname); else - printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES, + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, SILCTXT_KEY_AGREEMENT_REQUEST_HOST, client_entry->nickname, hostname, portstr); @@ -1221,13 +1221,31 @@ void silc_ftp(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry, uint32 session_id, const char *hostname, uint16 port) { + SILC_SERVER_REC *server; + char portstr[12]; + FtpSession ftp = silc_calloc(1, sizeof(*ftp)); SILC_LOG_DEBUG(("Start")); - /* XXX */ - silc_client_file_receive(client, conn, NULL, NULL, client_entry, - session_id); + server = conn->context; + + ftp->client_entry = client_entry; + ftp->session_id = session_id; + ftp->send = FALSE; + ftp->conn = conn; + silc_dlist_add(server->ftp_sessions, ftp); + server->current_session = ftp; + if (hostname) + snprintf(portstr, sizeof(portstr) - 1, "%d", port); + + if (!hostname) + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_FILE_REQUEST, client_entry->nickname); + else + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_FILE_REQUEST_HOST, + client_entry->nickname, hostname, portstr); } /* SILC client operations */ diff --git a/apps/irssi/src/silc/core/silc-channels.c b/apps/irssi/src/silc/core/silc-channels.c index a44f88cd..3bdc9cc7 100644 --- a/apps/irssi/src/silc/core/silc-channels.c +++ b/apps/irssi/src/silc/core/silc-channels.c @@ -216,6 +216,8 @@ static void event_signoff(SILC_SERVER_REC *server, va_list va) client = va_arg(va, SilcClientEntry); message = va_arg(va, char *); + silc_server_free_ftp(server, client); + memset(userhost, 0, sizeof(userhost)); if (client->username) snprintf(userhost, sizeof(userhost) - 1, "%s@%s", @@ -249,6 +251,8 @@ static void event_topic(SILC_SERVER_REC *server, va_list va) topic = va_arg(va, char *); channel = va_arg(va, SilcChannelEntry); + silc_server_free_ftp(server, client); + chanrec = silc_channel_find_entry(server, channel); if (chanrec != NULL) { g_free_not_null(chanrec->topic); @@ -761,7 +765,7 @@ static void keyagr_completion(SilcClient client, switch(status) { case SILC_KEY_AGREEMENT_OK: - printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES, + printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP, SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname); if (i->type == 1) { @@ -769,7 +773,7 @@ static void keyagr_completion(SilcClient client, silc_client_del_private_message_key(client, conn, client_entry); silc_client_add_private_message_key_ske(client, conn, client_entry, NULL, key, i->responder); - printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES, + printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP, SILCTXT_KEY_AGREEMENT_PRIVMSG, client_entry->nickname); silc_ske_free_key_material(key); @@ -778,17 +782,17 @@ static void keyagr_completion(SilcClient client, break; case SILC_KEY_AGREEMENT_ERROR: - printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES, + printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP, SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname); break; case SILC_KEY_AGREEMENT_FAILURE: - printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES, + printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP, SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname); break; case SILC_KEY_AGREEMENT_TIMEOUT: - printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES, + printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP, SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname); break; @@ -850,12 +854,8 @@ static void command_key(const char *data, SILC_SERVER_REC *server, silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7); g_free(tmp); - if (argc < 4) { - silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, - "Usage: /KEY msg|channel " - "set|unset|agreement|negotiate []"); - return; - } + if (argc < 4) + cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS); /* Get type */ if (!strcasecmp(argv[1], "msg")) @@ -863,12 +863,8 @@ static void command_key(const char *data, SILC_SERVER_REC *server, if (!strcasecmp(argv[1], "channel")) type = 2; - if (type == 0) { - silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, - "Usage: /KEY msg|channel " - "set|unset|agreement|negotiate []"); - return; - } + if (type == 0) + cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS); if (type == 1) { if (argv[2][0] == '*') { @@ -1185,7 +1181,7 @@ static void command_key(const char *data, SILC_SERVER_REC *server, } if (command == 4 && client_entry) { - printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES, + printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, SILCTXT_KEY_AGREEMENT, argv[2]); internal->responder = TRUE; silc_client_send_key_agreement(silc_client, conn, client_entry, hostname, @@ -1196,7 +1192,7 @@ static void command_key(const char *data, SILC_SERVER_REC *server, } if (command == 5 && client_entry && hostname) { - printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES, + printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]); internal->responder = FALSE; silc_client_perform_key_agreement(silc_client, conn, client_entry, diff --git a/apps/irssi/src/silc/core/silc-servers.c b/apps/irssi/src/silc/core/silc-servers.c index 210740a1..6fccc11b 100644 --- a/apps/irssi/src/silc/core/silc-servers.c +++ b/apps/irssi/src/silc/core/silc-servers.c @@ -243,6 +243,8 @@ SILC_SERVER_REC *silc_server_connect(SILC_SERVER_CONNECT_REC *conn) return NULL; } + server->ftp_sessions = silc_dlist_init(); + return server; } @@ -306,6 +308,10 @@ char *silc_server_get_channels(SILC_SERVER_REC *server) /* SYNTAX: PING */ /* SYNTAX: SCONNECT [] */ /* SYNTAX: USERS */ +/* SYNTAX: FILE SEND */ +/* SYNTAX: FILE RECEIVE [] */ +/* SYNTAX: FILE CLOSE [] */ +/* SYNTAX: FILE SHOW */ void silc_command_exec(SILC_SERVER_REC *server, const char *command, const char *args) @@ -396,7 +402,84 @@ static void event_text(const char *line, SILC_SERVER_REC *server, signal_emit("command msg", 3, str, server, item); g_free(str); - signal_stop(); + signal_stop(); +} + +/* FILE command */ + +SILC_TASK_CALLBACK(silc_client_file_close_later) +{ + FtpSession ftp = (FtpSession)context; + + SILC_LOG_DEBUG(("Start")); + + silc_client_file_close(silc_client, ftp->conn, ftp->session_id); + silc_free(ftp->filepath); + silc_free(ftp); +} + +static void silc_client_file_monitor(SilcClient client, + SilcClientConnection conn, + SilcClientMonitorStatus status, + uint64 offset, + uint64 filesize, + SilcClientEntry client_entry, + uint32 session_id, + const char *filepath, + void *context) +{ + SILC_SERVER_REC *server = (SILC_SERVER_REC *)context; + FtpSession ftp; + char fsize[32]; + + snprintf(fsize, sizeof(fsize) - 1, "%llu", (filesize / 1024)); + + silc_dlist_start(server->ftp_sessions); + while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) { + if (ftp->client_entry == client_entry) { + ftp->session_id = session_id; + + if (!ftp->filepath) + ftp->filepath = strdup(filepath); + break; + } + } + + if (status == SILC_CLIENT_FILE_MONITOR_SEND) { + if (offset == 0) + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_FILE_TRANSMIT, filepath, fsize, + client_entry->nickname); + if (offset == filesize) { + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_FILE_TRANSMITTED, filepath, fsize, + client_entry->nickname, "1024"); + if (ftp != SILC_LIST_END) { + silc_schedule_task_add(silc_client->schedule, 0, + silc_client_file_close_later, ftp, + 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + silc_dlist_del(server->ftp_sessions, ftp); + } + } + } + + if (status == SILC_CLIENT_FILE_MONITOR_RECEIVE) { + if (offset == 0) + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_FILE_RECEIVE, filepath, fsize, + client_entry->nickname); + if (offset == filesize) { + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_FILE_RECEIVED, filepath, fsize, + client_entry->nickname, "1024"); + if (ftp != SILC_LIST_END) { + silc_schedule_task_add(silc_client->schedule, 0, + silc_client_file_close_later, ftp, + 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + silc_dlist_del(server->ftp_sessions, ftp); + } + } + } } typedef struct { @@ -419,11 +502,12 @@ static void command_file(const char *data, SILC_SERVER_REC *server, { SilcClientConnection conn; SilcClientEntry client_entry; - char *nickname, *tmp; + char *nickname = NULL, *tmp; unsigned char **argv; uint32 argc; uint32 *argv_lens, *argv_types; int type; + FtpSession ftp; if (!server || !IS_SILC_SERVER(server) || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED); @@ -435,44 +519,220 @@ static void command_file(const char *data, SILC_SERVER_REC *server, silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 4); g_free(tmp); + if (argc < 2) + cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS); + type = 0; if (!strcasecmp(argv[1], "send")) type = 1; if (!strcasecmp(argv[1], "receive")) type = 2; + if (!strcasecmp(argv[1], "close")) + type = 3; + if (!strcasecmp(argv[1], "show")) + type = 4; - /* Parse the typed nickname. */ - if (!silc_parse_userfqdn(argv[3], &nickname, NULL)) { - printformat_module("fe-common/silc", server, NULL, - MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]); - return; - } - - /* Find client entry */ - client_entry = silc_idlist_get_client(silc_client, conn, nickname, - argv[3], TRUE); - if (!client_entry) { - FileGetClients inter = silc_calloc(1, sizeof(*inter)); - inter->server = server; - inter->data = strdup(data); - inter->item = item; - - /* 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, - NULL, silc_client_command_file_get_clients, - inter); - goto out; - } + if (type == 0) + cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS); switch (type) { case 1: - silc_client_file_send(silc_client, conn, NULL, NULL, client_entry, - argv[2]); + if (argc < 4) + cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS); + + /* Parse the typed nickname. */ + if (!silc_parse_userfqdn(argv[3], &nickname, NULL)) { + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[3]); + goto out; + } + + /* Find client entry */ + client_entry = silc_idlist_get_client(silc_client, conn, nickname, + argv[3], TRUE); + if (!client_entry) { + FileGetClients inter = silc_calloc(1, sizeof(*inter)); + inter->server = server; + inter->data = strdup(data); + inter->item = item; + + /* 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, + NULL, silc_client_command_file_get_clients, + inter); + goto out; + } + + silc_client_file_send(silc_client, conn, silc_client_file_monitor, + server, client_entry, argv[2]); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_FILE_SEND, client_entry->nickname, + argv[2]); + + ftp = silc_calloc(1, sizeof(*ftp)); + ftp->client_entry = client_entry; + ftp->filepath = strdup(argv[2]); + ftp->conn = conn; + ftp->send = TRUE; + silc_dlist_add(server->ftp_sessions, ftp); + server->current_session = ftp; + break; case 2: + /* Parse the typed nickname. */ + if (argc >= 3) { + if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) { + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]); + goto out; + } + + /* Find client entry */ + client_entry = silc_idlist_get_client(silc_client, conn, nickname, + argv[2], TRUE); + if (!client_entry) { + FileGetClients inter = silc_calloc(1, sizeof(*inter)); + inter->server = server; + inter->data = strdup(data); + inter->item = item; + + /* 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, + NULL, + silc_client_command_file_get_clients, + inter); + goto out; + } + } else { + if (!server->current_session) { + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_NA); + goto out; + } + + if (!silc_client_file_receive(silc_client, conn, + silc_client_file_monitor, server, + server->current_session->client_entry, + server->current_session->session_id)) + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_CLIENT_NA, + server->current_session->client_entry->nickname); + + goto out; + } + + silc_dlist_start(server->ftp_sessions); + while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) { + if (ftp->client_entry == client_entry) { + if (!silc_client_file_receive(silc_client, conn, + silc_client_file_monitor, server, + ftp->client_entry, + ftp->session_id)) + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_CLIENT_NA, + server->current_session->client_entry->nickname); + break; + } + } + + if (ftp == SILC_LIST_END) { + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_CLIENT_NA, + client_entry->nickname); + goto out; + } + break; + + case 3: + /* Parse the typed nickname. */ + if (argc >= 3) { + if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) { + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]); + goto out; + } + + /* Find client entry */ + client_entry = silc_idlist_get_client(silc_client, conn, nickname, + argv[2], TRUE); + if (!client_entry) { + FileGetClients inter = silc_calloc(1, sizeof(*inter)); + inter->server = server; + inter->data = strdup(data); + inter->item = item; + + /* 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, + NULL, + silc_client_command_file_get_clients, + inter); + goto out; + } + } else { + if (!server->current_session) { + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_NA); + goto out; + } + + if (!silc_client_file_close(silc_client, conn, + server->current_session->session_id)) + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_CLIENT_NA, + server->current_session->client_entry->nickname); + + goto out; + } + + silc_dlist_start(server->ftp_sessions); + while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) { + if (ftp->client_entry == client_entry) { + if (!silc_client_file_close(silc_client, conn, ftp->session_id)) + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_CLIENT_NA, + server->current_session->client_entry->nickname); + silc_dlist_del(server->ftp_sessions, ftp); + silc_free(ftp->filepath); + silc_free(ftp); + break; + } + } + + if (ftp == SILC_LIST_END) { + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_CLIENT_NA, + client_entry->nickname); + goto out; + } + break; + + case 4: + + if (!silc_dlist_count(server->ftp_sessions)) { + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_NA); + goto out; + } + + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_SHOW_HEADER); + + silc_dlist_start(server->ftp_sessions); + while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) { + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_SHOW_LINE, + ftp->client_entry->nickname, + ftp->filepath ? ftp->filepath : "[unknown]", + ftp->send ? "send" : "receive"); + } + break; default: @@ -548,3 +808,19 @@ void silc_server_deinit(void) command_unbind("sconnect", (SIGNAL_FUNC) command_sconnect); command_unbind("file", (SIGNAL_FUNC) command_file); } + +void silc_server_free_ftp(SILC_SERVER_REC *server, + SilcClientEntry client_entry) +{ + FtpSession ftp; + + silc_dlist_start(server->ftp_sessions); + while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) { + if (ftp->client_entry == client_entry) { + silc_dlist_del(server->ftp_sessions, ftp); + silc_free(ftp->filepath); + silc_free(ftp); + break; + } + } +} diff --git a/apps/irssi/src/silc/core/silc-servers.h b/apps/irssi/src/silc/core/silc-servers.h index eb0edc6d..a790fa39 100644 --- a/apps/irssi/src/silc/core/silc-servers.h +++ b/apps/irssi/src/silc/core/silc-servers.h @@ -21,6 +21,14 @@ typedef struct { #include "server-connect-rec.h" } SILC_SERVER_CONNECT_REC; +typedef struct { + SilcClientEntry client_entry; + SilcClientConnection conn; + uint32 session_id; + char *filepath; + bool send; +} *FtpSession; + #define STRUCT_SERVER_CONNECT_REC SILC_SERVER_CONNECT_REC typedef struct { #include "server-rec.h" @@ -36,6 +44,9 @@ typedef struct { GSList *idles; /* Idle queue - send these commands to server if there's nothing else to do */ + + SilcDList ftp_sessions; + FtpSession current_session; gpointer chanqueries; SilcClientConnection conn; @@ -50,5 +61,7 @@ void silc_command_exec(SILC_SERVER_REC *server, const char *command, const char *args); void silc_server_init(void); void silc_server_deinit(void); +void silc_server_free_ftp(SILC_SERVER_REC *server, + SilcClientEntry client_entry); #endif diff --git a/apps/silcd/server.c b/apps/silcd/server.c index f7918f7d..65438285 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -1650,7 +1650,7 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real) /* Parser callback called by silc_packet_receive_process. This merely registers timeout that will handle the actual parsing when appropriate. */ -void silc_server_packet_parse(SilcPacketParserContext *parser_context, +bool silc_server_packet_parse(SilcPacketParserContext *parser_context, void *context) { SilcServer server = (SilcServer)context; @@ -1660,6 +1660,31 @@ void silc_server_packet_parse(SilcPacketParserContext *parser_context, if (idata) idata->psn_receive = parser_context->packet->sequence + 1; + /* If protocol for this connection is key exchange or rekey then we'll + process all packets synchronously, since there might be packets in + queue that we are not able to decrypt without first processing the + packets before them. */ + if (sock->protocol && sock->protocol->protocol && + (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE || + sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)) { + silc_server_packet_parse_real(server->schedule, 0, sock->sock, + parser_context); + + /* Reprocess data since we'll return FALSE here. This is because + the idata->receive_key might have become valid in the last packet + and we want to call this processor with valid cipher. */ + if (idata) + silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? + TRUE : FALSE, idata->receive_key, + idata->hmac_receive, idata->psn_receive, + silc_server_packet_parse, server); + else + silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? + TRUE : FALSE, NULL, NULL, 0, + silc_server_packet_parse, server); + return FALSE; + } + switch (sock->type) { case SILC_SOCKET_TYPE_UNKNOWN: case SILC_SOCKET_TYPE_CLIENT: @@ -1680,8 +1705,10 @@ void silc_server_packet_parse(SilcPacketParserContext *parser_context, SILC_TASK_PRI_NORMAL); break; default: - return; + return TRUE; } + + return TRUE; } /* Parses the packet type and calls what ever routines the packet type diff --git a/apps/silcd/server.h b/apps/silcd/server.h index 5249e6b8..1020a81a 100644 --- a/apps/silcd/server.h +++ b/apps/silcd/server.h @@ -126,7 +126,7 @@ void silc_server_stop(SilcServer server); void silc_server_start_key_exchange(SilcServer server, SilcServerConnection sconn, int sock); -void silc_server_packet_parse(SilcPacketParserContext *parser_context, +bool silc_server_packet_parse(SilcPacketParserContext *parser_context, void *context); void silc_server_packet_parse_type(SilcServer server, SilcSocketConnection sock, diff --git a/includes/clientlibincludes.h b/includes/clientlibincludes.h index 959e13a8..8e026002 100644 --- a/includes/clientlibincludes.h +++ b/includes/clientlibincludes.h @@ -30,7 +30,6 @@ #include "client.h" #include "command.h" #include "command_reply.h" -#include "client_ftp.h" #include "idlist.h" #include "protocol.h" #include "silcapi.h" diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index b8d98dbd..3e0032f6 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -30,7 +30,7 @@ SILC_TASK_CALLBACK(silc_client_packet_parse_real); SILC_TASK_CALLBACK(silc_client_rekey_callback); SILC_TASK_CALLBACK(silc_client_rekey_final); -static void silc_client_packet_parse(SilcPacketParserContext *parser_context, +static bool silc_client_packet_parse(SilcPacketParserContext *parser_context, void *context); static void silc_client_packet_parse_type(SilcClient client, SilcSocketConnection sock, @@ -499,7 +499,8 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_second) ctx->ske->prop->pkcs, ctx->ske->prop->hash, ctx->ske->prop->hmac, - ctx->ske->prop->group); + ctx->ske->prop->group, + ctx->responder); silc_ske_free_key_material(ctx->keymat); /* Allocate internal context for the authentication protocol. This @@ -741,14 +742,14 @@ SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process) /* If connection is disconnecting already we will finally close the connection */ if (SILC_IS_DISCONNECTING(sock)) { - if (sock == conn->sock) + if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT) client->ops->disconnect(client, conn); silc_client_close_connection(client, sock, conn); return; } SILC_LOG_DEBUG(("EOF from connection %d", sock->sock)); - if (sock == conn->sock) + if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT) client->ops->disconnect(client, conn); silc_client_close_connection(client, sock, conn); return; @@ -800,8 +801,8 @@ SILC_TASK_CALLBACK(silc_client_packet_parse_real) /* Parser callback called by silc_packet_receive_process. Thie merely registers timeout that will handle the actual parsing when appropriate. */ -void silc_client_packet_parse(SilcPacketParserContext *parser_context, - void *context) +static bool silc_client_packet_parse(SilcPacketParserContext *parser_context, + void *context) { SilcClient client = (SilcClient)context; SilcSocketConnection sock = parser_context->sock; @@ -810,12 +811,37 @@ void silc_client_packet_parse(SilcPacketParserContext *parser_context, if (conn && conn->hmac_receive) conn->psn_receive = parser_context->packet->sequence + 1; + /* If protocol for this connection is key exchange or rekey then we'll + process all packets synchronously, since there might be packets in + queue that we are not able to decrypt without first processing the + packets before them. */ + if (sock->protocol && sock->protocol->protocol && + (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE || + sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) { + silc_client_packet_parse_real(client->schedule, 0, sock->sock, + parser_context); + + /* Reprocess the buffer since we'll return FALSE. This is because + the `conn->receive_key' might have become valid bu processing + the previous packet */ + if (sock->type != SILC_SOCKET_TYPE_UNKNOWN) + silc_packet_receive_process(sock, FALSE, conn->receive_key, + conn->hmac_receive, conn->psn_receive, + silc_client_packet_parse, client); + else + silc_packet_receive_process(sock, FALSE, NULL, NULL, 0, + silc_client_packet_parse, client); + return FALSE; + } + /* Parse the packet */ - silc_schedule_task_add(client->schedule, parser_context->sock->sock, + silc_schedule_task_add(client->schedule, sock->sock, silc_client_packet_parse_real, (void *)parser_context, 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + + return TRUE; } /* Parses the packet type and calls what ever routines the packet type @@ -1185,7 +1211,7 @@ void silc_client_packet_send(SilcClient client, silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, sock->outbuf->len); - SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len), + SILC_LOG_HEXDUMP(("Packet (%d), len %d", sequence, sock->outbuf->len), sock->outbuf->data, sock->outbuf->len); /* Now actually send the packet */ @@ -1315,6 +1341,14 @@ void silc_client_close_connection(SilcClient client, if (conn->rekey) silc_free(conn->rekey); + if (conn->active_session) { + sock->user_data = NULL; + silc_client_ftp_session_free(conn->active_session); + conn->active_session = NULL; + } + + silc_client_ftp_free_sessions(client, conn); + memset(conn, 0, sizeof(*conn)); silc_client_del_connection(client, conn); } diff --git a/lib/silcclient/client_ftp.c b/lib/silcclient/client_ftp.c index 0e83768b..5d554d37 100644 --- a/lib/silcclient/client_ftp.c +++ b/lib/silcclient/client_ftp.c @@ -30,7 +30,6 @@ silc_client_connect_to_client_internal(SilcClientInternalConnectContext *ctx); SILC_TASK_CALLBACK(silc_client_ftp_connected); static void silc_client_ftp_start_key_agreement(SilcClientFtpSession session, int sock); -static void silc_client_ftp_session_free(SilcClientFtpSession session); /* File transmission session */ struct SilcClientFtpSessionStruct { @@ -39,6 +38,8 @@ struct SilcClientFtpSessionStruct { SilcClientConnection conn; SilcClientEntry client_entry; + SilcSocketConnection sock; + char *hostname; uint16 port; int listener; @@ -58,6 +59,40 @@ struct SilcClientFtpSessionStruct { int fd; }; +void silc_client_ftp_free_sessions(SilcClient client, + SilcClientConnection conn) +{ + if (conn->ftp_sessions) { + SilcClientFtpSession session; + silc_dlist_start(conn->ftp_sessions); + while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) { + session->sock->user_data = NULL; + silc_client_ftp_session_free(session); + } + silc_dlist_del(conn->ftp_sessions, session); + silc_dlist_uninit(conn->ftp_sessions); + } +} + +void silc_client_ftp_session_free_client(SilcClientConnection conn, + SilcClientEntry client_entry) +{ + SilcClientFtpSession session; + + if (!conn->ftp_sessions) + return; + + /* Get the session */ + silc_dlist_start(conn->ftp_sessions); + while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) { + if (session->client_entry == client_entry) { + session->sock->user_data = NULL; + silc_client_ftp_session_free(session); + break; + } + } +} + /* SFTP packet send callback */ static void silc_client_ftp_send_packet(SilcSocketConnection sock, @@ -65,12 +100,42 @@ static void silc_client_ftp_send_packet(SilcSocketConnection sock, { SilcClientFtpSession session = (SilcClientFtpSession)context; SilcClient client = session->client; + SilcBuffer buffer; SILC_LOG_DEBUG(("Start")); + buffer = silc_buffer_alloc(1 + packet->len); + silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); + silc_buffer_format(buffer, + SILC_STR_UI_CHAR(1), + SILC_STR_UI_XNSTRING(packet->data, packet->len), + SILC_STR_END); + /* Send the packet immediately */ silc_client_packet_send(client, sock, SILC_PACKET_FTP, NULL, 0, NULL, NULL, - packet->data, packet->len, TRUE); + buffer->data, buffer->len, TRUE); + + silc_buffer_free(buffer); +} + +/* SFTP monitor callback for SFTP server */ + +static void silc_client_ftp_monitor(SilcSFTP sftp, + SilcSFTPMonitors type, + const SilcSFTPMonitorData data, + void *context) +{ + SilcClientFtpSession session = (SilcClientFtpSession)context; + + if (type == SILC_SFTP_MONITOR_READ) { + /* Call the monitor for application */ + if (session->monitor) + (*session->monitor)(session->client, session->conn, + SILC_CLIENT_FILE_MONITOR_SEND, + data->offset, session->filesize, + session->client_entry, session->session_id, + session->filepath, session->monitor_context); + } } /* Returns the read data */ @@ -136,16 +201,20 @@ static void silc_client_ftp_open_handle(SilcSFTP sftp, if (status != SILC_SFTP_STATUS_OK) { /* XXX errror */ + return; } /* Open the actual local file */ session->fd = silc_file_open(session->filepath, O_RDWR | O_CREAT); if (session->fd < 0) { /* XXX errror */ + return; } + session->read_handle = handle; + /* Now, start reading the file */ - silc_sftp_read(sftp, handle, session->read_offset, 16384, + silc_sftp_read(sftp, session->read_handle, session->read_offset, 16384, silc_client_ftp_data, session); /* Call monitor callback */ @@ -234,7 +303,6 @@ SILC_TASK_CALLBACK(silc_client_ftp_key_agreement_final) SilcProtocol protocol = (SilcProtocol)context; SilcClientKEInternalContext *ctx = (SilcClientKEInternalContext *)protocol->context; - SilcClient client = (SilcClient)ctx->client; SilcClientFtpSession session = (SilcClientFtpSession)ctx->context; SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data; @@ -253,7 +321,8 @@ SILC_TASK_CALLBACK(silc_client_ftp_key_agreement_final) ctx->ske->prop->pkcs, ctx->ske->prop->hash, ctx->ske->prop->hmac, - ctx->ske->prop->group); + ctx->ske->prop->group, + ctx->responder); /* If we are the SFTP client then start the SFTP session and retrieve the info about the file available for download. */ @@ -264,14 +333,17 @@ SILC_TASK_CALLBACK(silc_client_ftp_key_agreement_final) silc_client_ftp_version, session); } + /* Set this as active session */ + conn->active_session = session; + out: silc_ske_free_key_material(ctx->keymat); if (ctx->ske) silc_ske_free(ctx->ske); silc_free(ctx->dest_id); + ctx->sock->protocol = NULL; silc_socket_free(ctx->sock); silc_free(ctx); - ctx->sock->protocol = NULL; silc_protocol_free(protocol); } @@ -291,16 +363,22 @@ static void silc_client_ftp_start_key_agreement(SilcClientFtpSession session, session->port, session); /* Allocate new socket connection object */ - silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, (void *)conn, &conn->sock); + silc_socket_alloc(sock, SILC_SOCKET_TYPE_CLIENT, (void *)conn, &conn->sock); conn->sock->hostname = strdup(session->hostname); conn->sock->port = silc_net_get_remote_port(sock); + session->sock = silc_socket_dup(conn->sock); /* Allocate the SFTP */ - if (session->server) + if (session->server) { session->sftp = silc_sftp_server_start(conn->sock, silc_client_ftp_send_packet, session, session->fs); + /* Monitor transmission */ + silc_sftp_server_set_monitor(session->sftp, SILC_SFTP_MONITOR_READ, + silc_client_ftp_monitor, session); + } + /* Allocate internal context for key exchange protocol. This is sent as context for the protocol. */ proto_ctx = silc_calloc(1, sizeof(*proto_ctx)); @@ -316,6 +394,7 @@ static void silc_client_ftp_start_key_agreement(SilcClientFtpSession session, silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE, &protocol, (void *)proto_ctx, silc_client_ftp_key_agreement_final); + conn->sock->protocol = protocol; /* Register the connection for network input and output. This sets that scheduler will listen for incoming packets for this connection @@ -429,8 +508,10 @@ silc_client_connect_to_client(SilcClient client, /* Free session */ -static void silc_client_ftp_session_free(SilcClientFtpSession session) +void silc_client_ftp_session_free(SilcClientFtpSession session) { + SilcClientConnection conn; + silc_dlist_del(session->conn->ftp_sessions, session); if (session->sftp) { @@ -443,6 +524,29 @@ static void silc_client_ftp_session_free(SilcClientFtpSession session) if (session->fs) silc_sftp_fs_memory_free(session->fs); + if (session->listener) { + silc_schedule_unset_listen_fd(session->client->schedule, + session->listener); + silc_net_close_connection(session->listener); + } + + if (session->sock) { + silc_schedule_unset_listen_fd(session->client->schedule, + session->sock->sock); + silc_net_close_connection(session->sock->sock); + + if (session->sock->user_data) { + conn = (SilcClientConnection)session->sock->user_data; + + if (conn->active_session == session) + conn->active_session = NULL; + + silc_client_close_connection(session->client, session->sock, conn); + } else { + silc_socket_free(session->sock); + } + } + silc_free(session->hostname); silc_free(session->filepath); silc_free(session); @@ -470,7 +574,7 @@ SILC_TASK_CALLBACK(silc_client_ftp_process_key_agreement) silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1); /* Allocate new socket connection object */ - silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket); + silc_socket_alloc(sock, SILC_SOCKET_TYPE_CLIENT, NULL, &newsocket); /* Perform name and address lookups for the remote host. */ silc_net_check_host_by_sock(sock, &newsocket->hostname, &newsocket->ip); @@ -487,6 +591,7 @@ SILC_TASK_CALLBACK(silc_client_ftp_process_key_agreement) newsocket->port, session); conn->sock = newsocket; conn->sock->user_data = conn; + session->sock = silc_socket_dup(conn->sock); /* Allocate internal context for key exchange protocol. This is sent as context for the protocol. */ @@ -526,7 +631,7 @@ uint32 silc_client_file_send(SilcClient client, { SilcClientFtpSession session; SilcBuffer keyagr, ftp; - char *filename; + char *filename, *path; SILC_LOG_DEBUG(("Start")); @@ -550,15 +655,21 @@ uint32 silc_client_file_send(SilcClient client, session->server = TRUE; silc_dlist_add(conn->ftp_sessions, session); + path = silc_calloc(strlen(filepath) + 8, sizeof(*path)); + strcat(path, "file://"); + strncat(path, filepath, strlen(filepath)); + /* Allocate memory filesystem and put the file to it */ - if (strrchr(filepath, '/')) - filename = strrchr(filepath, '/') + 1; + if (strrchr(path, '/')) + filename = strrchr(path, '/') + 1; else - filename = (char *)filepath; + filename = (char *)path; session->fs = silc_sftp_fs_memory_alloc(SILC_SFTP_FS_PERM_READ | SILC_SFTP_FS_PERM_EXEC); silc_sftp_fs_memory_add_file(session->fs, NULL, SILC_SFTP_FS_PERM_READ, - filename, filepath); + filename, path); + + session->filesize = silc_file_size(filepath); /* Send the key agreement inside FTP packet */ keyagr = silc_key_agreement_payload_encode(NULL, 0); @@ -575,6 +686,7 @@ uint32 silc_client_file_send(SilcClient client, silc_buffer_free(keyagr); silc_buffer_free(ftp); + silc_free(path); return session->session_id; } @@ -589,7 +701,7 @@ bool silc_client_file_receive(SilcClient client, SilcClientFtpSession session; SilcBuffer keyagr, ftp; - SILC_LOG_DEBUG(("Start")); + SILC_LOG_DEBUG(("Start, Session ID: %d", session_id)); /* Get the session */ silc_dlist_start(conn->ftp_sessions); @@ -616,7 +728,7 @@ bool silc_client_file_receive(SilcClient client, session->conn = conn; /* Add the listener for the key agreement */ - session->hostname = silc_net_localhost(); + session->hostname = silc_net_localip(); session->listener = silc_net_create_server(0, session->hostname); if (session->listener < 0) { /* XXX Error */ @@ -629,7 +741,7 @@ bool silc_client_file_receive(SilcClient client, 0, 0, SILC_TASK_FD, SILC_TASK_PRI_NORMAL); /* Send the key agreement inside FTP packet */ - keyagr = silc_key_agreement_payload_encode(NULL, 0); + keyagr = silc_key_agreement_payload_encode(session->hostname, session->port); ftp = silc_buffer_alloc(1 + keyagr->len); silc_buffer_pull_tail(ftp, SILC_BUFFER_END(ftp)); @@ -647,12 +759,30 @@ bool silc_client_file_receive(SilcClient client, return TRUE; } +/* Closes FTP session */ + bool silc_client_file_close(SilcClient client, SilcClientConnection conn, uint32 session_id) { + SilcClientFtpSession session; - SILC_LOG_DEBUG(("Start")); + SILC_LOG_DEBUG(("Start, Session ID: %d", session_id)); + + /* Get the session */ + silc_dlist_start(conn->ftp_sessions); + while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) { + if (session->session_id == session_id) { + break; + } + } + + if (session == SILC_LIST_END) { + SILC_LOG_DEBUG(("Unknown session ID: %d\n", session_id)); + return FALSE; + } + + silc_client_ftp_session_free(session); return TRUE; } diff --git a/lib/silcclient/client_ftp.h b/lib/silcclient/client_ftp.h deleted file mode 100644 index 385a48f4..00000000 --- a/lib/silcclient/client_ftp.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - - client_ftp.h - - Author: Pekka Riikonen - - Copyright (C) 2001 Pekka Riikonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - -*/ - -#ifndef CLIENT_FTP_H -#define CLIENT_FTP_H - -#endif /* CLIENT_FTP_H */ diff --git a/lib/silcclient/client_internal.h b/lib/silcclient/client_internal.h index a820e232..c9b950d4 100644 --- a/lib/silcclient/client_internal.h +++ b/lib/silcclient/client_internal.h @@ -58,5 +58,10 @@ SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process); int silc_client_packet_send_real(SilcClient client, SilcSocketConnection sock, bool force_send); +void silc_client_ftp_free_sessions(SilcClient client, + SilcClientConnection conn); +void silc_client_ftp_session_free(SilcClientFtpSession session); +void silc_client_ftp_session_free_client(SilcClientConnection conn, + SilcClientEntry client_entry); #endif diff --git a/lib/silcclient/client_notify.c b/lib/silcclient/client_notify.c index 403d7623..85b4530d 100644 --- a/lib/silcclient/client_notify.c +++ b/lib/silcclient/client_notify.c @@ -305,7 +305,7 @@ void silc_client_notify_by_server(SilcClient client, client->ops->notify(client, conn, type, client_entry, tmp); /* Free data */ - silc_client_del_client_entry(client, client_entry); + silc_client_del_client_entry(client, conn, client_entry); break; case SILC_NOTIFY_TYPE_TOPIC_SET: @@ -406,7 +406,7 @@ void silc_client_notify_by_server(SilcClient client, client->ops->notify(client, conn, type, client_entry, client_entry2); /* Free data */ - silc_client_del_client_entry(client, client_entry); + silc_client_del_client_entry(client, conn, client_entry); break; case SILC_NOTIFY_TYPE_CMODE_CHANGE: diff --git a/lib/silcclient/idlist.c b/lib/silcclient/idlist.c index 9141372c..f5686a72 100644 --- a/lib/silcclient/idlist.c +++ b/lib/silcclient/idlist.c @@ -20,6 +20,7 @@ /* $Id$ */ #include "clientlibincludes.h" +#include "client_internal.h" typedef struct { SilcClientCommandContext cmd; @@ -631,6 +632,7 @@ void silc_client_update_client(SilcClient client, /* Deletes the client entry and frees all memory. */ void silc_client_del_client_entry(SilcClient client, + SilcClientConnection conn, SilcClientEntry client_entry) { SILC_LOG_DEBUG(("Start")); @@ -645,6 +647,7 @@ void silc_client_del_client_entry(SilcClient client, if (client_entry->receive_key) silc_cipher_free(client_entry->receive_key); silc_free(client_entry->key); + silc_client_ftp_session_free_client(conn, client_entry); silc_free(client_entry); } @@ -654,7 +657,7 @@ bool silc_client_del_client(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry) { bool ret = silc_idcache_del_by_context(conn->client_cache, client_entry); - silc_client_del_client_entry(client, client_entry); + silc_client_del_client_entry(client, conn, client_entry); return ret; } diff --git a/lib/silcclient/idlist.h b/lib/silcclient/idlist.h index cd4de489..396d024b 100644 --- a/lib/silcclient/idlist.h +++ b/lib/silcclient/idlist.h @@ -118,6 +118,7 @@ void silc_client_update_client(SilcClient client, const char *userinfo, uint32 mode); void silc_client_del_client_entry(SilcClient client, + SilcClientConnection conn, SilcClientEntry client_entry); SilcClientEntry silc_idlist_get_client(SilcClient client, SilcClientConnection conn, diff --git a/lib/silcclient/protocol.c b/lib/silcclient/protocol.c index ef570d81..9721497f 100644 --- a/lib/silcclient/protocol.c +++ b/lib/silcclient/protocol.c @@ -112,7 +112,8 @@ void silc_client_protocol_ke_set_keys(SilcSKE ske, SilcPKCS pkcs, SilcHash hash, SilcHmac hmac, - SilcSKEDiffieHellmanGroup group) + SilcSKEDiffieHellmanGroup group, + bool is_responder) { SilcClientConnection conn = (SilcClientConnection)sock->user_data; @@ -124,16 +125,29 @@ void silc_client_protocol_ke_set_keys(SilcSKE ske, silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, &conn->hmac_send); silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, &conn->hmac_receive); - silc_cipher_set_key(conn->send_key, keymat->send_enc_key, - keymat->enc_key_len); - silc_cipher_set_iv(conn->send_key, keymat->send_iv); - silc_cipher_set_key(conn->receive_key, keymat->receive_enc_key, - keymat->enc_key_len); - silc_cipher_set_iv(conn->receive_key, keymat->receive_iv); - silc_hmac_set_key(conn->hmac_send, keymat->send_hmac_key, - keymat->hmac_key_len); - silc_hmac_set_key(conn->hmac_receive, keymat->receive_hmac_key, - keymat->hmac_key_len); + if (is_responder == TRUE) { + silc_cipher_set_key(conn->send_key, keymat->receive_enc_key, + keymat->enc_key_len); + silc_cipher_set_iv(conn->send_key, keymat->receive_iv); + silc_cipher_set_key(conn->receive_key, keymat->send_enc_key, + keymat->enc_key_len); + silc_cipher_set_iv(conn->receive_key, keymat->send_iv); + silc_hmac_set_key(conn->hmac_send, keymat->receive_hmac_key, + keymat->hmac_key_len); + silc_hmac_set_key(conn->hmac_receive, keymat->send_hmac_key, + keymat->hmac_key_len); + } else { + silc_cipher_set_key(conn->send_key, keymat->send_enc_key, + keymat->enc_key_len); + silc_cipher_set_iv(conn->send_key, keymat->send_iv); + silc_cipher_set_key(conn->receive_key, keymat->receive_enc_key, + keymat->enc_key_len); + silc_cipher_set_iv(conn->receive_key, keymat->receive_iv); + silc_hmac_set_key(conn->hmac_send, keymat->send_hmac_key, + keymat->hmac_key_len); + silc_hmac_set_key(conn->hmac_receive, keymat->receive_hmac_key, + keymat->hmac_key_len); + } /* Rekey stuff */ conn->rekey = silc_calloc(1, sizeof(*conn->rekey)); diff --git a/lib/silcclient/protocol.h b/lib/silcclient/protocol.h index b74bd6f7..c229ff01 100644 --- a/lib/silcclient/protocol.h +++ b/lib/silcclient/protocol.h @@ -105,6 +105,7 @@ void silc_client_protocol_ke_set_keys(SilcSKE ske, SilcPKCS pkcs, SilcHash hash, SilcHmac hmac, - SilcSKEDiffieHellmanGroup group); + SilcSKEDiffieHellmanGroup group, + bool is_responder); #endif diff --git a/lib/silccore/silcpacket.c b/lib/silccore/silcpacket.c index 7674a030..68cb566c 100644 --- a/lib/silccore/silcpacket.c +++ b/lib/silccore/silcpacket.c @@ -332,7 +332,8 @@ void silc_packet_receive_process(SilcSocketConnection sock, SilcPacketParserContext *parse_ctx; int packetlen, paddedlen, mac_len = 0; int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0; - + bool cont = TRUE; + if (sock->inbuf->len < SILC_PACKET_MIN_HEADER_LEN) return; @@ -340,7 +341,7 @@ void silc_packet_receive_process(SilcSocketConnection sock, mac_len = silc_hmac_len(hmac); /* Parse the packets from the data */ - while (sock->inbuf->len > 0) { + while (sock->inbuf->len > 0 && cont) { /* Decrypt first 16 bytes of the packet */ if (!SILC_IS_INBUF_PENDING(sock) && cipher) @@ -404,15 +405,17 @@ void silc_packet_receive_process(SilcSocketConnection sock, silc_packet_decrypt(cipher, hmac, parse_ctx->packet->sequence, parse_ctx->packet->buffer, parse_ctx->normal); - /* Call the parser */ - if (parser) - (*parser)(parse_ctx, parser_context); - /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */ silc_buffer_pull(sock->inbuf, paddedlen + mac_len); + + /* Call the parser */ + cont = (*parser)(parse_ctx, parser_context); } + if (cont == FALSE && sock->inbuf->len > 0) + return; + SILC_LOG_DEBUG(("Clearing inbound buffer")); silc_buffer_clear(sock->inbuf); } diff --git a/lib/silccore/silcpacket.h b/lib/silccore/silcpacket.h index f0df279e..54e5453c 100644 --- a/lib/silccore/silcpacket.h +++ b/lib/silccore/silcpacket.h @@ -279,7 +279,7 @@ typedef struct { * * SYNOPSIS * - * typedef void (*SilcPacketParserCallback)(SilcPacketParserContext + * typedef bool (*SilcPacketParserCallback)(SilcPacketParserContext * *parse_context); * * DESCRIPTION @@ -292,8 +292,16 @@ typedef struct { * context. The application receiving the SilcPacketParserContext * must free it. * + * This returns TRUE if the library should continue packet processing + * (assuming there is more data to be processed), and FALSE if the + * upper layer does not want the library to continue but to leave the + * rest of the data is the packet queue untouched. Application may + * want to do this for example if the cipher is not ready before + * processing a certain packet. In this case the application wants + * to recall the processing function with the correct cipher. + * ***/ -typedef void (*SilcPacketParserCallback)(SilcPacketParserContext +typedef bool (*SilcPacketParserCallback)(SilcPacketParserContext *parse_context, void *context); /* Macros */ diff --git a/lib/silcsftp/sftp_server.c b/lib/silcsftp/sftp_server.c index d62b3155..119dbf1f 100644 --- a/lib/silcsftp/sftp_server.c +++ b/lib/silcsftp/sftp_server.c @@ -28,6 +28,9 @@ typedef struct { SilcSocketConnection sock; SilcSFTPSendPacketCallback send_packet; void *send_context; + SilcSFTPMonitors monitors; + SilcSFTPMonitor monitor; + void *monitor_context; SilcSFTPFilesystem fs; } *SilcSFTPServer; @@ -285,6 +288,19 @@ void silc_sftp_server_shutdown(SilcSFTP sftp) silc_free(server); } +/* Sets monitor callback */ + +void silc_sftp_server_set_monitor(SilcSFTP sftp, + SilcSFTPMonitors monitors, + SilcSFTPMonitor monitor, + void *context) +{ + SilcSFTPServer server = (SilcSFTPServer)sftp; + server->monitors = monitors; + server->monitor = monitor; + server->monitor_context = context; +} + /* Function that is called to process the incmoing SFTP packet. */ /* XXX Some day this will go away and we have automatic receive callbacks for SilcSocketConnection API or SilcPacketContext API. */ @@ -303,6 +319,7 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, uint32 id; SilcSFTPAttributes attrs; SilcSFTPHandle handle; + SilcSFTPMonitorDataStruct mdata; SILC_LOG_DEBUG(("Start")); @@ -314,6 +331,8 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, silc_buffer_set(&buf, (unsigned char *)payload, payload_len); + memset(&mdata, 0, sizeof(mdata)); + switch (type) { case SILC_SFTP_INIT: { @@ -327,6 +346,13 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, if (ret < 0) break; + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_INIT && server->monitor) { + mdata.version = version; + (*server->monitor)(sftp, SILC_SFTP_MONITOR_INIT, &mdata, + server->monitor_context); + } + silc_sftp_send_packet(server, SILC_SFTP_VERSION, 4, SILC_STR_UI_INT(SILC_SFTP_PROTOCOL_VERSION), SILC_STR_END); @@ -359,6 +385,14 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, attrs = silc_calloc(1, sizeof(*attrs)); } + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_OPEN && server->monitor) { + mdata.name = filename; + mdata.pflags = pflags; + (*server->monitor)(sftp, SILC_SFTP_MONITOR_OPEN, &mdata, + server->monitor_context); + } + /* Open operation */ server->fs->fs->sftp_open(server->fs->fs_context, sftp, filename, pflags, attrs, silc_sftp_server_handle, (void *)id); @@ -392,6 +426,12 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, break; } + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_CLOSE && server->monitor) { + (*server->monitor)(sftp, SILC_SFTP_MONITOR_CLOSE, &mdata, + server->monitor_context); + } + /* Close operation */ server->fs->fs->sftp_close(server->fs->fs_context, sftp, handle, silc_sftp_server_status, (void *)id); @@ -426,6 +466,14 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, break; } + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_READ && server->monitor) { + mdata.offset = offset; + mdata.data_len = len; + (*server->monitor)(sftp, SILC_SFTP_MONITOR_READ, &mdata, + server->monitor_context); + } + /* Read operation */ server->fs->fs->sftp_read(server->fs->fs_context, sftp, handle, offset, len, @@ -463,6 +511,14 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, break; } + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_WRITE && server->monitor) { + mdata.offset = offset; + mdata.data_len = data_len; + (*server->monitor)(sftp, SILC_SFTP_MONITOR_WRITE, &mdata, + server->monitor_context); + } + /* Write operation */ server->fs->fs->sftp_write(server->fs->fs_context, sftp, handle, offset, (const unsigned char *)data, data_len, @@ -481,6 +537,13 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, if (ret < 0) goto failure; + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_REMOVE && server->monitor) { + mdata.name = filename; + (*server->monitor)(sftp, SILC_SFTP_MONITOR_REMOVE, &mdata, + server->monitor_context); + } + /* Remove operation */ server->fs->fs->sftp_remove(server->fs->fs_context, sftp, filename, silc_sftp_server_status, (void *)id); @@ -503,8 +566,17 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, if (ret < 0) goto failure; + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_RENAME && server->monitor) { + mdata.name = filename; + mdata.name2 = newname; + (*server->monitor)(sftp, SILC_SFTP_MONITOR_RENAME, &mdata, + server->monitor_context); + } + /* Rename operation */ - server->fs->fs->sftp_rename(server->fs->fs_context, sftp, filename, newname, + server->fs->fs->sftp_rename(server->fs->fs_context, sftp, + filename, newname, silc_sftp_server_status, (void *)id); silc_free(filename); @@ -536,6 +608,13 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, attrs = silc_calloc(1, sizeof(*attrs)); } + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_MKDIR && server->monitor) { + mdata.name = path; + (*server->monitor)(sftp, SILC_SFTP_MONITOR_MKDIR, &mdata, + server->monitor_context); + } + /* Mkdir operation */ server->fs->fs->sftp_mkdir(server->fs->fs_context, sftp, path, attrs, silc_sftp_server_status, (void *)id); @@ -556,6 +635,13 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, if (ret < 0) goto failure; + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_RMDIR && server->monitor) { + mdata.name = path; + (*server->monitor)(sftp, SILC_SFTP_MONITOR_RMDIR, &mdata, + server->monitor_context); + } + /* Rmdir operation */ server->fs->fs->sftp_rmdir(server->fs->fs_context, sftp, path, silc_sftp_server_status, (void *)id); @@ -575,6 +661,13 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, if (ret < 0) goto failure; + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_OPENDIR && server->monitor) { + mdata.name = path; + (*server->monitor)(sftp, SILC_SFTP_MONITOR_OPENDIR, &mdata, + server->monitor_context); + } + /* Opendir operation */ server->fs->fs->sftp_opendir(server->fs->fs_context, sftp, path, silc_sftp_server_handle, (void *)id); @@ -607,6 +700,12 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, break; } + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_READDIR && server->monitor) { + (*server->monitor)(sftp, SILC_SFTP_MONITOR_READDIR, &mdata, + server->monitor_context); + } + /* Readdir operation */ server->fs->fs->sftp_readdir(server->fs->fs_context, sftp, handle, silc_sftp_server_name, (void *)id); @@ -624,6 +723,13 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, if (ret < 0) goto failure; + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_STAT && server->monitor) { + mdata.name = path; + (*server->monitor)(sftp, SILC_SFTP_MONITOR_STAT, &mdata, + server->monitor_context); + } + /* Stat operation */ server->fs->fs->sftp_stat(server->fs->fs_context, sftp, path, silc_sftp_server_attr, (void *)id); @@ -643,6 +749,13 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, if (ret < 0) goto failure; + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_LSTAT && server->monitor) { + mdata.name = path; + (*server->monitor)(sftp, SILC_SFTP_MONITOR_LSTAT, &mdata, + server->monitor_context); + } + /* Lstat operation */ server->fs->fs->sftp_lstat(server->fs->fs_context, sftp, path, silc_sftp_server_attr, (void *)id); @@ -675,6 +788,12 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, break; } + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_FSTAT && server->monitor) { + (*server->monitor)(sftp, SILC_SFTP_MONITOR_FSTAT, &mdata, + server->monitor_context); + } + /* Fstat operation */ server->fs->fs->sftp_fstat(server->fs->fs_context, sftp, handle, silc_sftp_server_attr, (void *)id); @@ -705,6 +824,13 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, attrs = silc_calloc(1, sizeof(*attrs)); } + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_SETSTAT && server->monitor) { + mdata.name = path; + (*server->monitor)(sftp, SILC_SFTP_MONITOR_SETSTAT, &mdata, + server->monitor_context); + } + /* Setstat operation */ server->fs->fs->sftp_setstat(server->fs->fs_context, sftp, path, attrs, silc_sftp_server_status, (void *)id); @@ -748,8 +874,15 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, break; } + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_FSETSTAT && server->monitor) { + (*server->monitor)(sftp, SILC_SFTP_MONITOR_FSETSTAT, &mdata, + server->monitor_context); + } + /* Fsetstat operation */ - server->fs->fs->sftp_fsetstat(server->fs->fs_context, sftp, handle, attrs, + server->fs->fs->sftp_fsetstat(server->fs->fs_context, sftp, + handle, attrs, silc_sftp_server_status, (void *)id); silc_sftp_attr_free(attrs); @@ -767,6 +900,13 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, if (ret < 0) goto failure; + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_READLINK && server->monitor) { + mdata.name = path; + (*server->monitor)(sftp, SILC_SFTP_MONITOR_READLINK, &mdata, + server->monitor_context); + } + /* Readlink operation */ server->fs->fs->sftp_readlink(server->fs->fs_context, sftp, path, silc_sftp_server_name, (void *)id); @@ -789,6 +929,14 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, if (ret < 0) goto failure; + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_SYMLINK && server->monitor) { + mdata.name = path; + mdata.name2 = target; + (*server->monitor)(sftp, SILC_SFTP_MONITOR_SYMLINK, &mdata, + server->monitor_context); + } + /* Symlink operation */ server->fs->fs->sftp_symlink(server->fs->fs_context, sftp, path, target, silc_sftp_server_status, (void *)id); @@ -809,6 +957,13 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, if (ret < 0) goto failure; + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_REALPATH && server->monitor) { + mdata.name = path; + (*server->monitor)(sftp, SILC_SFTP_MONITOR_REALPATH, &mdata, + server->monitor_context); + } + /* Realpath operation */ server->fs->fs->sftp_realpath(server->fs->fs_context, sftp, path, silc_sftp_server_name, (void *)id); @@ -841,6 +996,12 @@ void silc_sftp_server_receive_process(SilcSFTP sftp, goto failure; data_len = buf.len; + /* Call monitor */ + if (server->monitors & SILC_SFTP_MONITOR_EXTENDED && server->monitor) { + (*server->monitor)(sftp, SILC_SFTP_MONITOR_EXTENDED, &mdata, + server->monitor_context); + } + /* Extended operation */ server->fs->fs->sftp_extended(server->fs->fs_context, sftp, request, data, data_len, diff --git a/lib/silcsftp/silcsftp.h b/lib/silcsftp/silcsftp.h index fb81b595..cfc633e1 100644 --- a/lib/silcsftp/silcsftp.h +++ b/lib/silcsftp/silcsftp.h @@ -874,6 +874,111 @@ SilcSFTP silc_sftp_server_start(SilcSocketConnection sock, ***/ void silc_sftp_server_shutdown(SilcSFTP sftp); +/****d* silcsftp/SilcSFTPAPI/SilcSFTPMonitors + * + * NAME + * + * typedef enum { ... } SilcSFTPMonitors; + * + * DESCRIPTION + * + * SFTP server monitor types. These can be masked together to monitor + * various client requests. + * + * SOURCE + */ +typedef enum { + SILC_SFTP_MONITOR_INIT = 0x0001, + SILC_SFTP_MONITOR_OPEN = 0x0002, + SILC_SFTP_MONITOR_CLOSE = 0x0004, + SILC_SFTP_MONITOR_READ = 0x0008, + SILC_SFTP_MONITOR_WRITE = 0x0010, + SILC_SFTP_MONITOR_REMOVE = 0x0020, + SILC_SFTP_MONITOR_RENAME = 0x0040, + SILC_SFTP_MONITOR_MKDIR = 0x0080, + SILC_SFTP_MONITOR_RMDIR = 0x0100, + SILC_SFTP_MONITOR_OPENDIR = 0x0200, + SILC_SFTP_MONITOR_READDIR = 0x0400, + SILC_SFTP_MONITOR_STAT = 0x0800, + SILC_SFTP_MONITOR_LSTAT = 0x1000, + SILC_SFTP_MONITOR_FSTAT = 0x2000, + SILC_SFTP_MONITOR_SETSTAT = 0x4000, + SILC_SFTP_MONITOR_FSETSTAT = 0x8000, + SILC_SFTP_MONITOR_READLINK = 0x10000, + SILC_SFTP_MONITOR_SYMLINK = 0x20000, + SILC_SFTP_MONITOR_REALPATH = 0x40000, + SILC_SFTP_MONITOR_EXTENDED = 0x80000, +} SilcSFTPMonitors; +/***/ + +/****s* silcsftp/SilcSFTPAPI/SilcSFTP + * + * NAME + * + * typedef struct { ... } *SilcSFTPMonitorData, SilcSFTPMonitorDataStruct; + * + * DESCRIPTION + * + * This structure includes the monitor type specific data. The + * application can check what the client has requested from this + * structure. + * + * SOURCE + */ +typedef struct { + SilcSFTPVersion version; /* _INIT */ + char *name; /* _OPEN, _REMOVE, _RENAME, _MKDIR, + _RMDIR, _OPENDIR, _STAT, _LSTAT, + _SETSTAT, _READLINK, _SYMLINK, _REALPATH */ + char *name2; /* _RENAME, _SYMLINK */ + SilcSFTPFileOperation pflags; /* _OPEN */ + uint64 offset; /* _READ, _WRITE */ + uint32 data_len; /* _READ, _WRITE */ + SilcSFTPName names; /* _READDIR, _READLINK, _REALPATH */ +} *SilcSFTPMonitorData, SilcSFTPMonitorDataStruct; +/***/ + +/****f* silcsftp/SilcSFTPAPI/silc_sftp_server_set_monitor + * + * SYNOPSIS + * + * typedef void (*SilcSFTPMonitor)(SilcSFTP sftp + * SilcSFTPMonitors type, + * void *context); + * + * DESCRIPTION + * + * Monitor callback that is called when an specified request is + * received from client. The `type' is the requested type that + * was being monitored. + * + ***/ +typedef void (*SilcSFTPMonitor)(SilcSFTP sftp, + SilcSFTPMonitors type, + const SilcSFTPMonitorData data, + void *context); + +/****f* silcsftp/SilcSFTPAPI/silc_sftp_server_set_monitor + * + * SYNOPSIS + * + * void silc_sftp_server_set_monitor(SilcSFTP sftp, + * SilcSFTPMonitors monitors, + * SilcSFTPMonitor monitor, + * void *context); + * + * DESCRIPTION + * + * Sets monitor callback to monitor various request sent by an client. + * When request that has been set in the `monitors' is received the + * monitor callback will be called to notify the caller. + * + ***/ +void silc_sftp_server_set_monitor(SilcSFTP sftp, + SilcSFTPMonitors monitors, + SilcSFTPMonitor monitor, + void *context); + /* Function that is called to process the incmoing SFTP packet. */ /* XXX Some day this will go away and we have automatic receive callbacks for SilcSocketConnection API or SilcPacketContext API. */ diff --git a/lib/silcutil/silcnet.c b/lib/silcutil/silcnet.c index 1120529e..2cdac41a 100644 --- a/lib/silcutil/silcnet.c +++ b/lib/silcutil/silcnet.c @@ -229,3 +229,25 @@ char *silc_net_localhost(void) return strdup(dest->h_name); } + +/* Returns local IP address */ + +char *silc_net_localip(void) +{ + char hostname[256]; + struct hostent *dest; + struct in_addr ip; + char *ips; + + if (gethostname(hostname, sizeof(hostname))) + return NULL; + + dest = gethostbyname(hostname); + if (!dest) + return NULL; + + SILC_GET32_LSB(ip.s_addr, dest->h_addr_list[0]); + ips = inet_ntoa(ip); + + return strdup(ips); +} diff --git a/lib/silcutil/silcnet.h b/lib/silcutil/silcnet.h index 40e138f8..7278d237 100644 --- a/lib/silcutil/silcnet.h +++ b/lib/silcutil/silcnet.h @@ -291,6 +291,19 @@ uint16 silc_net_get_local_port(int sock); ***/ char *silc_net_localhost(void); +/****f* silcutil/SilcNetAPI/silc_net_localip + * + * SYNOPSIS + * + * char *silc_net_localip(void) + * + * DESCRIPTION + * + * Return IP of localhost. + * + ***/ +char *silc_net_localip(void); + #ifdef WIN32 /****f* silcutil/SilcNetAPI/silc_net_win32_init diff --git a/lib/silcutil/silcschedule.c b/lib/silcutil/silcschedule.c index bd046a8f..8a8e581c 100644 --- a/lib/silcutil/silcschedule.c +++ b/lib/silcutil/silcschedule.c @@ -747,7 +747,7 @@ void silc_schedule_task_del(SilcSchedule schedule, SilcTask task) void silc_schedule_task_del_by_fd(SilcSchedule schedule, uint32 fd) { - SILC_LOG_DEBUG(("Unregister task by fd")); + SILC_LOG_DEBUG(("Unregister task by fd %d", fd)); silc_task_del_by_fd(schedule->timeout_queue, fd); silc_task_del_by_fd(schedule->fd_queue, fd); @@ -819,6 +819,8 @@ void silc_schedule_unset_listen_fd(SilcSchedule schedule, uint32 fd) silc_mutex_lock(schedule->lock); + SILC_LOG_DEBUG(("Unset listen fd %d", fd)); + for (i = 0; i < schedule->max_fd; i++) if (schedule->fd_list[i].fd == fd) { schedule->fd_list[i].fd = 0; diff --git a/lib/silcutil/silcutil.c b/lib/silcutil/silcutil.c index 9d1ab991..0ee0dd68 100644 --- a/lib/silcutil/silcutil.c +++ b/lib/silcutil/silcutil.c @@ -32,7 +32,7 @@ int silc_file_open(const char *filename, int flags) { int fd; - fd = open(filename, flags); + fd = open(filename, flags, 0600); return fd; } @@ -158,6 +158,20 @@ char *silc_file_readfile(const char *filename, uint32 *return_len) return buffer; } +/* Returns files size. Returns 0 on error. */ + +uint64 silc_file_size(const char *filename) +{ + int ret; + struct stat stats; + + ret = lstat(filename, &stats); + if (ret < 0) + return 0; + + return (uint64)stats.st_size; +} + /* Gets line from a buffer. Stops reading when a newline or EOF occurs. This doesn't remove the newline sign from the destination buffer. The argument begin is returned and should be passed again for the function. */ diff --git a/lib/silcutil/silcutil.h b/lib/silcutil/silcutil.h index 53226bbb..1c467a56 100644 --- a/lib/silcutil/silcutil.h +++ b/lib/silcutil/silcutil.h @@ -30,6 +30,7 @@ char *silc_file_readfile(const char *filename, uint32 *return_len); int silc_file_writefile(const char *filename, const char *buffer, uint32 len); int silc_file_writefile_mode(const char *filename, const char *buffer, uint32 len, int mode); +uint64 silc_file_size(const char *filename); int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin); int silc_check_line(char *buf); char *silc_get_time(); -- 2.24.0