X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=apps%2Fsilcd%2Fserver.c;h=b3914316e3b9cedef4d11937049dcc429a3d323a;hb=2407b5a8d55101dcc4cccb098888e0e21f6f299c;hp=f90aca67e2ba55daa6568bd6ea54f9dbf4777fd8;hpb=6493ad0f849286d972031f20c6eed45140d5e0a7;p=silc.git diff --git a/apps/silcd/server.c b/apps/silcd/server.c index f90aca67..b3914316 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -143,7 +143,6 @@ int silc_server_init(SilcServer server) /* Set log files where log message should be saved. */ server->config->server = server; - silc_server_config_setlogfiles(server->config); /* Register all configured ciphers, PKCS and hash functions. */ if (!silc_server_config_register_ciphers(server->config)) @@ -164,9 +163,6 @@ int silc_server_init(SilcServer server) silc_hash_alloc("md5", &server->md5hash); silc_hash_alloc("sha1", &server->sha1hash); - /* Initialize none cipher */ - silc_cipher_alloc("none", &server->none_cipher); - /* 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); @@ -284,7 +280,7 @@ int silc_server_init(SilcServer server) server->schedule = silc_schedule_init(SILC_SERVER_MAX_CONNECTIONS); if (!server->schedule) goto err0; - + /* Add the first task to the scheduler. This is task that is executed by timeout. It expires as soon as the caller calls silc_server_run. This task performs authentication protocol and key exchange with our @@ -305,6 +301,9 @@ int silc_server_init(SilcServer server) SILC_TASK_PRI_NORMAL); server->listenning = TRUE; + /* Send log file configuration */ + silc_server_config_setlogfiles(server->config, server->schedule); + /* If server connections has been configured then we must be router as normal server cannot have server connections, only router connections. */ if (server->config->servers) { @@ -357,27 +356,26 @@ int silc_server_init(SilcServer server) return FALSE; } -/* Fork server to background and set gid+uid to non-root */ +/* Fork server to background */ void silc_server_daemonise(SilcServer server) { int i; - i = fork (); + SILC_LOG_DEBUG(("Forking SILC server to background")); - if (i) { - if (i > 0) { - if (geteuid()) - SILC_LOG_DEBUG(("Server started as user")); - else - SILC_LOG_DEBUG(("Server started as root. Dropping privileges.")); + i = fork(); - SILC_LOG_DEBUG(("Forking SILC server to background")); - exit(0); - } else { - SILC_LOG_DEBUG(("fork() failed, cannot proceed")); - exit(1); - } + if (i < 0) { + SILC_LOG_DEBUG(("fork() failed, cannot proceed")); + exit(1); + } + else if (i) { + if (geteuid()) + SILC_LOG_DEBUG(("Server started as user")); + else + SILC_LOG_DEBUG(("Server started as root. Dropping privileges.")); + exit(0); } setsid(); } @@ -388,7 +386,6 @@ void silc_server_drop(SilcServer server) { /* Are we executing silcd as root or a regular user? */ if (!geteuid()) { - struct passwd *pw; struct group *gr; char *user, *group; @@ -501,8 +498,11 @@ void silc_server_stop(SilcServer server) { SILC_LOG_DEBUG(("Stopping server")); - silc_schedule_stop(server->schedule); - silc_schedule_uninit(server->schedule); + if (server->schedule) { + silc_schedule_stop(server->schedule); + silc_schedule_uninit(server->schedule); + server->schedule = NULL; + } silc_server_protocols_unregister(); @@ -522,6 +522,10 @@ void silc_server_start_key_exchange(SilcServer server, SilcServerKEInternalContext *proto_ctx; void *context; + /* Cancel any possible retry timeouts */ + silc_schedule_task_del_by_callback(server->schedule, + silc_server_connect_router); + /* Set socket options */ silc_net_set_socket_nonblock(sock); silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1); @@ -635,11 +639,13 @@ SILC_TASK_CALLBACK(silc_server_connect_router) sconn->remote_port, sconn->remote_host); if (sock < 0) { - SILC_LOG_ERROR(("Could not connect to router")); - silc_schedule_task_add(server->schedule, fd, - silc_server_connect_to_router_retry, - context, 0, 1, SILC_TASK_TIMEOUT, - SILC_TASK_PRI_NORMAL); + SILC_LOG_ERROR(("Could not connect to router %s:%d", + sconn->remote_host, sconn->remote_port)); + if (!sconn->no_reconnect) + silc_schedule_task_add(server->schedule, fd, + silc_server_connect_to_router_retry, + context, 0, 1, SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); return; } @@ -689,6 +695,9 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router) sconn->backup_replace_port = ptr->backup_replace_port; } + if (!server->router_conn && !sconn->backup) + server->router_conn = sconn; + silc_schedule_task_add(server->schedule, fd, silc_server_connect_router, (void *)sconn, 0, 1, SILC_TASK_TIMEOUT, @@ -940,7 +949,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) timeout!! */ hb_context = silc_calloc(1, sizeof(*hb_context)); hb_context->server = server; - silc_socket_set_heartbeat(sock, 600, hb_context, + silc_socket_set_heartbeat(sock, 300, hb_context, silc_server_perform_heartbeat, server->schedule); @@ -988,6 +997,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) silc_free(sconn->backup_replace_ip); silc_free(sconn); } + if (sconn == server->router_conn) + server->router_conn = NULL; /* Free the protocol object */ if (sock->protocol == protocol) @@ -1080,6 +1091,8 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock, sock->hostname, port); if (!cconfig && !sconfig && !rconfig) { + SILC_LOG_INFO(("Connection %s (%s) is not allowed", + sock->hostname, sock->ip)); silc_server_disconnect_remote(server, sock, "Server closed connection: " "Connection refused"); @@ -1283,7 +1296,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) SilcSocketConnection sock = ctx->sock; SilcServerHBContext hb_context; SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data; - void *id_entry = NULL; + void *id_entry; SILC_LOG_DEBUG(("Start")); @@ -1425,15 +1438,15 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) break; } default: + goto out; break; } sock->type = ctx->conn_type; /* Add the common data structure to the ID entry. */ - if (id_entry) - silc_idlist_add_data(id_entry, (SilcIDListData)sock->user_data); - + silc_idlist_add_data(id_entry, (SilcIDListData)sock->user_data); + /* Add to sockets internal pointer for fast referencing */ silc_free(sock->user_data); sock->user_data = id_entry; @@ -1446,7 +1459,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) timeout!! */ hb_context = silc_calloc(1, sizeof(*hb_context)); hb_context->server = server; - silc_socket_set_heartbeat(sock, 600, hb_context, + silc_socket_set_heartbeat(sock, 400, hb_context, silc_server_perform_heartbeat, server->schedule); @@ -1546,7 +1559,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process) close the connection */ if (SILC_IS_DISCONNECTING(sock)) { if (sock->user_data) - silc_server_free_sock_user_data(server, sock); + silc_server_free_sock_user_data(server, sock, NULL); silc_server_close_connection(server, sock); return; } @@ -1554,8 +1567,20 @@ SILC_TASK_CALLBACK(silc_server_packet_process) SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock)); SILC_SET_DISCONNECTING(sock); - if (sock->user_data) - silc_server_free_sock_user_data(server, sock); + if (sock->user_data) { + char tmp[128]; + if (silc_socket_get_error(sock, tmp, sizeof(tmp) - 1)) + silc_server_free_sock_user_data(server, sock, tmp); + else + silc_server_free_sock_user_data(server, sock, NULL); + } else if (server->router_conn && server->router_conn->sock == sock && + !server->router && server->standalone) + silc_schedule_task_add(server->schedule, 0, + silc_server_connect_to_router, + server, 1, 0, + SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); + silc_server_close_connection(server, sock); return; } @@ -1579,9 +1604,23 @@ SILC_TASK_CALLBACK(silc_server_packet_process) /* Process the packet. This will call the parser that will then decrypt and parse the packet. */ - silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? - TRUE : FALSE, cipher, hmac, sequence, - silc_server_packet_parse, server); + ret = silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? + TRUE : FALSE, cipher, hmac, sequence, + silc_server_packet_parse, server); + + /* If this socket connection is not authenticated yet and the packet + processing failed we will drop the connection since it can be + a malicious flooder. */ + if (sock->type == SILC_SOCKET_TYPE_UNKNOWN && ret == FALSE && + (!sock->protocol || sock->protocol->protocol->type == + SILC_PROTOCOL_SERVER_KEY_EXCHANGE)) { + SILC_LOG_DEBUG(("Bad data sent from unknown connection %d", sock->sock)); + SILC_SET_DISCONNECTING(sock); + + if (sock->user_data) + silc_server_free_sock_user_data(server, sock, NULL); + silc_server_close_connection(server, sock); + } } /* Parses whole packet, received earlier. */ @@ -2173,7 +2212,7 @@ void silc_server_packet_parse_type(SilcServer server, /* Creates connection to a remote router. */ void silc_server_create_connection(SilcServer server, - char *remote_host, uint32 port) + const char *remote_host, uint32 port) { SilcServerConnection sconn; @@ -2182,6 +2221,7 @@ void silc_server_create_connection(SilcServer server, sconn->server = server; sconn->remote_host = strdup(remote_host); sconn->remote_port = port; + sconn->no_reconnect = TRUE; silc_schedule_task_add(server->schedule, 0, silc_server_connect_router, @@ -2290,7 +2330,7 @@ void silc_server_free_client_data(SilcServer server, SilcSocketConnection sock, SilcClientEntry client, int notify, - char *signoff) + const char *signoff) { FreeClientInternal i = silc_calloc(1, sizeof(*i)); @@ -2310,11 +2350,19 @@ void silc_server_free_client_data(SilcServer server, /* Remove client from all channels */ if (notify) silc_server_remove_from_channels(server, NULL, client, - TRUE, signoff, TRUE); + TRUE, (char *)signoff, TRUE); else silc_server_remove_from_channels(server, NULL, client, FALSE, NULL, FALSE); + /* Update statistics */ + server->stat.my_clients--; + server->stat.clients--; + if (server->server_type == SILC_ROUTER) + server->stat.cell_clients--; + SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR); + SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR); + /* We will not delete the client entry right away. We will take it into history (for WHOWAS command) for 5 minutes */ i->server = server; @@ -2326,12 +2374,7 @@ void silc_server_free_client_data(SilcServer server, client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; client->router = NULL; client->connection = NULL; - - /* Free the client entry and everything in it */ - server->stat.my_clients--; - server->stat.clients--; - if (server->server_type == SILC_ROUTER) - server->stat.cell_clients--; + client->mode = 0; } /* Frees user_data pointer from socket connection object. This also sends @@ -2339,7 +2382,8 @@ void silc_server_free_client_data(SilcServer server, entities. */ void silc_server_free_sock_user_data(SilcServer server, - SilcSocketConnection sock) + SilcSocketConnection sock, + const char *signoff_message) { SILC_LOG_DEBUG(("Start")); @@ -2347,7 +2391,8 @@ void silc_server_free_sock_user_data(SilcServer server, case SILC_SOCKET_TYPE_CLIENT: { SilcClientEntry user_data = (SilcClientEntry)sock->user_data; - silc_server_free_client_data(server, sock, user_data, TRUE, NULL); + silc_server_free_client_data(server, sock, user_data, TRUE, + signoff_message); break; } case SILC_SOCKET_TYPE_SERVER: @@ -2365,7 +2410,7 @@ void silc_server_free_sock_user_data(SilcServer server, /* Check whether we have a backup router connection */ if (!backup_router || backup_router == user_data) { silc_schedule_task_add(server->schedule, 0, - silc_server_connect_to_router, + silc_server_connect_to_router, server, 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); @@ -2717,13 +2762,15 @@ SILC_TASK_CALLBACK(silc_server_timeout_remote) /* If we have protocol active we must assure that we call the protocol's final callback so that all the memory is freed. */ if (sock->protocol) { + silc_protocol_cancel(sock->protocol, server->schedule); sock->protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute_final(sock->protocol, server->schedule); + sock->protocol = NULL; return; } if (sock->user_data) - silc_server_free_sock_user_data(server, sock); + silc_server_free_sock_user_data(server, sock, NULL); silc_server_disconnect_remote(server, sock, "Server closed connection: " "Connection timeout"); @@ -2765,7 +2812,7 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server, channel_name = strdup(channel_name); - /* Create the channel */ + /* Create the channel ID */ if (!silc_id_create_channel_id(server, router_id, server->rng, &channel_id)) { silc_free(channel_name); @@ -2773,6 +2820,8 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server, silc_hmac_free(newhmac); return NULL; } + + /* Create the channel */ entry = silc_idlist_add_channel(server->local_list, channel_name, SILC_CHANNEL_MODE_NONE, channel_id, NULL, key, newhmac, 0); @@ -2780,6 +2829,7 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server, silc_free(channel_name); silc_cipher_free(key); silc_hmac_free(newhmac); + silc_free(channel_id); return NULL; } @@ -2789,11 +2839,7 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server, /* Now create the actual key material */ if (!silc_server_create_channel_key(server, entry, silc_cipher_get_key_len(key) / 8)) { - silc_free(channel_name); - silc_cipher_free(key); - silc_hmac_free(newhmac); - silc_free(entry->cipher); - silc_free(entry->hmac_name); + silc_idlist_del_channel(server->local_list, entry); return NULL; } @@ -2848,6 +2894,8 @@ silc_server_create_new_channel_with_id(SilcServer server, SILC_CHANNEL_MODE_NONE, channel_id, NULL, key, newhmac, 0); if (!entry) { + silc_cipher_free(key); + silc_hmac_free(newhmac); silc_free(channel_name); return NULL; } @@ -2855,7 +2903,7 @@ silc_server_create_new_channel_with_id(SilcServer server, /* Now create the actual key material */ if (!silc_server_create_channel_key(server, entry, silc_cipher_get_key_len(key) / 8)) { - silc_free(channel_name); + silc_idlist_del_channel(server->local_list, entry); return NULL; } @@ -2982,10 +3030,10 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server, SILC_LOG_DEBUG(("Start")); /* Decode channel key payload */ - payload = silc_channel_key_payload_parse(key_payload->data, + payload = silc_channel_key_payload_parse(key_payload->data, key_payload->len); if (!payload) { - SILC_LOG_ERROR(("Bad channel key payload, dropped")); + SILC_LOG_ERROR(("Bad channel key payload received, dropped")); channel = NULL; goto out; } @@ -3005,7 +3053,8 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server, if (!channel) { channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL); if (!channel) { - SILC_LOG_ERROR(("Received key for non-existent channel")); + SILC_LOG_ERROR(("Received key for non-existent channel %s", + silc_id_render(id, SILC_ID_CHANNEL))); goto out; } } @@ -3090,8 +3139,7 @@ void silc_server_perform_heartbeat(SilcSocketConnection sock, { SilcServerHBContext hb = (SilcServerHBContext)hb_context; - SILC_LOG_DEBUG(("Sending heartbeat to %s (%s)", sock->hostname, - sock->ip)); + SILC_LOG_DEBUG(("Sending heartbeat to %s (%s)", sock->hostname, sock->ip)); /* Send the heartbeat */ silc_server_send_heartbeat(hb->server, sock); @@ -3547,6 +3595,8 @@ void silc_server_announce_channels(SilcServer server, int i; for (i = 0; i < channel_users_modes_c; i++) { + if (!channel_users_modes[i]) + continue; silc_buffer_push(channel_users_modes[i], channel_users_modes[i]->data - channel_users_modes[i]->head); @@ -3675,6 +3725,8 @@ void silc_server_save_users_on_channel(SilcServer server, SilcIDCacheEntry cache; bool global; + SILC_LOG_DEBUG(("Start")); + for (i = 0; i < user_count; i++) { /* Client ID */ SILC_GET16_MSB(idp_len, user_list->data + 2); @@ -3880,10 +3932,14 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server, it using WHOIS command. */ SilcClientEntry silc_server_get_client_resolve(SilcServer server, - SilcClientID *client_id) + SilcClientID *client_id, + bool *resolved) { SilcClientEntry client; + if (resolved) + *resolved = FALSE; + client = silc_idlist_find_client_by_id(server->local_list, client_id, TRUE, NULL); if (!client) { @@ -3913,6 +3969,10 @@ SilcClientEntry silc_server_get_client_resolve(SilcServer server, buffer->data, buffer->len, FALSE); silc_buffer_free(idp); silc_buffer_free(buffer); + + if (resolved) + *resolved = TRUE; + return NULL; }