From: Pekka Riikonen Date: Sun, 14 Jan 2007 15:31:35 +0000 (+0000) Subject: Added connection authentication request support. X-Git-Tag: silc.client.1.1.beta1~59 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=8a6279964422ae932dcf5af1a32616cfcbde5a19 Added connection authentication request support. Fixed channel reference counting. --- diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index f8931441..d46f0818 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2006 Pekka Riikonen + Copyright (C) 1997 - 2007 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 @@ -64,7 +64,6 @@ static void silc_client_connection_finished(SilcFSMThread fsm, silc_fsm_free(fsm); } - /* Packet FSM thread destructor */ static void silc_client_packet_destructor(SilcFSMThread thread, @@ -101,7 +100,6 @@ static SilcBool silc_client_packet_receive(SilcPacketEngine engine, case SILC_PACKET_KEY_EXCHANGE_2: case SILC_PACKET_REKEY_DONE: case SILC_PACKET_CONNECTION_AUTH: - case SILC_PACKET_CONNECTION_AUTH_REQUEST: return FALSE; break; } @@ -307,7 +305,7 @@ SILC_FSM_STATE(silc_client_connection_st_packet) case SILC_PACKET_FTP: /* File transfer packet */ - // silc_client_ftp(client, conn, packet); +// silc_fsm_next(fsm, silc_client_ftp); break; case SILC_PACKET_CHANNEL_KEY: @@ -356,9 +354,8 @@ SILC_FSM_STATE(silc_client_connection_st_packet) break; case SILC_PACKET_CONNECTION_AUTH_REQUEST: - /* Reply to connection authentication request to resolve authentication - method from server. */ - // silc_client_connection_auth_request(client, conn, packet); + /** Connection auth resolve reply */ + silc_fsm_next(fsm, silc_client_connect_auth_request); break; case SILC_PACKET_REKEY: @@ -427,7 +424,6 @@ SILC_FSM_STATE(silc_client_connection_st_close) silc_packet_stream_destroy(conn->stream); SILC_LOG_DEBUG(("Finishing connection machine")); - SILC_FSM_FINISH; } @@ -857,114 +853,6 @@ void silc_client_close_connection(SilcClient client, } } -#if 0 -/* Processes incoming connection authentication method request packet. - It is a reply to our previously sent request. The packet can be used - to resolve the authentication method for the current session if the - client does not know it beforehand. */ - -void silc_client_connection_auth_request(SilcClient client, - SilcClientConnection conn, - SilcPacketContext *packet) -{ - SilcClientConnection conn = (SilcClientConnection)sock->user_data; - SilcUInt16 conn_type, auth_meth; - int ret; - - /* If we haven't send our request then ignore this one. */ - if (!conn->internal->connauth) - return; - - /* Parse the payload */ - ret = silc_buffer_unformat(packet->buffer, - SILC_STR_UI_SHORT(&conn_type), - SILC_STR_UI_SHORT(&auth_meth), - SILC_STR_END); - if (ret == -1) - auth_meth = SILC_AUTH_NONE; - - /* Call the request callback to notify application for received - authentication method information. */ - if (conn->internal->connauth->callback) - (*conn->internal->connauth->callback)(client, conn, auth_meth, - conn->internal->connauth->context); - - silc_schedule_task_del(client->schedule, conn->internal->connauth->timeout); - - silc_free(conn->internal->connauth); - conn->internal->connauth = NULL; -} - -/* Timeout task callback called if the server does not reply to our - connection authentication method request in the specified time interval. */ - -SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout) -{ - SilcClientConnection conn = (SilcClientConnection)context; - SilcClient client = conn->client; - - if (!conn->internal->connauth) - return; - - /* Call the request callback to notify application */ - if (conn->internal->connauth->callback) - (*conn->internal->connauth->callback)(client, conn, SILC_AUTH_NONE, - conn->internal->connauth->context); - - silc_free(conn->internal->connauth); - conn->internal->connauth = NULL; -} - -/* This function can be used to request the current authentication method - from the server. This may be called when connecting to the server - and the client library requests the authentication data from the - application. If the application does not know the current authentication - method it can request it from the server using this function. - The `callback' with `context' will be called after the server has - replied back with the current authentication method. */ - -void -silc_client_request_authentication_method(SilcClient client, - SilcClientConnection conn, - SilcConnectionAuthRequest callback, - void *context) -{ - SilcClientConnAuthRequest connauth; - SilcBuffer packet; - - assert(client && conn); - connauth = silc_calloc(1, sizeof(*connauth)); - connauth->callback = callback; - connauth->context = context; - - if (conn->internal->connauth) - silc_free(conn->internal->connauth); - - conn->internal->connauth = connauth; - - /* Assemble the request packet and send it to the server */ - packet = silc_buffer_alloc(4); - silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet)); - silc_buffer_format(packet, - SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT), - SILC_STR_UI_SHORT(SILC_AUTH_NONE), - SILC_STR_END); - silc_client_packet_send(client, conn->sock, - SILC_PACKET_CONNECTION_AUTH_REQUEST, - NULL, 0, NULL, NULL, - packet->data, packet->len, FALSE); - silc_buffer_free(packet); - - /* Register a timeout in case server does not reply anything back. */ - connauth->timeout = - silc_schedule_task_add(client->schedule, conn->sock->sock, - silc_client_request_authentication_method_timeout, - conn, - client->internal->params->connauth_request_secs, 0, - SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); -} -#endif /* 0 */ - /* Allocates new client object. This has to be done before client may work. After calling this one must call silc_client_init to initialize the client. The `application' is application specific user data pointer @@ -997,9 +885,6 @@ SilcClient silc_client_alloc(SilcClientOperations *ops, if (params) memcpy(new_client->internal->params, params, sizeof(*params)); - if (!new_client->internal->params->connauth_request_secs) - new_client->internal->params->connauth_request_secs = 2; - new_client->internal->params-> nickname_format[sizeof(new_client->internal-> params->nickname_format) - 1] = 0; diff --git a/lib/silcclient/client.h b/lib/silcclient/client.h index ab56cfbb..147dcbd1 100644 --- a/lib/silcclient/client.h +++ b/lib/silcclient/client.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2006 Pekka Riikonen + Copyright (C) 1997 - 2007 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 @@ -39,7 +39,7 @@ typedef struct SilcClientCommandReplyContextStruct typedef struct SilcChannelUserStruct *SilcChannelUser; typedef struct SilcClientInternalStruct *SilcClientInternal; typedef struct SilcClientConnectionInternalStruct - *SilcClientConnectionInternal; + *SilcClientConnectionInternal; typedef struct SilcChannelPrivateKeyStruct *SilcChannelPrivateKey; diff --git a/lib/silcclient/client_channel.c b/lib/silcclient/client_channel.c index 59902d84..e7753b94 100644 --- a/lib/silcclient/client_channel.c +++ b/lib/silcclient/client_channel.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2004, 2006 Pekka Riikonen + Copyright (C) 1997 - 2007 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 @@ -701,6 +701,8 @@ SilcBool silc_client_add_to_channel(SilcClient client, if (silc_client_on_channel(channel, client_entry)) return TRUE; + SILC_LOG_DEBUG(("Add client %s to channel", client_entry->nickname)); + chu = silc_calloc(1, sizeof(*chu)); if (!chu) return FALSE; @@ -731,10 +733,16 @@ SilcBool silc_client_remove_from_channel(SilcClient client, if (!chu) return FALSE; + SILC_LOG_DEBUG(("Remove client %s from channel", client_entry->nickname)); + silc_hash_table_del(chu->client->channels, chu->channel); silc_hash_table_del(chu->channel->user_list, chu->client); silc_free(chu); + /* If channel became empty, delete it */ + if (!silc_hash_table_count(channel->user_list)) + silc_client_del_channel(client, conn, channel); + silc_client_unref_client(client, conn, client_entry); silc_client_unref_channel(client, conn, channel); @@ -750,10 +758,20 @@ void silc_client_remove_from_channels(SilcClient client, SilcHashTableList htl; SilcChannelUser chu; + if (!silc_hash_table_count(client_entry->channels)) + return; + + SILC_LOG_DEBUG(("Remove client from all joined channels")); + silc_hash_table_list(client_entry->channels, &htl); while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { silc_hash_table_del(chu->client->channels, chu->channel); silc_hash_table_del(chu->channel->user_list, chu->client); + + /* If channel became empty, delete it */ + if (!silc_hash_table_count(chu->channel->user_list)) + silc_client_del_channel(client, conn, chu->channel); + silc_client_unref_client(client, conn, chu->client); silc_client_unref_channel(client, conn, chu->channel); silc_free(chu); diff --git a/lib/silcclient/client_channel.h b/lib/silcclient/client_channel.h index d72e2189..ed590e07 100644 --- a/lib/silcclient/client_channel.h +++ b/lib/silcclient/client_channel.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2006 Pekka Riikonen + Copyright (C) 2006 - 2007 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 diff --git a/lib/silcclient/client_connect.c b/lib/silcclient/client_connect.c index b9267fb1..06215fb8 100644 --- a/lib/silcclient/client_connect.c +++ b/lib/silcclient/client_connect.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2006 Pekka Riikonen + Copyright (C) 2006 - 2007 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 @@ -278,21 +278,16 @@ static void silc_client_rekey_completion(SilcSKE ske, /* Callback called by application to return authentication data */ -static void silc_client_connect_auth_method(SilcBool success, - SilcAuthMethod auth_meth, +static void silc_client_connect_auth_method(SilcAuthMethod auth_meth, void *auth, SilcUInt32 auth_len, void *context) { SilcFSMThread fsm = context; SilcClientConnection conn = silc_fsm_get_context(fsm); - conn->internal->params.auth_method = SILC_AUTH_NONE; - - if (success) { - conn->internal->params.auth_method = auth_meth; - conn->internal->params.auth = auth; - conn->internal->params.auth_len = auth_len; - } + conn->internal->params.auth_method = auth_meth; + conn->internal->params.auth = auth; + conn->internal->params.auth_len = auth_len; SILC_FSM_CALL_CONTINUE(fsm); } @@ -324,6 +319,42 @@ static void silc_client_connect_auth_completion(SilcConnAuth connauth, SILC_FSM_CALL_CONTINUE(fsm); } +/********************** CONNECTION_AUTH_REQUEST packet **********************/ + +/* Received connection authentication request packet. We get the + required authentication method here. */ + +SILC_FSM_STATE(silc_client_connect_auth_request) +{ + SilcClientConnection conn = fsm_context; + SilcPacket packet = state_context; + SilcUInt16 conn_type, auth_meth; + + if (!conn->internal->auth_request) { + silc_packet_free(packet); + SILC_FSM_FINISH; + } + + /* Parse the payload */ + if (silc_buffer_unformat(&packet->buffer, + SILC_STR_UI_SHORT(&conn_type), + SILC_STR_UI_SHORT(&auth_meth), + SILC_STR_END) < 0) + auth_meth = SILC_AUTH_NONE; + + silc_packet_free(packet); + + SILC_LOG_DEBUG(("Resolved authentication method: %s", + (auth_meth == SILC_AUTH_NONE ? "none" : + auth_meth == SILC_AUTH_PASSWORD ? "passphrase" : + "public key"))); + conn->internal->params.auth_method = auth_meth; + + /* Continue authentication */ + silc_fsm_continue_sync(&conn->internal->event_thread); + SILC_FSM_FINISH; +} + /*************************** Connect remote host ****************************/ /* Connection timeout callback */ @@ -472,7 +503,7 @@ SILC_FSM_STATE(silc_client_st_connect_key_exchange) silc_fsm_next(fsm, silc_client_st_connect_setup_udp); else /** Run key exchange (TCP) */ - silc_fsm_next(fsm, silc_client_st_connect_auth); + silc_fsm_next(fsm, silc_client_st_connect_auth_resolve); SILC_FSM_CALL(conn->internal->op = silc_ske_initiator(conn->internal->ske, conn->stream, @@ -521,13 +552,48 @@ SILC_FSM_STATE(silc_client_st_connect_setup_udp) silc_stream_destroy(old); /** Start authentication */ - silc_fsm_next(fsm, silc_client_st_connect_auth); + silc_fsm_next(fsm, silc_client_st_connect_auth_resolve); SILC_FSM_CONTINUE; } -/* Get authentication method to be used in authentication protocol */ +/* Resolved authentication method to be used in authentication protocol */ + +SILC_FSM_STATE(silc_client_st_connect_auth_resolve) +{ + SilcClientConnection conn = fsm_context; + + SILC_LOG_DEBUG(("Resolve authentication method")); + + if (conn->internal->disconnected) { + /** Disconnected */ + silc_fsm_next(fsm, silc_client_st_connect_error); + SILC_FSM_CONTINUE; + } + + /* If authentication method and data is set, use them */ + if (conn->internal->params.auth_set) { + /** Got authentication data */ + silc_fsm_next(fsm, silc_client_st_connect_auth_start); + SILC_FSM_CONTINUE; + } + + /* Send connection authentication request packet */ + silc_packet_send_va(conn->stream, + SILC_PACKET_CONNECTION_AUTH_REQUEST, 0, + SILC_STR_UI_SHORT(SILC_CONN_CLIENT), + SILC_STR_UI_SHORT(SILC_AUTH_NONE), + SILC_STR_END); + + /** Wait for authentication method */ + conn->internal->auth_request = TRUE; + conn->internal->params.auth_method = SILC_AUTH_NONE; + silc_fsm_next_later(fsm, silc_client_st_connect_auth_data, 2, 0); + SILC_FSM_WAIT; +} + +/* Get authentication data to be used in authentication protocol */ -SILC_FSM_STATE(silc_client_st_connect_auth) +SILC_FSM_STATE(silc_client_st_connect_auth_data) { SilcClientConnection conn = fsm_context; SilcClient client = conn->client; @@ -540,21 +606,16 @@ SILC_FSM_STATE(silc_client_st_connect_auth) SILC_FSM_CONTINUE; } - silc_fsm_next(fsm, silc_client_st_connect_auth_start); + conn->internal->auth_request = FALSE; - /* If authentication data not provided, ask from application */ - if (!conn->internal->params.auth_set) - SILC_FSM_CALL(client->internal->ops->get_auth_method( + /** Get authentication data */ + silc_fsm_next(fsm, silc_client_st_connect_auth_start); + SILC_FSM_CALL(client->internal->ops->get_auth_method( client, conn, conn->remote_host, conn->remote_port, + conn->internal->params.auth_method, silc_client_connect_auth_method, fsm)); - - if (conn->internal->params.auth_method == SILC_AUTH_PUBLIC_KEY) - conn->internal->params.auth = conn->private_key; - - /* We have authentication data */ - SILC_FSM_CONTINUE; } /* Start connection authentication with remote host */ @@ -573,6 +634,10 @@ SILC_FSM_STATE(silc_client_st_connect_auth_start) SILC_FSM_CONTINUE; } + /* We always use the same key for connection authentication and SKE */ + if (conn->internal->params.auth_method == SILC_AUTH_PUBLIC_KEY) + conn->internal->params.auth = conn->private_key; + /* Allocate connection authentication protocol */ connauth = silc_connauth_alloc(conn->internal->schedule, conn->internal->ske, diff --git a/lib/silcclient/client_connect.h b/lib/silcclient/client_connect.h index 0ee3c9ca..9c825f39 100644 --- a/lib/silcclient/client_connect.h +++ b/lib/silcclient/client_connect.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2006 Pekka Riikonen + Copyright (C) 2006 - 2007 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 @@ -20,12 +20,13 @@ #ifndef CLIENT_CONNECT_H #define CLIENT_CONNECT_H -/* States */ +SILC_FSM_STATE(silc_client_connect_auth_request); SILC_FSM_STATE(silc_client_st_connect); SILC_FSM_STATE(silc_client_st_connect_set_stream); SILC_FSM_STATE(silc_client_st_connect_key_exchange); SILC_FSM_STATE(silc_client_st_connect_setup_udp); -SILC_FSM_STATE(silc_client_st_connect_auth); +SILC_FSM_STATE(silc_client_st_connect_auth_resolve); +SILC_FSM_STATE(silc_client_st_connect_auth_data); SILC_FSM_STATE(silc_client_st_connect_auth_start); SILC_FSM_STATE(silc_client_st_connected); SILC_FSM_STATE(silc_client_st_connect_error); diff --git a/lib/silcclient/client_ftp.c b/lib/silcclient/client_ftp.c index 09aac707..ecb361c9 100644 --- a/lib/silcclient/client_ftp.c +++ b/lib/silcclient/client_ftp.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2001 - 2004 Pekka Riikonen + Copyright (C) 2001 - 2007 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 @@ -867,9 +867,7 @@ silc_client_file_send(SilcClient client, session->filepath = strdup(filepath); silc_dlist_add(conn->internal->ftp_sessions, session); - path = silc_calloc(strlen(filepath) + 9, sizeof(*path)); - silc_strncat(path, strlen(filepath) + 9, "file://", 7); - silc_strncat(path, strlen(filepath) + 9, filepath, strlen(filepath)); + silc_asprintf(&path, "file://%s", filepath); /* Allocate memory filesystem and put the file to it */ if (strrchr(path, '/')) @@ -1089,30 +1087,77 @@ SilcClientFileError silc_client_file_close(SilcClient client, return SILC_CLIENT_FILE_OK; } -/* Callback called after remote client information has been resolved. - This will try to find existing session for the client entry. If found - then continue with the key agreement protocol. If not then it means - this is a file transfer request and we let the application know. */ +/************************** FTP Request Processing **************************/ -static void silc_client_ftp_resolve_cb(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context) +/* Client resolving callback. Continues with the FTP processing */ + +static void silc_client_ftp_client_resolved(SilcClient client, + SilcClientConnection conn, + SilcStatus status, + SilcDList clients, + void *context) { - SilcPacketContext *packet = (SilcPacketContext *)context; - SilcClientFtpSession session; - SilcKeyAgreementPayload payload = NULL; - SilcClientEntry client_entry; + SilcFSMThread thread = context; + SilcPacket packet = silc_fsm_get_state_context(thread); + + /* If no client found, ignore the packet, a silent error */ + if (!clients) { + silc_packet_free(packet); + silc_fsm_finish(thread); + return; + } + + /* Continue processing the packet */ + SILC_FSM_CALL_CONTINUE(context); +} + +/* Received file transfer packet. Only file transfer requests get here. + The actual file transfer is handled by the SFTP library when we give it + the packet stream wrapped into SilcStream context. */ + +SILC_FSM_STATE(silc_client_ftp) +{ + SilcClientConnection conn = fsm_context; + SilcClient client = conn->client; + SilcPacket packet = state_context; + SilcClientID remote_id; + SilcClientEntry remote_client; + SilcKeyAgreementPayload payload; + SilcUInt8 type; char *hostname; SilcUInt16 port; + int ret; - SILC_LOG_DEBUG(("Start")); + SILC_LOG_DEBUG(("Process file transfer packet")); + + if (silc_buffer_len(&packet->buffer) < 1) + goto out; - if (!clients) + /* We support file transfer type number 1 (== SFTP) */ + if (packet->buffer.data[0] != 0x01) { + SILC_LOG_DEBUG(("Unsupported file transfer type %d", + packet->buffer.data[0])); goto out; + } + + if (!silc_id_str2id(packet->src_id, packet->src_id_len, + SILC_ID_CLIENT, &remote_id, sizeof(remote_id))) { + SILC_LOG_DEBUG(("Invalid client ID")); + goto out; + } + + /* Check whether we know this client already */ + remote_client = silc_client_get_client_by_id(client, conn, &remote_id); + if (!remote_client || !remote_client->nickname[0]) { + /** Resolve client info */ + silc_client_unref_client(client, conn, remote_client); + SILC_FSM_CALL(silc_client_get_client_by_id_resolve( + client, conn, &remote_id, NULL, + silc_client_ftp_client_resolved, + fsm)); + /* NOT REACHED */ + } - client_entry = clients[0]; silc_dlist_start(conn->internal->ftp_sessions); while ((session = silc_dlist_get(conn->internal->ftp_sessions)) @@ -1123,10 +1168,12 @@ static void silc_client_ftp_resolve_cb(SilcClient client, } /* Parse the key agreement payload */ - payload = silc_key_agreement_payload_parse(packet->buffer->data, - packet->buffer->len); - if (!payload) + payload = silc_key_agreement_payload_parse(packet->buffer->data + 1, + packet->buffer->len - 1); + if (!payload) { + SILC_LOG_DEBUG(("Invalid key agreement payload")); goto out; + } hostname = silc_key_agreement_get_hostname(payload); port = silc_key_agreement_get_port(payload); @@ -1185,65 +1232,9 @@ static void silc_client_ftp_resolve_cb(SilcClient client, session->filepath, session->monitor_context); } - out: - if (payload) - silc_key_agreement_payload_free(payload); - silc_packet_context_free(packet); -} - -/* Called when file transfer packet is received. This will parse the - packet and give it to the file transfer protocol. */ - -void silc_client_ftp(SilcClient client, - SilcSocketConnection sock, - SilcPacketContext *packet) -{ - SilcClientConnection conn = (SilcClientConnection)sock->user_data; - SilcUInt8 type; - int ret; - - SILC_LOG_DEBUG(("Start")); - - /* Parse the payload */ - ret = silc_buffer_unformat(packet->buffer, - SILC_STR_UI_CHAR(&type), - SILC_STR_END); - if (ret == -1) - return; - - /* We support only type number 1 (== SFTP) */ - if (type != 1) - return; - silc_buffer_pull(packet->buffer, 1); - /* If we have active FTP session then give the packet directly to the - protocol processor. */ - if (conn->internal->active_session) { - /* Give it to the SFTP */ - if (conn->internal->active_session->server) - silc_sftp_server_receive_process(conn->internal->active_session->sftp, - sock, packet); - else - silc_sftp_client_receive_process(conn->internal->active_session->sftp, - sock, packet); - } else { - /* We don't have active session, resolve the remote client information - and then try to find the correct session. */ - SilcClientID *remote_id; - - if (packet->src_id_type != SILC_ID_CLIENT) - return; - - remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, - SILC_ID_CLIENT); - if (!remote_id) - return; - - /* Resolve the client */ - silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id, - NULL, silc_client_ftp_resolve_cb, - silc_packet_context_dup(packet)); - silc_free(remote_id); - } + out: + silc_packet_free(packet); + SILC_FSM_FINISH; } diff --git a/lib/silcclient/client_internal.h b/lib/silcclient/client_internal.h index 75425acb..c7bc0434 100644 --- a/lib/silcclient/client_internal.h +++ b/lib/silcclient/client_internal.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2006 Pekka Riikonen + Copyright (C) 1997 - 2007 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 @@ -49,39 +49,6 @@ typedef struct { void *completion_context; } *VerifyKeyContext; -/* Context to hold the connection authentication request callbacks that - will be called when the server has replied back to our request about - current authentication method in the session. */ -typedef struct { - SilcConnectionAuthRequest callback; - void *context; - SilcTask timeout; -} *SilcClientConnAuthRequest; - -/* Generic rekey context for connections */ -typedef struct { - /* Current sending encryption key, provided for re-key. The `pfs' - is TRUE if the Perfect Forward Secrecy is performed in re-key. */ - unsigned char *send_enc_key; - SilcUInt32 enc_key_len; - int ske_group; - SilcBool pfs; - SilcUInt32 timeout; - void *context; -} *SilcClientRekey; - -/* Internal context for connection process. This is needed as we - doing asynchronous connecting. */ -typedef struct { - SilcClient client; - SilcClientConnection conn; - SilcTask task; - int sock; - char *host; - int port; - void *context; -} SilcClientInternalConnectContext; - /* Structure to hold away messages set by user. This is mainly created for future extensions where away messages could be set according filters such as nickname and hostname. For now only one away message can @@ -160,7 +127,7 @@ struct SilcClientConnectionInternalStruct { SilcClientConnectionParams params; /* Connection parameters */ SilcFSMStruct fsm; /* Connection FSM */ SilcFSMThreadStruct event_thread; /* FSM thread for events */ - SilcFSMEventStruct wait_event; /* Event signaller */ + SilcFSMEventStruct wait_event; /* Event signaller */ SilcSchedule schedule; /* Connection's scheduler */ SilcMutex lock; /* Connection lock */ SilcSKE ske; /* Key exchange protocol */ @@ -173,6 +140,7 @@ struct SilcClientConnectionInternalStruct { SilcBuffer remote_idp; /* Remote ID Payload */ SilcAsyncOperation op; /* Protocols async operation */ SilcAsyncOperation cop; /* Async operation for application */ + SilcHashTable attrs; /* Configured user attributes */ SilcIDCache client_cache; /* Client entry cache */ SilcIDCache channel_cache; /* Channel entry cache */ @@ -193,13 +161,12 @@ struct SilcClientConnectionInternalStruct { unsigned int registering : 1; /* Set when registering to network */ unsigned int rekey_responder : 1; /* Set when rekeying as responder */ unsigned int callback_called : 1; /* Set when connect callback called */ + unsigned int auth_request : 1; /* Set when requesting auth method */ SilcClientAway *away; - SilcClientConnAuthRequest connauth; SilcDList ftp_sessions; SilcUInt32 next_session_id; SilcClientFtpSession active_session; - SilcHashTable attrs; SilcHashTable privmsg_wait; /* Waited private messages */ }; diff --git a/lib/silcclient/client_keyagr.c b/lib/silcclient/client_keyagr.c index a0c791d8..3effa056 100644 --- a/lib/silcclient/client_keyagr.c +++ b/lib/silcclient/client_keyagr.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2001 - 2006 Pekka Riikonen + Copyright (C) 2001 - 2007 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 @@ -186,7 +186,7 @@ static void silc_client_keyagr_completion(SilcSKE ske, silc_client_keyagr_free(client, conn, client_entry); } -/* Starts key agreement as responder. */ +/* Starts key agreement as responder. */ static void silc_client_process_key_agreement(SilcClient client, SilcClientConnection conn, diff --git a/lib/silcclient/client_notify.c b/lib/silcclient/client_notify.c index 90c18490..7cdb688c 100644 --- a/lib/silcclient/client_notify.c +++ b/lib/silcclient/client_notify.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2006 Pekka Riikonen + Copyright (C) 1997 - 2007 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 @@ -75,7 +75,7 @@ static SilcBool silc_client_notify_wait_continue(SilcClient client, /* Continue after last command reply received */ if (SILC_STATUS_IS_ERROR(status) || status == SILC_STATUS_OK || status == SILC_STATUS_LIST_END) - SILC_FSM_CALL_CONTINUE(notify->fsm); + SILC_FSM_CALL_CONTINUE_SYNC(notify->fsm); return TRUE; } @@ -471,10 +471,12 @@ SILC_FSM_STATE(silc_client_notify_signoff) SilcClient client = conn->client; SilcClientNotify notify = state_context; SilcNotifyPayload payload = notify->payload; + SilcPacket packet = notify->packet; SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); SilcClientEntry client_entry; - unsigned char *tmp; + SilcChannelEntry channel; + unsigned char *tmp; SilcUInt32 tmp_len; SilcID id; @@ -497,8 +499,19 @@ SILC_FSM_STATE(silc_client_notify_signoff) /* Notify application */ NOTIFY(client, conn, type, client_entry, tmp); + /* Remove from channel */ + if (packet->dst_id_type == SILC_ID_CHANNEL) { + if (silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL, + &id.u.channel_id, sizeof(id.u.channel_id))) { + channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id); + if (channel) { + silc_client_remove_from_channel(client, conn, channel, client_entry); + silc_client_unref_channel(client, conn, channel); + } + } + } + /* Delete client */ - silc_client_remove_from_channels(client, conn, client_entry); silc_client_del_client(client, conn, client_entry); silc_client_unref_client(client, conn, client_entry); diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index a1050556..91f35f32 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2006 Pekka Riikonen + Copyright (C) 1997 - 2007 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 @@ -119,9 +119,6 @@ static void silc_client_command_resolve_continue(SilcClient client, if (status != SILC_STATUS_OK) silc_fsm_next(&cmd->thread, silc_client_command_continue_error); - if (clients) - silc_dlist_uninit(clients); - /* Continue with the command */ SILC_FSM_CALL_CONTINUE(&cmd->thread); } @@ -854,7 +851,8 @@ SILC_FSM_STATE(silc_client_command_list) { SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; - SilcChannelEntry channel; + SilcClient client = conn->client; + SilcChannelEntry channel = NULL; SilcBuffer idp = NULL; if (cmd->argc == 2) { @@ -871,6 +869,7 @@ SILC_FSM_STATE(silc_client_command_list) 1, 1, silc_buffer_datalen(idp)); silc_buffer_free(idp); + silc_client_unref_channel(client, conn, channel); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -888,6 +887,7 @@ SILC_FSM_STATE(silc_client_command_topic) { SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; + SilcClient client = conn->client; SilcChannelEntry channel; SilcBuffer idp; char *name; @@ -934,6 +934,7 @@ SILC_FSM_STATE(silc_client_command_topic) 1, silc_buffer_datalen(idp)); silc_buffer_free(idp); + silc_client_unref_channel(client, conn, channel); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -957,7 +958,7 @@ SILC_FSM_STATE(silc_client_command_invite) SilcClientConnection conn = cmd->conn; SilcClient client = conn->client; SilcClientEntry client_entry = NULL; - SilcChannelEntry channel; + SilcChannelEntry channel = NULL; SilcBuffer clidp, chidp, args = NULL; SilcPublicKey pubkey = NULL; SilcDList clients = NULL; @@ -980,6 +981,7 @@ SILC_FSM_STATE(silc_client_command_invite) } channel = conn->current_channel; + silc_client_ref_channel(client, conn, channel); } else { name = cmd->argv[1]; @@ -1058,6 +1060,7 @@ SILC_FSM_STATE(silc_client_command_invite) silc_buffer_free(args); silc_free(nickname); silc_client_list_free(client, conn, clients); + silc_client_unref_channel(client, conn, channel); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -1280,7 +1283,8 @@ SILC_FSM_STATE(silc_client_command_join) { SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; - SilcChannelEntry channel; + SilcClient client = conn->client; + SilcChannelEntry channel = NULL; SilcBuffer auth = NULL, cauth = NULL; char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL; int i, passphrase_len = 0; @@ -1378,6 +1382,7 @@ SILC_FSM_STATE(silc_client_command_join) if (passphrase) memset(passphrase, 0, strlen(passphrase)); silc_free(passphrase); + silc_client_unref_channel(client, conn, channel); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -1387,6 +1392,7 @@ SILC_FSM_STATE(silc_client_command_join) SILC_FSM_CONTINUE; out: + silc_client_unref_channel(client, conn, channel); SILC_FSM_FINISH; } @@ -1574,7 +1580,7 @@ SILC_FSM_STATE(silc_client_command_cmode) SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; SilcClient client = conn->client; - SilcChannelEntry channel; + SilcChannelEntry channel = NULL; SilcBuffer chidp, auth = NULL, pk = NULL; unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL; SilcUInt32 mode, add, type, len, arg_len = 0; @@ -1594,6 +1600,7 @@ SILC_FSM_STATE(silc_client_command_cmode) } channel = conn->current_channel; + silc_client_ref_channel(client, conn, channel); } else { name = cmd->argv[1]; @@ -1847,6 +1854,7 @@ SILC_FSM_STATE(silc_client_command_cmode) silc_buffer_free(chidp); silc_buffer_free(auth); silc_buffer_free(pk); + silc_client_unref_channel(client, conn, channel); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -1856,6 +1864,7 @@ SILC_FSM_STATE(silc_client_command_cmode) SILC_FSM_CONTINUE; out: + silc_client_unref_channel(client, conn, channel); SILC_FSM_FINISH; } @@ -1868,7 +1877,7 @@ SILC_FSM_STATE(silc_client_command_cumode) SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; SilcClient client = conn->client; - SilcChannelEntry channel; + SilcChannelEntry channel = NULL; SilcChannelUser chu; SilcClientEntry client_entry; SilcBuffer clidp, chidp, auth = NULL; @@ -1892,6 +1901,7 @@ SILC_FSM_STATE(silc_client_command_cumode) } channel = conn->current_channel; + silc_client_ref_channel(client, conn, channel); } else { name = cmd->argv[1]; @@ -2026,6 +2036,7 @@ SILC_FSM_STATE(silc_client_command_cumode) silc_buffer_free(auth); silc_free(nickname); silc_client_list_free(client, conn, clients); + silc_client_unref_channel(client, conn, channel); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -2035,6 +2046,7 @@ SILC_FSM_STATE(silc_client_command_cumode) SILC_FSM_CONTINUE; out: + silc_client_unref_channel(client, conn, channel); silc_client_list_free(client, conn, clients); silc_free(nickname); SILC_FSM_FINISH; @@ -2049,7 +2061,7 @@ SILC_FSM_STATE(silc_client_command_kick) SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; SilcClient client = conn->client; - SilcChannelEntry channel; + SilcChannelEntry channel = NULL; SilcBuffer idp, idp2; SilcClientEntry target; SilcDList clients = NULL; @@ -2116,6 +2128,7 @@ SILC_FSM_STATE(silc_client_command_kick) silc_buffer_free(idp2); silc_free(nickname); silc_client_list_free(client, conn, clients); + silc_client_unref_channel(client, conn, channel); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -2125,6 +2138,7 @@ SILC_FSM_STATE(silc_client_command_kick) SILC_FSM_CONTINUE; out: + silc_client_unref_channel(client, conn, channel); silc_free(nickname); SILC_FSM_FINISH; } @@ -2262,6 +2276,7 @@ SILC_FSM_STATE(silc_client_command_ban) { SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; + SilcClient client = conn->client; SilcChannelEntry channel; SilcBuffer chidp, args = NULL; char *name, *ban = NULL; @@ -2283,6 +2298,7 @@ SILC_FSM_STATE(silc_client_command_ban) } channel = conn->current_channel; + silc_client_ref_channel(client, conn, channel); } else { name = cmd->argv[1]; @@ -2332,6 +2348,7 @@ SILC_FSM_STATE(silc_client_command_ban) silc_buffer_free(chidp); silc_buffer_free(args); + silc_client_unref_channel(client, conn, channel); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -2446,6 +2463,7 @@ SILC_FSM_STATE(silc_client_command_leave) { SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; + SilcClient client = conn->client; SilcChannelEntry channel; SilcBuffer idp; char *name; @@ -2488,6 +2506,8 @@ SILC_FSM_STATE(silc_client_command_leave) if (conn->current_channel == channel) conn->current_channel = NULL; + silc_client_unref_channel(client, conn, channel); + /** Wait for command reply */ silc_fsm_next(fsm, silc_client_command_reply_wait); SILC_FSM_CONTINUE; diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index cf68fddd..c1c7b190 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2006 Pekka Riikonen + Copyright (C) 1997 - 2007 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 @@ -233,6 +233,8 @@ SILC_FSM_STATE(silc_client_command_reply_timeout) if (conn->internal->disconnected) { SILC_LOG_DEBUG(("Command %s canceled", silc_get_command_name(cmd->cmd))); silc_list_del(conn->internal->pending_commands, cmd); + if (!cmd->called) + ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT); SILC_FSM_FINISH; } @@ -922,7 +924,7 @@ SILC_FSM_STATE(silc_client_command_reply_kill) /* Notify application */ silc_client_command_callback(cmd, client_entry); - /* Remove the client from all channels and free it */ + /* Remove the client */ if (client_entry) { silc_client_remove_from_channels(client, conn, client_entry); silc_client_del_client(client, conn, client_entry); @@ -1814,7 +1816,7 @@ SILC_FSM_STATE(silc_client_command_reply_users) SilcUInt16 idp_len, mode; SilcHashTableList htl; SilcBufferStruct client_id_list, client_mode_list; - SilcChannelEntry channel; + SilcChannelEntry channel = NULL; SilcClientEntry client_entry; SilcID id; int i; @@ -1858,6 +1860,7 @@ SILC_FSM_STATE(silc_client_command_reply_users) /* Resolve users we do not know about */ if (!cmd->resolved) { cmd->resolved = TRUE; + silc_client_unref_channel(client, conn, channel); SILC_FSM_CALL(silc_client_get_clients_by_list( client, conn, list_count, &client_id_list, silc_client_command_reply_users_resolved, cmd)); @@ -1903,6 +1906,7 @@ SILC_FSM_STATE(silc_client_command_reply_users) silc_hash_table_list_reset(&htl); out: + silc_client_unref_channel(client, conn, channel); silc_fsm_next(fsm, silc_client_command_reply_processed); SILC_FSM_CONTINUE; } diff --git a/lib/silcclient/silcclient.h b/lib/silcclient/silcclient.h index 69083194..659301fc 100644 --- a/lib/silcclient/silcclient.h +++ b/lib/silcclient/silcclient.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2000 - 2006 Pekka Riikonen + Copyright (C) 2000 - 2007 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 @@ -427,18 +427,23 @@ typedef void (*SilcVerifyPublicKey)(SilcBool success, void *context); * * DESCRIPTION * - * Authentication method resolving callback. This is called by the - * application to return the resolved authentication method. The client + * Authentication data resolving callback. This is called by the + * application to return the resolved authentication data. The client * library has called the get_auth_method client operation and given - * this function pointer as argument. The `success' will indicate whether - * the authentication method could be resolved. The `auth_meth' is the - * resolved authentication method. The `auth_data' and the `auth_data_len' + * this function pointer as argument. The `auth_meth' is the selected + * authentication method. The `auth_data' and the `auth_data_len' * are the resolved authentication data. The `context' is the libary's * context sent to the get_auth_method client operation. * + * If the `auth_method' is SILC_AUTH_PASSWORD then `auth' and `auth_len' + * is the passphrase and its length. If it is SILC_AUTH_PUBLIC_KEY the + * `auth' must be NULL. The library will use the private key given as + * argument to silc_client_connect_to_server, silc_client_connect_to_client + * or silc_client_key_exchange. If it is SILC_AUTH_NONE, both `auth' and + * `auth_len' are ignored. + * ***/ -typedef void (*SilcGetAuthMeth)(SilcBool success, - SilcAuthMethod auth_meth, +typedef void (*SilcGetAuthMeth)(SilcAuthMethod auth_meth, void *auth, SilcUInt32 auth_len, void *context); @@ -561,19 +566,26 @@ typedef struct { SilcStatus error, va_list ap); /* Find authentication method and authentication data by hostname and - port. The hostname may be IP address as well. When the authentication - method has been resolved the `completion' callback with the found - authentication method and authentication data is called. The `conn' - may be NULL. */ + port. The hostname may be IP address as well. The `auth_method' is + the authentication method the remote connection requires. It is + however possible that remote accepts also some other authentication + method. Application should use the method that may have been + configured for this connection. If none has been configured it should + use the required `auth_method'. If the `auth_method' is + SILC_AUTH_NONE, server does not require any authentication or the + required authentication method is not known. The `completion' + callback must be called to deliver the chosen authentication method + and data. The `conn' may be NULL. */ void (*get_auth_method)(SilcClient client, SilcClientConnection conn, char *hostname, SilcUInt16 port, + SilcAuthMethod auth_method, SilcGetAuthMeth completion, void *context); /* Verifies received public key. The `conn_type' indicates which entity - (server, client etc.) has sent the public key. If user decides to trust - the application may save the key as trusted public key for later - use. The `completion' must be called after the public key has been - verified. */ + (server or client) has sent the public key. If user decides to trust + the key the application may save the key as trusted public key for + later use. The `completion' must be called after the public key has + been verified. */ void (*verify_public_key)(SilcClient client, SilcClientConnection conn, SilcConnectionType conn_type, SilcPublicKey public_key, @@ -632,12 +644,6 @@ typedef struct { in the callbacks to protect application specific data. */ SilcBool threads; - /* Connection authentication method request timeout. If server does not - reply back the current authentication method when we've requested it - in this time interval we'll assume the reply will not come at all. - If set to zero, the default value (2 seconds) will be used. */ - unsigned int connauth_request_secs; - /* Nickname format string. This can be used to order the client library to save the nicknames in the library in a certain format. Since nicknames are not unique in SILC it is possible to have multiple same @@ -929,6 +935,7 @@ typedef struct { * silc_client_connect_to_server(SilcClient client, * SilcClientConnectionParams *params, * SilcPublicKey public_key, + * SilcPrivateKey private_key, * char *remote_host, int port, * SilcClientConnectCallback callback, * void *context); @@ -971,6 +978,7 @@ silc_client_connect_to_server(SilcClient client, * silc_client_connect_to_client(SilcClient client, * SilcClientConnectionParams *params, * SilcPublicKey public_key, + * SilcPrivateKey private_key, * char *remote_host, int port, * SilcClientConnectCallback callback, * void *context); @@ -1632,10 +1640,10 @@ SilcBool silc_client_del_channel_private_key(SilcClient client, * DESCRIPTION * * Returns list of private keys associated to the `channel'. The caller - * must free the returned list. The pointers in the list may be - * used to delete the specific key by giving the pointer as argument to the - * function silc_client_del_channel_private_key. Each entry in the list - * is SilcChannelPrivateKey. + * must free the returned list with silc_dlist_uninit. The pointers in + * the list may be used to delete the specific key by giving the pointer + * as argument to the function silc_client_del_channel_private_key. Each + * entry in the list is SilcChannelPrivateKey. * ***/ SilcDList silc_client_list_channel_private_keys(SilcClient client, @@ -1854,56 +1862,6 @@ void silc_client_set_away_message(SilcClient client, SilcClientConnection conn, char *message); -/****f* silcclient/SilcClientAPI/SilcConnectionAuthRequest - * - * SYNOPSIS - * - * typedef void (*SilcConnectionAuthRequest)(SilcClient client, - * SilcClientConnection conn, - * SilcAuthMethod auth_meth, - * void *context); - * - * DESCRIPTION - * - * Connection authentication method request callback. This is called - * by the client library after it has received the authentication method - * that the application requested by calling the function - * silc_client_request_authentication_method. - * - ***/ -typedef void (*SilcConnectionAuthRequest)(SilcClient client, - SilcClientConnection conn, - SilcAuthMethod auth_meth, - void *context); - -/****f* silcclient/SilcClientAPI/silc_client_request_authentication_method - * - * SYNOPSIS - * - * void - * silc_client_request_authentication_method(SilcClient client, - * SilcClientConnection conn, - * SilcConnectionAuthRequest - * callback, - * void *context); - * - * DESCRIPTION - * - * This function can be used to request the current authentication method - * from the server. This may be called when connecting to the server - * and the client library requests the authentication data from the - * application. If the application does not know the current authentication - * method it can request it from the server using this function. - * The `callback' with `context' will be called after the server has - * replied back with the current authentication method. - * - ***/ -void -silc_client_request_authentication_method(SilcClient client, - SilcClientConnection conn, - SilcConnectionAuthRequest callback, - void *context); - /****d* silcclient/SilcClientAPI/SilcClientMonitorStatus * * NAME