From 0fd8b4134368dc548b9de997cd84f1cbc076c8f7 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Tue, 4 Sep 2001 11:52:09 +0000 Subject: [PATCH] updates. --- CHANGES | 47 +++++ TODO | 12 -- .../irssi/src/fe-common/core/fe-common-core.c | 2 + apps/irssi/src/silc/core/client_ops.c | 69 +++++-- apps/irssi/src/silc/core/client_ops.h | 8 +- apps/irssi/src/silc/core/clientutil.c | 4 + apps/silcd/packet_receive.c | 9 +- apps/silcd/protocol.c | 23 +-- apps/silcd/server.c | 24 ++- apps/silcd/serverconfig.c | 8 +- apps/silcd/serverconfig.h | 8 +- configure.in.pre | 1 - doc/draft-riikonen-silc-ke-auth-04.nroff | 20 +- doc/example_silcd.conf | 2 +- lib/silcclient/client.c | 186 ++++++++++++++++-- lib/silcclient/client.h | 15 ++ lib/silcclient/client_keyagr.c | 2 +- lib/silcclient/protocol.c | 44 ++--- lib/silcclient/silcapi.h | 99 +++++++++- lib/silccrypt/rsa.c | 24 +-- lib/silcmath/silcprimegen.c | 19 +- lib/silcutil/silcmemory.c | 21 -- lib/silcutil/silcnet.h | 21 +- lib/silcutil/unix/silcunixnet.c | 62 +++++- lib/silcutil/win32/silcwin32net.c | 6 +- prepare | 4 +- 26 files changed, 547 insertions(+), 193 deletions(-) diff --git a/CHANGES b/CHANGES index 1f3ac680..839d6424 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,40 @@ +Tue Sep 4 12:39:17 EEST 2001 Pekka Riikonen + + * Changed the get_auth_methdod client operation to be asynchronous. + It can be async if the application resolves the authentication + method from the server during the negotiation. Added new + SilcGetAuthMeth completion callback that the application will + call after resolving the authentication method. + + Added function silc_client_request_authentication_method that + the application can use to resolve the authentication method + from the server. Added also SilcConnectionAuthRequest callback + that the library will call after the server has replied. The + application can call this function if it does not know the + current authentication method. + + Affected files are lib/silcclient/client.c and + lib/silcclient/silcapi.h. + + * The Irssi SILC client now automatically resolves the authentication + method incase any configuration information is not present (and + currently there never is). The affected file is + irssi/src/silc/core/client_ops.c. + + * Fixed public key authentication from the client library. + Affected file lib/silcclient/protocol.c. Changed also the + protocol specification about the public key authentication in + the connection authentication protocol. The actual data to be + signed is now computed with a hash function before signing. + + * Fixed the public key authentication from the server as well. + Affected file silcd/protocol.c. + + * Removed the mlock()'s from the memory allocation routines. + Affected file lib/silcutil/silcmemory.c. The ./configure does + not check anymore for the mlock(). Affected file is + configure.in.pre. + Mon Sep 3 20:09:59 EEST 2001 Pekka Riikonen * Fixed the lib/silcmath/mpi/mpi.h to always use 32-bit data @@ -8,6 +45,16 @@ Mon Sep 3 20:09:59 EEST 2001 Pekka Riikonen * Do not check for threads at all on BSD systems. Affected file configure.in.pre. + * Removed -n and -h options from the Irssi SILC Client since + they are not used in silc. + + * Fixed the prime generation to assure that the first digit + of the generated random number is not zero since our conversion + routines does not like number strings that starts with zero + digit. If zero digit is seen the random number is regenerated. + This caused some corrupted RSA keys when the zero first digit + was met. Affected file lib/silcmath/silcprimegen.c. + Sun Sep 2 17:17:24 EEST 2001 Pekka Riikonen * Fixed WIN32 configuration in the ./configure script. diff --git a/TODO b/TODO index a2bdc1cd..ce43e4d3 100644 --- a/TODO +++ b/TODO @@ -1,15 +1,6 @@ TODO/bugs in Irssi SILC client ============================== - o If the configuration for a server connection does not exist then - resolve the authentication method always from the server. Otherwise - password and/or public key auth with server does not work since it - now assumes that config exists or NONE is used. - - o -n and -c options does not work. - - o Switching servers while on channel is supposed to crash the client? - o Add local command to switch the channel's private key when channel has several private keys. Currently sending channel messages with many keys is not possible because changing the key is not possible by the @@ -88,9 +79,6 @@ TODO/bugs In SILC Libraries o Some ./prepare problems with latest autoconf and automake. - o Remove the mlock() stuff from the lib/silcutil/silcmemory.c, they - are redundant. - o Compression routines are missing. The protocol supports packet compression thus it must be implemented. SILC Comp API must be defined. zlib package is already included into the lib dir (in CVS, diff --git a/apps/irssi/src/fe-common/core/fe-common-core.c b/apps/irssi/src/fe-common/core/fe-common-core.c index 8cfb3a85..24836905 100644 --- a/apps/irssi/src/fe-common/core/fe-common-core.c +++ b/apps/irssi/src/fe-common/core/fe-common-core.c @@ -123,8 +123,10 @@ void fe_common_core_init(void) { "password", 'w', POPT_ARG_STRING, &autocon_password, 0, "Autoconnect password", "SERVER" }, { "port", 'p', POPT_ARG_INT, &autocon_port, 0, "Autoconnect port", "PORT" }, { "noconnect", '!', POPT_ARG_NONE, &no_autoconnect, 0, "Disable autoconnecting", NULL }, + /* { "nick", 'n', POPT_ARG_STRING, &cmdline_nick, 0, "Specify nick to use", NULL }, { "hostname", 'h', POPT_ARG_STRING, &cmdline_hostname, 0, "Specify host name to use", NULL }, + */ { NULL, '\0', 0, NULL } }; diff --git a/apps/irssi/src/silc/core/client_ops.c b/apps/irssi/src/silc/core/client_ops.c index 6da1a80b..9247a3c4 100644 --- a/apps/irssi/src/silc/core/client_ops.c +++ b/apps/irssi/src/silc/core/client_ops.c @@ -961,7 +961,7 @@ void ask_passphrase_completion(const char *passphrase, void *context) } void silc_ask_passphrase(SilcClient client, SilcClientConnection conn, - SilcAskPassphrase completion, void *context) + SilcAskPassphrase completion, void *context) { AskPassphrase p = silc_calloc(1, sizeof(*p)); p->completion = completion; @@ -971,34 +971,69 @@ void silc_ask_passphrase(SilcClient client, SilcClientConnection conn, "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p); } +typedef struct { + SilcGetAuthMeth completion; + void *context; +} *InternalGetAuthMethod; + +/* Callback called when we've received the authentication method information + from the server after we've requested it. This will get the authentication + data from the user if needed. */ + +static void silc_get_auth_method_callback(SilcClient client, + SilcClientConnection conn, + SilcAuthMethod auth_meth, + void *context) +{ + InternalGetAuthMethod internal = (InternalGetAuthMethod)context; + + switch (auth_meth) { + case SILC_AUTH_NONE: + /* No authentication required. */ + (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context); + break; + case SILC_AUTH_PASSWORD: + /* Do not ask the passphrase from user, the library will ask it if + we do not provide it here. */ + (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context); + break; + case SILC_AUTH_PUBLIC_KEY: + /* Do not get the authentication data now, the library will generate + it using our default key, if we do not provide it here. */ + /* XXX In the future when we support multiple local keys and multiple + local certificates we will need to ask from user which one to use. */ + (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context); + break; + } + + silc_free(internal); +} + /* Find authentication method and authentication data by hostname and port. The hostname may be IP address as well. The found authentication method and authentication data is returned to `auth_meth', `auth_data' and `auth_data_len'. The function returns TRUE if authentication method is found and FALSE if not. `conn' may be NULL. */ -int silc_get_auth_method(SilcClient client, SilcClientConnection conn, - char *hostname, uint16 port, - SilcProtocolAuthMeth *auth_meth, - unsigned char **auth_data, - uint32 *auth_data_len) +void silc_get_auth_method(SilcClient client, SilcClientConnection conn, + char *hostname, uint16 port, + SilcGetAuthMeth completion, void *context) { - bool ret = TRUE; - SILC_SERVER_REC *server = conn ? conn->context : NULL; + InternalGetAuthMethod internal; /* XXX must resolve from configuration whether this connection has any specific authentication data */ - *auth_meth = SILC_AUTH_NONE; - *auth_data = NULL; - *auth_data_len = 0; - - if (ret == FALSE) { - printformat_module("fe-common/silc", server, NULL, - MSGLEVEL_MODES, SILCTXT_AUTH_METH_UNRESOLVED); - } + /* If we do not have this connection configured by the user in a + configuration file then resolve the authentication method from the + server for this session. */ + internal = silc_calloc(1, sizeof(*internal)); + internal->completion = completion; + internal->context = context; - return ret; + silc_client_request_authentication_method(client, conn, + silc_get_auth_method_callback, + internal); } /* Notifies application that failure packet was received. This is called diff --git a/apps/irssi/src/silc/core/client_ops.h b/apps/irssi/src/silc/core/client_ops.h index 620e72f8..38ccf656 100644 --- a/apps/irssi/src/silc/core/client_ops.h +++ b/apps/irssi/src/silc/core/client_ops.h @@ -47,11 +47,9 @@ void silc_verify_public_key(SilcClient client, SilcClientConnection conn, SilcSocketType conn_type, unsigned char *pk, uint32 pk_len, SilcSKEPKType pk_type, SilcVerifyPublicKey completion, void *context); -int silc_get_auth_method(SilcClient client, SilcClientConnection conn, - char *hostname, uint16 port, - SilcProtocolAuthMeth *auth_meth, - unsigned char **auth_data, - uint32 *auth_data_len); +void silc_get_auth_method(SilcClient client, SilcClientConnection conn, + char *hostname, uint16 port, + SilcGetAuthMeth completion, void *context); void silc_failure(SilcClient client, SilcClientConnection conn, SilcProtocol protocol, void *failure); int silc_key_agreement(SilcClient client, SilcClientConnection conn, diff --git a/apps/irssi/src/silc/core/clientutil.c b/apps/irssi/src/silc/core/clientutil.c index 46396967..6b19cc6f 100644 --- a/apps/irssi/src/silc/core/clientutil.c +++ b/apps/irssi/src/silc/core/clientutil.c @@ -537,6 +537,10 @@ int silc_client_load_keys(SilcClient client) SILC_PKCS_FILE_BIN) == FALSE) return FALSE; + silc_pkcs_alloc(client->public_key->name, &client->pkcs); + silc_pkcs_public_key_set(client->pkcs, client->public_key); + silc_pkcs_private_key_set(client->pkcs, client->private_key); + return TRUE; } diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index ba3c9cd7..d88d0546 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -2135,7 +2135,7 @@ void silc_server_key_agreement(SilcServer server, actually be received at anytime but usually it is used only during the connection authentication phase. Now, protocol says that this packet can come from client or server, however, we support only this coming - from client and expect that server's always knows what authentication + from client and expect that server always knows what authentication method to use. */ void silc_server_connection_auth_request(SilcServer server, @@ -2144,7 +2144,7 @@ void silc_server_connection_auth_request(SilcServer server, { SilcServerConfigSectionClientConnection *client = NULL; uint16 conn_type; - int ret; + int ret, port; SilcAuthMethod auth_meth; SILC_LOG_DEBUG(("Start")); @@ -2165,13 +2165,14 @@ void silc_server_connection_auth_request(SilcServer server, /* Get the authentication method for the client */ auth_meth = SILC_AUTH_NONE; + port = server->sockets[server->sock]->port; /* Listenning port */ client = silc_server_config_find_client_conn(server->config, sock->ip, - sock->port); + port); if (!client) client = silc_server_config_find_client_conn(server->config, sock->hostname, - sock->port); + port); if (client) auth_meth = client->auth_meth; diff --git a/apps/silcd/protocol.c b/apps/silcd/protocol.c index 543687a5..53b31d97 100644 --- a/apps/silcd/protocol.c +++ b/apps/silcd/protocol.c @@ -712,7 +712,8 @@ silc_server_public_key_authentication(SilcServer server, SILC_STR_END); /* Verify signature */ - if (silc_pkcs_verify(pkcs, sign, sign_len, auth->data, auth->len)) { + if (silc_pkcs_verify_with_hash(pkcs, ske->prop->hash, sign, sign_len, + auth->data, auth->len)) { silc_pkcs_free(pkcs); silc_buffer_free(auth); return TRUE; @@ -725,7 +726,6 @@ silc_server_public_key_authentication(SilcServer server, static int silc_server_get_public_key_auth(SilcServer server, - SilcPublicKey pub_key, unsigned char *auth_data, uint32 *auth_data_len, SilcSKE ske) @@ -734,14 +734,7 @@ silc_server_get_public_key_auth(SilcServer server, SilcPKCS pkcs; SilcBuffer auth; - if (!pub_key) - return FALSE; - - silc_pkcs_alloc(pub_key->name, &pkcs); - if (!silc_pkcs_public_key_set(pkcs, pub_key)) { - silc_pkcs_free(pkcs); - return FALSE; - } + pkcs = server->pkcs; /* Make the authentication data. Protocol says it is HASH plus KE Start Payload. */ @@ -754,13 +747,12 @@ silc_server_get_public_key_auth(SilcServer server, ske->start_payload_copy->len), SILC_STR_END); - if (silc_pkcs_sign(pkcs, auth->data, auth->len, auth_data, auth_data_len)) { - silc_pkcs_free(pkcs); + if (silc_pkcs_sign_with_hash(pkcs, ske->prop->hash, auth->data, + auth->len, auth_data, auth_data_len)) { silc_buffer_free(auth); return TRUE; } - silc_pkcs_free(pkcs); silc_buffer_free(auth); return FALSE; } @@ -1081,8 +1073,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) unsigned char sign[1024]; /* Public key authentication */ - silc_server_get_public_key_auth(server, ctx->auth_data, - sign, &auth_data_len, + silc_server_get_public_key_auth(server, sign, &auth_data_len, ctx->ske); auth_data = silc_calloc(auth_data_len, sizeof(*auth_data)); memcpy(auth_data, sign, auth_data_len); @@ -1545,7 +1536,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) if (ctx->packet->type != SILC_PACKET_REKEY_DONE) { /* Error in protocol */ protocol->state = SILC_PROTOCOL_STATE_ERROR; - silc_protocol_execute(protocol, server->schedule, 0, 0); + silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } diff --git a/apps/silcd/server.c b/apps/silcd/server.c index b65af7d6..9047fa07 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -84,6 +84,9 @@ void silc_server_free(SilcServer server) if (server->rng) silc_rng_free(server->rng); + if (server->pkcs) + silc_pkcs_free(server->pkcs); + #ifdef SILC_SIM while ((sim = silc_dlist_get(server->sim)) != SILC_LIST_END) { silc_dlist_del(server->sim, sim); @@ -115,6 +118,7 @@ int silc_server_init(SilcServer server) SilcServerID *id; SilcServerEntry id_entry; SilcIDListPurge purge; + SilcServerConfigSectionListenPort *listen; SILC_LOG_DEBUG(("Initializing server")); assert(server); @@ -166,22 +170,27 @@ int silc_server_init(SilcServer server) /* Initialize none cipher */ silc_cipher_alloc("none", &server->none_cipher); - /* Create a listening server. Note that our server can listen on - multiple ports. All listeners are created here and now. */ - /* XXX Still check this whether to use server_info or listen_port. */ + /* Allocate PKCS context for local public and private keys */ + silc_pkcs_alloc(server->public_key->name, &server->pkcs); + silc_pkcs_public_key_set(server->pkcs, server->public_key); + silc_pkcs_private_key_set(server->pkcs, server->private_key); + + /* Create a listening server. Note that our server can listen on multiple + ports. All listeners are created here and now. */ sock_count = 0; - while(server->config->listen_port) { + listen = server->config->listen_port; + while(listen) { int tmp; tmp = silc_net_create_server(server->config->listen_port->port, - server->config->listen_port->host); + server->config->listen_port->listener_ip); if (tmp < 0) goto err0; sock = silc_realloc(sock, (sizeof(int *) * (sock_count + 1))); sock[sock_count] = tmp; - server->config->listen_port = server->config->listen_port->next; sock_count++; + listen = listen->next; } /* Initialize ID caches */ @@ -522,7 +531,8 @@ SILC_TASK_CALLBACK(silc_server_connect_router) sconn->remote_host, sconn->remote_port)); /* Connect to remote host */ - sock = silc_net_create_connection(sconn->remote_port, + sock = silc_net_create_connection(server->config->listen_port->local_ip, + sconn->remote_port, sconn->remote_host); if (sock < 0) { SILC_LOG_ERROR(("Could not connect to router")); diff --git a/apps/silcd/serverconfig.c b/apps/silcd/serverconfig.c index 894d4fd3..8b1f5161 100644 --- a/apps/silcd/serverconfig.c +++ b/apps/silcd/serverconfig.c @@ -557,13 +557,13 @@ int silc_server_config_parse_lines(SilcServerConfig config, SILC_SERVER_CONFIG_LIST_ALLOC(config->listen_port); - /* Get host */ - ret = silc_config_get_token(line, &config->listen_port->host); + /* Get local IP */ + ret = silc_config_get_token(line, &config->listen_port->local_ip); if (ret < 0) break; - /* Get remote IP */ - ret = silc_config_get_token(line, &config->listen_port->remote_ip); + /* Get listener IP */ + ret = silc_config_get_token(line, &config->listen_port->listener_ip); if (ret < 0) break; diff --git a/apps/silcd/serverconfig.h b/apps/silcd/serverconfig.h index f6612d4d..c9e1d2a6 100644 --- a/apps/silcd/serverconfig.h +++ b/apps/silcd/serverconfig.h @@ -56,8 +56,8 @@ typedef struct { /* Holds all the ports the server is listenning on */ typedef struct SilcServerConfigSectionListenPortStruct { - char *host; - char *remote_ip; + char *local_ip; + char *listener_ip; uint16 port; struct SilcServerConfigSectionListenPortStruct *next; struct SilcServerConfigSectionListenPortStruct *prev; @@ -66,8 +66,8 @@ typedef struct SilcServerConfigSectionListenPortStruct { /* Holds server's execution identity, or the user and group which to change from root when server starts */ typedef struct { - char *user; - char *group; + char *user; + char *group; } SilcServerConfigSectionIdentity; /* Holds all the configured log files. */ diff --git a/configure.in.pre b/configure.in.pre index 7ba342c8..e1312731 100644 --- a/configure.in.pre +++ b/configure.in.pre @@ -291,7 +291,6 @@ AC_CHECK_FUNCS(gethostname gethostbyaddr getservbyname getservbyport) AC_CHECK_FUNCS(select listen bind shutdown close connect) AC_CHECK_FUNCS(fcntl setsockopt) AC_CHECK_FUNCS(getopt_long time) -AC_CHECK_FUNCS(mlock munlock) AC_CHECK_FUNCS(chmod stat fstat getenv putenv strerror ctime gettimeofday) AC_CHECK_FUNCS(getpid getgid getsid getpgid getpgrp getuid) AC_CHECK_FUNCS(strchr strstr strcpy strncpy memcpy memset memmove) diff --git a/doc/draft-riikonen-silc-ke-auth-04.nroff b/doc/draft-riikonen-silc-ke-auth-04.nroff index 1ad23bdb..479ea7de 100644 --- a/doc/draft-riikonen-silc-ke-auth-04.nroff +++ b/doc/draft-riikonen-silc-ke-auth-04.nroff @@ -872,10 +872,10 @@ to have plaintext passphrase. See the section 3.2.1 Passphrase Authentication for more information. If authentication method is public key authentication the authentication -data is signature of the hash value HASH plus Key Exchange Start Payload, -established by the SILC Key Exchange protocol. This signature MUST then -be verified by the server. See the section 3.2.2 Public Key -Authentication for more information. +data is a signature of the hash value of hash HASH plus Key Exchange +Start Payload, established by the SILC Key Exchange protocol. This +signature MUST then be verified by the server. See the section 3.2.2 +Public Key Authentication for more information. The connecting client of this protocol MUST wait after successful execution of this protocol for the SILC_PACKET_NEW_ID packet where it will receive @@ -969,8 +969,16 @@ which the server has received earlier in SKE protocol. The signature is computed using the private key of the sender by signing the HASH value provided by the SKE protocol previously, and the Key Exchange Start Payload from SKE protocol that was sent to the server. -The server MUST verify the data, thus it must keep the HASH and the -Key Exchange Start Payload saved during SKE and authentication protocols. +These are concatenated and hash function is used to compute a hash value +which is then signed. + + auth_hash = hash(HASH | Key Exchange Start Payload); + signature = sign(auth_hash); + +The hash() function used to compute the value is the hash function negotiated +in the SKE protocol. The server MUST verify the data, thus it must keep +the HASH and the Key Exchange Start Payload saved during SKE and +authentication protocols. If the verified signature matches the sent signature, the authentication were successful and SILC_PACKET_SUCCESS is sent. If it failed the protocol diff --git a/doc/example_silcd.conf b/doc/example_silcd.conf index 89e7c6c6..e34d4331 100644 --- a/doc/example_silcd.conf +++ b/doc/example_silcd.conf @@ -84,7 +84,7 @@ lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:706 # # Listenning ports. # -# Format: :: +# Format: :: # [ListenPort] 10.2.1.6:10.2.1.6:706 diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index 02288635..aebaebe6 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -34,6 +34,10 @@ static void silc_client_packet_parse(SilcPacketParserContext *parser_context); static void silc_client_packet_parse_type(SilcClient client, SilcSocketConnection sock, SilcPacketContext *packet); +void silc_client_resolve_auth_method(bool success, + SilcProtocolAuthMeth auth_meth, + const unsigned char *auth_data, + uint32 auth_data_len, void *context); /* Allocates new client object. This has to be done before client may work. After calling this one must call silc_client_init to initialize @@ -59,6 +63,9 @@ SilcClient silc_client_alloc(SilcClientOperations *ops, if (!new_client->params->rekey_secs) new_client->params->rekey_secs = 3600; + if (!new_client->params->connauth_request_secs) + new_client->params->connauth_request_secs = 2; + return new_client; } @@ -247,7 +254,7 @@ silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx) /* XXX In the future we should give up this non-blocking connect all together and use threads instead. */ /* Create connection to server asynchronously */ - sock = silc_net_create_connection_async(ctx->port, ctx->host); + sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host); if (sock < 0) return -1; @@ -482,13 +489,6 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_second) proto_ctx->dest_id_type = ctx->dest_id_type; proto_ctx->dest_id = ctx->dest_id; - /* Resolve the authentication method to be used in this connection */ - if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname, - sock->port, &proto_ctx->auth_meth, - &proto_ctx->auth_data, - &proto_ctx->auth_data_len)) - proto_ctx->auth_meth = SILC_AUTH_NONE; - /* Free old protocol as it is finished now */ silc_protocol_free(protocol); if (ctx->packet) @@ -496,13 +496,46 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_second) silc_free(ctx); sock->protocol = NULL; + /* Resolve the authentication method to be used in this connection. The + completion callback is called after the application has resolved + the authentication method. */ + client->ops->get_auth_method(client, sock->user_data, sock->hostname, + sock->port, silc_client_resolve_auth_method, + proto_ctx); +} + +/* Authentication method resolving callback. Application calls this function + after we've called the client->ops->get_auth_method client operation + to resolve the authentication method. We will continue the executiong + of the protocol in this function. */ + +void silc_client_resolve_auth_method(bool success, + SilcProtocolAuthMeth auth_meth, + const unsigned char *auth_data, + uint32 auth_data_len, void *context) +{ + SilcClientConnAuthInternalContext *proto_ctx = + (SilcClientConnAuthInternalContext *)context; + SilcClient client = (SilcClient)proto_ctx->client; + + if (!success) + auth_meth = SILC_AUTH_NONE; + + proto_ctx->auth_meth = auth_meth; + + if (auth_data && auth_data_len) { + proto_ctx->auth_data = silc_calloc(auth_data_len, sizeof(*auth_data)); + memcpy(proto_ctx->auth_data, auth_data, auth_data_len); + proto_ctx->auth_data_len = auth_data_len; + } + /* Allocate the authenteication protocol and execute it. */ silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH, - &sock->protocol, (void *)proto_ctx, + &proto_ctx->sock->protocol, (void *)proto_ctx, silc_client_connect_to_server_final); /* Execute the protocol */ - silc_protocol_execute(sock->protocol, client->schedule, 0, 0); + silc_protocol_execute(proto_ctx->sock->protocol, client->schedule, 0, 0); } /* Finalizes the connection to the remote SILC server. This is called @@ -571,9 +604,9 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final) conn->rekey->timeout = client->params->rekey_secs; conn->rekey->context = (void *)client; silc_schedule_task_add(client->schedule, conn->sock->sock, - silc_client_rekey_callback, - (void *)conn->sock, conn->rekey->timeout, 0, - SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + silc_client_rekey_callback, + (void *)conn->sock, conn->rekey->timeout, 0, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); silc_protocol_free(protocol); if (ctx->auth_data) @@ -788,10 +821,10 @@ void silc_client_packet_parse(SilcPacketParserContext *parser_context) /* Parse the packet */ silc_schedule_task_add(client->schedule, parser_context->sock->sock, - silc_client_packet_parse_real, - (void *)parser_context, 0, 1, - SILC_TASK_TIMEOUT, - SILC_TASK_PRI_NORMAL); + silc_client_packet_parse_real, + (void *)parser_context, 0, 1, + SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); } /* Parses the packet type and calls what ever routines the packet type @@ -1045,6 +1078,15 @@ void silc_client_packet_parse_type(SilcClient client, } break; + case SILC_PACKET_CONNECTION_AUTH_REQUEST: + /* + * Reveived reply to our connection authentication method request + * packet. This is used to resolve the authentication method for the + * current session from the server if the client does not know it. + */ + silc_client_connection_auth_request(client, sock, packet); + break; + default: SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type)); break; @@ -1515,9 +1557,9 @@ SILC_TASK_CALLBACK(silc_client_rekey_callback) /* Re-register re-key timeout */ silc_schedule_task_add(client->schedule, sock->sock, - silc_client_rekey_callback, - context, conn->rekey->timeout, 0, - SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + silc_client_rekey_callback, + context, conn->rekey->timeout, 0, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); } /* The final callback for the REKEY protocol. This will actually take the @@ -1558,3 +1600,107 @@ SILC_TASK_CALLBACK(silc_client_rekey_final) silc_socket_free(ctx->sock); silc_free(ctx); } + +/* 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, + SilcSocketConnection sock, + SilcPacketContext *packet) +{ + SilcClientConnection conn = (SilcClientConnection)sock->user_data; + uint16 conn_type, auth_meth; + int ret; + + /* If we haven't send our request then ignore this one. */ + if (!conn->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->connauth->callback) + (*conn->connauth->callback)(client, conn, auth_meth, + conn->connauth->context); + + silc_schedule_task_del(client->schedule, conn->connauth->timeout); + + silc_free(conn->connauth); + conn->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->connauth) + return; + + /* Call the request callback to notify application */ + if (conn->connauth->callback) + (*conn->connauth->callback)(client, conn, SILC_AUTH_NONE, + conn->connauth->context); + + silc_free(conn->connauth); + conn->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; + + connauth = silc_calloc(1, sizeof(*connauth)); + connauth->callback = callback; + connauth->context = context; + + if (conn->connauth) + silc_free(conn->connauth); + + conn->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->params->connauth_request_secs, 0, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); +} diff --git a/lib/silcclient/client.h b/lib/silcclient/client.h index f78135f5..c0e33228 100644 --- a/lib/silcclient/client.h +++ b/lib/silcclient/client.h @@ -44,6 +44,15 @@ typedef struct { void *context; } *SilcClientRekey; +/* 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; + /* Connection structure used in client to associate all the important connection specific data to this structure. */ struct SilcClientConnectionStruct { @@ -121,6 +130,9 @@ struct SilcClientConnectionStruct { /* Re-key context */ SilcClientRekey rekey; + /* Authentication request context. */ + SilcClientConnAuthRequest connauth; + /* Pointer back to the SilcClient. This object is passed to the application and the actual client object is accesible through this pointer. */ SilcClient client; @@ -295,5 +307,8 @@ void silc_client_notify_by_server(SilcClient client, void silc_client_private_message(SilcClient client, SilcSocketConnection sock, SilcPacketContext *packet); +void silc_client_connection_auth_request(SilcClient client, + SilcSocketConnection sock, + SilcPacketContext *packet); #endif diff --git a/lib/silcclient/client_keyagr.c b/lib/silcclient/client_keyagr.c index 78337cfe..b23f6550 100644 --- a/lib/silcclient/client_keyagr.c +++ b/lib/silcclient/client_keyagr.c @@ -366,7 +366,7 @@ silc_client_connect_to_client_internal(SilcClientInternalConnectContext *ctx) int sock; /* Create connection to server asynchronously */ - sock = silc_net_create_connection_async(ctx->port, ctx->host); + sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host); if (sock < 0) return -1; diff --git a/lib/silcclient/protocol.c b/lib/silcclient/protocol.c index 5ba28db6..8460ad8f 100644 --- a/lib/silcclient/protocol.c +++ b/lib/silcclient/protocol.c @@ -544,7 +544,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange) static int silc_client_get_public_key_auth(SilcClient client, - char *filepath, + SilcClientConnection conn, unsigned char *auth_data, uint32 *auth_data_len, SilcSKE ske) @@ -552,18 +552,9 @@ silc_client_get_public_key_auth(SilcClient client, int len; SilcPKCS pkcs; SilcBuffer auth; - SilcPublicKey pub_key; - if (!silc_pkcs_load_public_key(filepath,&pub_key, SILC_PKCS_FILE_PEM)) - if (!silc_pkcs_load_public_key(filepath, &pub_key, SILC_PKCS_FILE_BIN)) - return FALSE; - - silc_pkcs_alloc(pub_key->name, &pkcs); - if (!silc_pkcs_public_key_set(pkcs, pub_key)) { - silc_pkcs_free(pkcs); - silc_pkcs_public_key_free(pub_key); - return FALSE; - } + /* Use our default key */ + pkcs = client->pkcs; /* Make the authentication data. Protocol says it is HASH plus KE Start Payload. */ @@ -576,16 +567,13 @@ silc_client_get_public_key_auth(SilcClient client, ske->start_payload_copy->len), SILC_STR_END); - if (silc_pkcs_sign(pkcs, auth->data, auth->len, auth_data, auth_data_len)) { - silc_pkcs_free(pkcs); + if (silc_pkcs_sign_with_hash(pkcs, ske->prop->hash, auth->data, + auth->len, auth_data, auth_data_len)) { silc_buffer_free(auth); - silc_pkcs_public_key_free(pub_key); return TRUE; } - silc_pkcs_free(pkcs); silc_buffer_free(auth); - silc_pkcs_public_key_free(pub_key); return FALSE; } @@ -619,11 +607,6 @@ silc_client_conn_auth_continue(unsigned char *auth_data, SILC_PACKET_CONNECTION_AUTH, NULL, 0, NULL, NULL, packet->data, packet->len, TRUE); - - if (auth_data) { - memset(auth_data, 0, auth_data_len); - silc_free(auth_data); - } silc_buffer_free(packet); /* Next state is end of protocol */ @@ -652,6 +635,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth) */ unsigned char *auth_data = NULL; uint32 auth_data_len = 0; + unsigned char sign[1024]; switch(ctx->auth_meth) { case SILC_AUTH_NONE: @@ -676,17 +660,17 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth) break; case SILC_AUTH_PUBLIC_KEY: - { - unsigned char sign[1024]; - + if (!ctx->auth_data) { /* Public key authentication */ - silc_client_get_public_key_auth(client, ctx->auth_data, - sign, &auth_data_len, + silc_client_get_public_key_auth(client, conn, sign, &auth_data_len, ctx->ske); - auth_data = silc_calloc(auth_data_len, sizeof(*auth_data)); - memcpy(auth_data, sign, auth_data_len); - break; + auth_data = sign; + } else { + auth_data = ctx->auth_data; + auth_data_len = ctx->auth_data_len; } + + break; } silc_client_conn_auth_continue(auth_data, diff --git a/lib/silcclient/silcapi.h b/lib/silcclient/silcapi.h index 1dec749b..157d658a 100644 --- a/lib/silcclient/silcapi.h +++ b/lib/silcclient/silcapi.h @@ -166,6 +166,32 @@ typedef void (*SilcAskPassphrase)(unsigned char *passphrase, ***/ typedef void (*SilcVerifyPublicKey)(bool success, void *context); +/****f* silcclient/SilcClientAPI/SilcGetAuthMeth + * + * SYNOPSIS + * + * typedef void (*SilcGetAuthMeth)(bool success, + * SilcProtocolAuthMeth auth_meth, + * const unsigned char *auth_data, + * uint32 auth_data_len, void *context); + * + * DESCRIPTION + * + * Authentication method resolving callback. This is called by the + * application to return the resolved authentication method. 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' + * are the resolved authentication data. The `context' is the libary's + * context sent to the get_auth_method client operation. + * + ***/ +typedef void (*SilcGetAuthMeth)(bool success, + SilcProtocolAuthMeth auth_meth, + const unsigned char *auth_data, + uint32 auth_data_len, void *context); + /****d* silcclient/SilcClientAPI/SilcClientMessageType * * NAME @@ -277,15 +303,13 @@ typedef struct { void (*disconnect)(SilcClient client, SilcClientConnection conn); /* Find authentication method and authentication data by hostname and - port. The hostname may be IP address as well. The found authentication - method and authentication data is returned to `auth_meth', `auth_data' - and `auth_data_len'. The function returns TRUE if authentication method - is found and FALSE if not. `conn' may be NULL. */ - int (*get_auth_method)(SilcClient client, SilcClientConnection conn, - char *hostname, uint16 port, - SilcProtocolAuthMeth *auth_meth, - unsigned char **auth_data, - uint32 *auth_data_len); + 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. */ + void (*get_auth_method)(SilcClient client, SilcClientConnection conn, + char *hostname, uint16 port, + 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 @@ -351,6 +375,12 @@ typedef struct { /* Rekey timeout in seconds. The client will perform rekey in this time interval. If set to zero, the default value will be used. */ unsigned int rekey_secs; + + /* 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; } SilcClientParams; /***/ @@ -1600,4 +1630,55 @@ 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); + #endif diff --git a/lib/silccrypt/rsa.c b/lib/silccrypt/rsa.c index 79d88cd2..66aea06a 100644 --- a/lib/silccrypt/rsa.c +++ b/lib/silccrypt/rsa.c @@ -77,6 +77,7 @@ SILC_PKCS_API_INIT(rsa) { uint32 prime_bits = keylen / 2; SilcMPInt p, q; + bool found = FALSE; printf("Generating RSA Public and Private keys, might take a while...\n"); @@ -84,16 +85,17 @@ SILC_PKCS_API_INIT(rsa) silc_mp_init(&q); /* Find p and q */ - retry_primes: - printf("Finding p: "); - silc_math_gen_prime(&p, prime_bits, TRUE); - - printf("\nFinding q: "); - silc_math_gen_prime(&q, prime_bits, TRUE); - - if ((silc_mp_cmp(&p, &q)) == 0) { - printf("\nFound equal primes, not good, retrying...\n"); - goto retry_primes; + while (!found) { + printf("Finding p: "); + silc_math_gen_prime(&p, prime_bits, TRUE); + + printf("\nFinding q: "); + silc_math_gen_prime(&q, prime_bits, TRUE); + + if ((silc_mp_cmp(&p, &q)) == 0) + printf("\nFound equal primes, not good, retrying...\n"); + else + found = TRUE; } /* If p is smaller than q, switch them */ @@ -480,7 +482,7 @@ void rsa_generate_keys(RsaKey *key, uint32 bits, /* Set the primes */ silc_mp_set(&key->p, p); silc_mp_set(&key->q, q); - + /* Compute modulus, n = p * q */ silc_mp_mul(&key->n, &key->p, &key->q); diff --git a/lib/silcmath/silcprimegen.c b/lib/silcmath/silcprimegen.c index bc5edf29..27ed090d 100644 --- a/lib/silcmath/silcprimegen.c +++ b/lib/silcmath/silcprimegen.c @@ -197,7 +197,7 @@ static uint32 primetable[] = bool silc_math_gen_prime(SilcMPInt *prime, uint32 bits, bool verbose) { - unsigned char *numbuf; + unsigned char *numbuf = NULL; uint32 i, b, k; uint32 *spmods; SilcMPInt r, base, tmp, tmp2, oprime; @@ -212,13 +212,20 @@ bool silc_math_gen_prime(SilcMPInt *prime, uint32 bits, bool verbose) SILC_LOG_DEBUG(("Generating new prime")); - /* Get random number */ - numbuf = silc_rng_global_get_rn_string((bits / 8)); - if (!numbuf) - return FALSE; + /* Get random number and assure that the first digit is not zero since + our conversion routines does not like the first digit being zero. */ + do { + if (numbuf) { + memset(numbuf, 0, (bits / 8)); + silc_free(numbuf); + } + numbuf = silc_rng_global_get_rn_string((bits / 8)); + if (!numbuf) + return FALSE; + } while (numbuf[0] == '0'); /* Convert into MP and set the size */ - silc_mp_set_str(prime, numbuf, 16); + silc_mp_set_str(prime, numbuf, 16); silc_mp_mod_2exp(prime, prime, bits); /* Empty buffer */ diff --git a/lib/silcutil/silcmemory.c b/lib/silcutil/silcmemory.c index 61cd6efc..2df6fee4 100644 --- a/lib/silcutil/silcmemory.c +++ b/lib/silcutil/silcmemory.c @@ -24,46 +24,25 @@ void *silc_malloc(size_t size) { void *addr; -#ifdef HAVE_MLOCK addr = malloc(size); assert(addr != NULL); - mlock(addr, size); return addr; -#else - addr = malloc(size); - assert(addr != NULL); - return addr; -#endif } void *silc_calloc(size_t items, size_t size) { void *addr; -#ifdef HAVE_MLOCK addr = calloc(items, size); assert(addr != NULL); - mlock(addr, size); return addr; -#else - addr = calloc(items, size); - assert(addr != NULL); - return addr; -#endif } void *silc_realloc(void *ptr, size_t size) { void *addr; -#ifdef HAVE_MLOCK - addr = realloc(ptr, size); - assert(addr != NULL); - mlock(addr, size); - return addr; -#else addr = realloc(ptr, size); assert(addr != NULL); return addr; -#endif } void silc_free(void *ptr) diff --git a/lib/silcutil/silcnet.h b/lib/silcutil/silcnet.h index 9bdee554..4c966eab 100644 --- a/lib/silcutil/silcnet.h +++ b/lib/silcutil/silcnet.h @@ -72,32 +72,41 @@ void silc_net_close_server(int sock); * * SYNOPSIS * - * int silc_net_create_connection(int port, char *host); + * int silc_net_create_connection(const char *local_ip, int port, + * const char *host); * * DESCRIPTION * * Creates a connection (TCP/IP) to a remote host. Returns the connection * socket or -1 on error. This blocks the process while trying to create - * the connection. + * the connection. If the `local_ip' is not NULL then this will bind + * the `local_ip' address to a port before creating the connection. If + * it is NULL then this will directly create the connection. * ***/ -int silc_net_create_connection(int port, char *host); +int silc_net_create_connection(const char *localhost, int port, + const char *host); /****f* silcutil/SilcNetAPI/silc_net_create_connection_async * * SYNOPSIS * - * int silc_net_create_connection_async(int port, char *host); + * int silc_net_create_connection_async(const char *local_ip, int port, + * const char *host); * * DESCRIPTION * * Creates a connection (TCP/IP) to a remote host. Returns the connection * socket or -1 on error. This creates non-blocking socket hence the * connection returns directly. To get the result of the connect() one - * must select() the socket and read the result after it's ready. + * must select() the socket and read the result after it's ready. If the + * `local_ip' is not NULL then this will bind the `local_ip' address to + * a port before creating the connection. If it is NULL then this will + * directly create the connection. * ***/ -int silc_net_create_connection_async(int port, char *host); +int silc_net_create_connection_async(const char *local_ip, int port, + const char *host); /****f* silcutil/SilcNetAPI/silc_net_close_connection * diff --git a/lib/silcutil/unix/silcunixnet.c b/lib/silcutil/unix/silcunixnet.c index 2849e3f7..5268d554 100644 --- a/lib/silcutil/unix/silcunixnet.c +++ b/lib/silcutil/unix/silcunixnet.c @@ -37,7 +37,7 @@ int silc_net_create_server(int port, char *ip_addr) SILC_LOG_DEBUG(("Creating a new server listener")); /* Create the socket */ - sock = socket(PF_INET, SOCK_STREAM, 0); + sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno))); return -1; @@ -52,7 +52,7 @@ int silc_net_create_server(int port, char *ip_addr) /* Set the socket information for bind() */ memset(&server, 0, sizeof(server)); - server.sin_family = PF_INET; + server.sin_family = AF_INET; if (port) server.sin_port = htons(port); @@ -98,7 +98,8 @@ void silc_net_close_server(int sock) socket or -1 on error. This blocks the process while trying to create the connection. */ -int silc_net_create_connection(int port, char *host) +int silc_net_create_connection(const char *local_ip, int port, + const char *host) { int sock, rval; struct hostent *dest; @@ -117,16 +118,38 @@ int silc_net_create_connection(int port, char *host) /* Set socket information */ memset(&desthost, 0, sizeof(desthost)); desthost.sin_port = htons(port); - desthost.sin_family = PF_INET; + desthost.sin_family = AF_INET; memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr)); /* Create the connection socket */ - sock = socket(PF_INET, SOCK_STREAM, 0); + sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno))); return -1; } + /* Bind to the local address if provided */ + if (local_ip) { + struct sockaddr_in local; + int local_len = sizeof(local.sin_addr); + + /* Set the socket information for bind() */ + memset(&local, 0, sizeof(local)); + local.sin_family = AF_INET; + + /* Convert IP address to network byte order */ + silc_net_addr2bin(local_ip, (unsigned char *)&local.sin_addr.s_addr, + local_len); + + /* Bind the local socket */ + rval = bind(sock, (struct sockaddr *)&local, sizeof(local)); + if (rval < 0) { + SILC_LOG_ERROR(("Cannot connect to remote host: " + "cannot bind socket: %s", strerror(errno))); + return -1; + } + } + /* Connect to the host */ rval = connect(sock, (struct sockaddr *)&desthost, sizeof(desthost)); if (rval < 0) { @@ -152,7 +175,8 @@ int silc_net_create_connection(int port, char *host) connection returns directly. To get the result of the connect() one must select() the socket and read the result after it's ready. */ -int silc_net_create_connection_async(int port, char *host) +int silc_net_create_connection_async(const char *local_ip, int port, + const char *host) { int sock, rval; struct hostent *dest; @@ -172,16 +196,38 @@ int silc_net_create_connection_async(int port, char *host) /* Set socket information */ memset(&desthost, 0, sizeof(desthost)); desthost.sin_port = htons(port); - desthost.sin_family = PF_INET; + desthost.sin_family = AF_INET; memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr)); /* Create the connection socket */ - sock = socket(PF_INET, SOCK_STREAM, 0); + sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno))); return -1; } + /* Bind to the local address if provided */ + if (local_ip) { + struct sockaddr_in local; + int local_len = sizeof(local.sin_addr); + + /* Set the socket information for bind() */ + memset(&local, 0, sizeof(local)); + local.sin_family = AF_INET; + + /* Convert IP address to network byte order */ + silc_net_addr2bin(local_ip, (unsigned char *)&local.sin_addr.s_addr, + local_len); + + /* Bind the local socket */ + rval = bind(sock, (struct sockaddr *)&local, sizeof(local)); + if (rval < 0) { + SILC_LOG_ERROR(("Cannot connect to remote host: " + "cannot bind socket: %s", strerror(errno))); + return -1; + } + } + /* Set the socket to non-blocking mode */ silc_net_set_socket_nonblock(sock); diff --git a/lib/silcutil/win32/silcwin32net.c b/lib/silcutil/win32/silcwin32net.c index 142a502e..e4ffc6aa 100644 --- a/lib/silcutil/win32/silcwin32net.c +++ b/lib/silcutil/win32/silcwin32net.c @@ -99,7 +99,8 @@ void silc_net_close_server(int sock) socket or -1 on error. This blocks the process while trying to create the connection. */ -int silc_net_create_connection(int port, char *host) +int silc_net_create_connection(const char *local_ip, int port, + const char *host) { SOCKET sock; int rval, err; @@ -155,7 +156,8 @@ int silc_net_create_connection(int port, char *host) connection returns directly. To get the result of the connect() one must select() the socket and read the result after it's ready. */ -int silc_net_create_connection_async(int port, char *host) +int silc_net_create_connection_async(const char *local_ip, int port, + const char *host) { SOCKET sock; int rval, err; diff --git a/prepare b/prepare index b00d1778..b9a8b856 100755 --- a/prepare +++ b/prepare @@ -2,7 +2,7 @@ # # prepare # -# Author: Pekka Riikonen +# Author: Pekka Riikonen # # Copyright (C) 2000 - 2001 Pekka Riikonen # @@ -60,7 +60,7 @@ if test "$dist_version" = ""; then dist_version=$version fi -echo "Preparing $distribution distribution version $version" +echo "Preparing $distribution distribution version $version (package $dist_version)" # # Go though the subdirs and create the Makefile.ams from the -- 2.24.0