int silc_file_writefile(const char *filename, const char *buffer, SilcUInt32 len) { int fd; int flags = O_CREAT | O_WRONLY | O_TRUNC; #if defined(O_BINARY) flags |= O_BINARY; #endif /* O_BINARY */ if ((fd = open(filename, flags, 0644)) == -1) { SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename, silc_errno_string(silc_errno))); return -1; } if (silc_file_write(fd, buffer, len) == -1) { SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, silc_errno_string(silc_errno))); silc_file_close(fd); return -1; } #ifdef SILC_UNIX fsync(fd); #endif /* SILC_UNIX */ return silc_file_close(fd); }
SilcCommandPayload silc_command_payload_parse(const unsigned char *payload, SilcUInt32 payload_len) { SilcBufferStruct buffer; SilcCommandPayload newp; unsigned char args_num; SilcUInt16 p_len; int ret; SILC_LOG_DEBUG(("Parsing command payload")); silc_buffer_set(&buffer, (unsigned char *)payload, payload_len); newp = silc_calloc(1, sizeof(*newp)); if (!newp) return NULL; /* Parse the Command Payload */ ret = silc_buffer_unformat(&buffer, SILC_STR_UI_SHORT(&p_len), SILC_STR_UI_CHAR(&newp->cmd), SILC_STR_UI_CHAR(&args_num), SILC_STR_UI_SHORT(&newp->ident), SILC_STR_END); if (ret == -1) { SILC_LOG_ERROR(("Incorrect command payload in packet")); silc_free(newp); return NULL; } if (p_len != silc_buffer_len(&buffer)) { SILC_LOG_ERROR(("Incorrect command payload in packet")); silc_free(newp); return NULL; } if (newp->cmd == 0) { SILC_LOG_ERROR(("Incorrect command type in command payload")); silc_free(newp); return NULL; } silc_buffer_pull(&buffer, SILC_COMMAND_PAYLOAD_LEN); if (args_num) { newp->args = silc_argument_payload_parse(buffer.data, silc_buffer_len(&buffer), args_num); if (!newp->args) { silc_free(newp); return NULL; } } silc_buffer_push(&buffer, SILC_COMMAND_PAYLOAD_LEN); return newp; }
char *silc_file_readfile(const char *filename, SilcUInt32 *return_len, SilcStack stack) { int fd; unsigned char *buffer; int filelen; fd = silc_file_open(filename, O_RDONLY); if (fd < 0) { if (silc_errno == SILC_ERR_NO_SUCH_FILE) return NULL; SILC_LOG_ERROR(("Cannot open file %s: %s", filename, silc_errno_string(silc_errno))); return NULL; } filelen = lseek(fd, (off_t)0L, SEEK_END); if (filelen < 0) { silc_set_errno_posix(errno); silc_file_close(fd); return NULL; } if (lseek(fd, (off_t)0L, SEEK_SET) < 0) { silc_set_errno_posix(errno); silc_file_close(fd); return NULL; } buffer = silc_calloc(filelen + 1, sizeof(*buffer)); if (!buffer) { silc_set_errno_posix(errno); silc_file_close(fd); return NULL; } if ((silc_file_read(fd, buffer, filelen)) == -1) { memset(buffer, 0, sizeof(buffer)); silc_file_close(fd); SILC_LOG_ERROR(("Cannot read from file %s: %s", filename, silc_errno_string(silc_errno))); return NULL; } silc_file_close(fd); buffer[filelen] = EOF; if (return_len) *return_len = filelen; return (char *)buffer; }
char *silc_file_readfile(const char *filename, SilcUInt32 *return_len) { int fd; char *buffer; int filelen; fd = silc_file_open(filename, O_RDONLY); if (fd < 0) { if (errno == ENOENT) return NULL; SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno))); return NULL; } filelen = lseek(fd, (off_t)0L, SEEK_END); if (filelen < 0) { silc_file_close(fd); return NULL; } if (lseek(fd, (off_t)0L, SEEK_SET) < 0) { silc_file_close(fd); return NULL; } if (filelen < 0) { SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno))); silc_file_close(fd); return NULL; } buffer = silc_calloc(filelen + 1, sizeof(char)); if ((silc_file_read(fd, buffer, filelen)) == -1) { memset(buffer, 0, sizeof(buffer)); silc_file_close(fd); SILC_LOG_ERROR(("Cannot read from file %s: %s", filename, strerror(errno))); return NULL; } silc_file_close(fd); buffer[filelen] = EOF; if (return_len) *return_len = filelen; return buffer; }
SilcThread silc_thread_create(SilcThreadStart start_func, void *context, SilcBool waitable) { #ifdef SILC_THREADS SilcWin32Thread thread; unsigned id; SILC_LOG_DEBUG(("Creating new thread")); thread = silc_calloc(1, sizeof(*thread)); thread->start_func = start_func; thread->context = context; thread->waitable = waitable; thread->thread = _beginthreadex(NULL, 0, (LPTHREAD_START_ROUTINE)silc_thread_win32_start, (void *)thread, 0, &id); if (!thread->thread) { SILC_LOG_ERROR(("Could not create new thread")); silc_free(thread); return NULL; } return (SilcThread)thread; #else /* Call thread callback immediately */ (*start_func)(context); return NULL; #endif }
SilcThread silc_thread_create(SilcThreadStart start_func, void *context, SilcBool waitable) { #ifdef SILC_THREADS int ret; SilcOs2Thread thread = silc_calloc(1, sizeof(*thread)); if (!thread) return NULL; thread->start_func = start_func; thread->context = context; thread->waitable = waitable; /* Create the thread, and run it */ thread->thread = _beginthread(silc_thread_os2_start, NULL, 65536, thread); if (thread->thread < 0) { SILC_LOG_ERROR(("Could not create new thread")); silc_free(thread); return NULL; } return (SilcThread)thread->thread; #else /* Call thread callback immediately */ (*start_func)(context); return NULL; #endif }
SilcAsyncOperation silc_client_key_exchange(SilcClient client, SilcClientConnectionParams *params, SilcPublicKey public_key, SilcPrivateKey private_key, SilcStream stream, SilcConnectionType conn_type, SilcClientConnectCallback callback, void *context) { SilcClientConnection conn; const char *host; SilcUInt16 port; SILC_LOG_DEBUG(("Performing key exchange")); if (!client || !stream) return NULL; if (client->internal->run_callback) { SILC_LOG_ERROR(("Client library is not started yet. SilcClientRunning " "callback has not been called yet.")); return NULL; } if (!silc_socket_stream_get_info(stream, NULL, &host, NULL, &port)) { SILC_LOG_ERROR(("Socket stream does not have remote host name set")); callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL, context); return NULL; } /* Add new connection */ conn = silc_client_add_connection(client, conn_type, TRUE, params, public_key, private_key, (char *)host, port, callback, context); if (!conn) { callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL, context); return NULL; } conn->internal->user_stream = stream; /* Signal connection to start key exchange */ conn->internal->key_exchange = TRUE; return conn->internal->cop; }
SilcThread silc_thread_create(SilcThreadStart start_func, void *context, SilcBool waitable) { #ifdef SILC_THREADS pthread_attr_t attr; pthread_t thread; int ret; SILC_LOG_DEBUG(("Creating new thread")); if (!start_func) return NULL; if (pthread_attr_init(&attr)) { SILC_LOG_ERROR(("Thread error: %s", strerror(errno))); return NULL; } if (pthread_attr_setdetachstate(&attr, waitable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED)) { SILC_LOG_ERROR(("Thread error: %s", strerror(errno))); pthread_attr_destroy(&attr); return NULL; } ret = pthread_create(&thread, &attr, (void * (*)(void *))start_func, context); if (ret) { SILC_LOG_ERROR(("Thread error: %s", strerror(errno))); pthread_attr_destroy(&attr); return NULL; } pthread_attr_destroy(&attr); SILC_LOG_DEBUG(("Created thread %p", (SilcThread)thread)); return (SilcThread)thread; #else /* Call thread callback immediately */ (*start_func)(context); return NULL; #endif }
SilcBool silc_buffer_stream_notifier(SilcStream stream, SilcSchedule schedule, SilcStreamNotifier callback, void *context) { SILC_LOG_ERROR(("The silc_stream_set_notifier cannot be used with " "buffer streams")); return FALSE; }
SilcBool silc_pkcs1_encode(SilcPkcs1BlockType bt, const unsigned char *data, SilcUInt32 data_len, unsigned char *dest_data, SilcUInt32 dest_data_size, SilcRng rng) { SilcInt32 padlen; int i; SILC_LOG_DEBUG(("PKCS#1 encoding, bt %d", bt)); if (!data || !dest_data || dest_data_size < SILC_PKCS1_MIN_PADDING + 3 || dest_data_size < data_len) { SILC_LOG_DEBUG(("Data to be encoded is too long")); return FALSE; } /* Start of block */ dest_data[0] = 0x00; dest_data[1] = (unsigned char)bt; padlen = (SilcInt32)dest_data_size - (SilcInt32)data_len - 3; if (padlen < SILC_PKCS1_MIN_PADDING) { SILC_LOG_DEBUG(("Data to be encoded is too long")); return FALSE; } /* Encode according to block type */ switch (bt) { case SILC_PKCS1_BT_PRV0: case SILC_PKCS1_BT_PRV1: /* Signature */ memset(dest_data + 2, bt == SILC_PKCS1_BT_PRV1 ? 0xff : 0x00, padlen); break; case SILC_PKCS1_BT_PUB: /* Encryption */ if (!rng) { SILC_LOG_ERROR(("Cannot encrypt: random number generator not provided")); return FALSE; } /* It is guaranteed this routine does not return zero byte. */ for (i = 2; i < padlen; i++) dest_data[i] = silc_rng_get_byte_fast(rng); break; } /* Copy the data */ dest_data[padlen + 2] = 0x00; memcpy(dest_data + padlen + 3, data, data_len); return TRUE; }
static SilcBool silc_net_set_sockaddr(SilcSockaddr *addr, const char *ip_addr, int port) { int len; memset(addr, 0, sizeof(*addr)); /* Check for IPv4 and IPv6 addresses */ if (ip_addr) { if (!silc_net_is_ip(ip_addr)) { SILC_LOG_ERROR(("%s is not IP address", ip_addr)); return FALSE; } if (silc_net_is_ip4(ip_addr)) { /* IPv4 address */ len = sizeof(addr->sin.sin_addr); silc_net_addr2bin(ip_addr, (unsigned char *)&addr->sin.sin_addr.s_addr, len); addr->sin.sin_family = AF_INET; addr->sin.sin_port = port ? htons(port) : 0; } else { #ifdef HAVE_IPV6 /* IPv6 address */ len = sizeof(addr->sin6.sin6_addr); silc_net_addr2bin(ip_addr, (unsigned char *)&addr->sin6.sin6_addr, len); addr->sin6.sin6_family = AF_INET6; addr->sin6.sin6_port = port ? htons(port) : 0; #else SILC_LOG_ERROR(("IPv6 support is not compiled in")); return FALSE; #endif } } else { /* Any address */ addr->sin.sin_family = AF_INET; addr->sin.sin_addr.s_addr = INADDR_ANY; if (port) addr->sin.sin_port = htons(port); } return TRUE; }
SilcThread silc_thread_create(SilcThreadStart start_func, void *context, SilcBool waitable) { #ifdef SILC_THREADS SilcSymbianThread *tc; RThread *thread; TInt ret; char tmp[24]; SilcUInt16 wname[24]; SILC_LOG_DEBUG(("Creating new thread")); tc = (SilcSymbianThread *)silc_calloc(1, sizeof(*tc)); if (!tc) return NULL; tc->start_func = start_func; tc->context = context; tc->waitable = waitable; /* Allocate thread */ thread = new RThread; if (!thread) { silc_free(tc); return NULL; } /* Create the thread */ silc_snprintf(tmp, sizeof(tmp), "thread-%p", tc); silc_utf8_c2w((const unsigned char *)tmp, strlen(tmp), wname, sizeof(wname) / sizeof(wname[0])); TBuf<24> name((unsigned short *)wname); name.PtrZ(); ret = thread->Create(name, silc_thread_start, 8192, NULL, tc); if (ret != KErrNone) { SILC_LOG_ERROR(("Could not create new thread, error %d", ret)); delete thread; silc_free(tc); return NULL; } /* Start the thread */ thread->Resume(); /* Close our instance to the thread */ thread->Close(); return (SilcThread)thread; #else /* Call thread callback immediately */ (*start_func)(context); return NULL; #endif }
SilcBool silc_client_send_private_message(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry, SilcMessageFlags flags, SilcHash hash, unsigned char *data, SilcUInt32 data_len) { SilcBuffer buffer; SilcBool ret; SilcID sid, rid; if (silc_unlikely(!client || !conn || !client_entry)) return FALSE; if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash)) return FALSE; if (silc_unlikely(conn->internal->disconnected)) return FALSE; SILC_LOG_DEBUG(("Sending private message")); sid.type = SILC_ID_CLIENT; sid.u.client_id = conn->local_entry->id; rid.type = SILC_ID_CLIENT; rid.u.client_id = client_entry->id; /* Encode private message payload */ buffer = silc_message_payload_encode(flags, data, data_len, (!client_entry->internal.send_key ? FALSE : !client_entry->internal.generated), TRUE, client_entry->internal.send_key, client_entry->internal.hmac_send, client->rng, NULL, conn->private_key, hash, &sid, &rid, NULL); if (silc_unlikely(!buffer)) { SILC_LOG_ERROR(("Error encoding private message")); return FALSE; } /* Send the private message packet */ ret = silc_packet_send_ext(conn->stream, SILC_PACKET_PRIVATE_MESSAGE, client_entry->internal.send_key ? SILC_PACKET_FLAG_PRIVMSG_KEY : 0, 0, NULL, SILC_ID_CLIENT, &client_entry->id, silc_buffer_datalen(buffer), NULL, NULL); silc_buffer_free(buffer); return ret; }
static SilcBool silc_net_set_sockaddr(TInetAddr *addr, const char *ip_addr, int port) { /* Check for IPv4 and IPv6 addresses */ if (ip_addr) { if (!silc_net_is_ip(ip_addr)) { SILC_LOG_ERROR(("%s is not IP address", ip_addr)); return FALSE; } if (silc_net_is_ip4(ip_addr)) { /* IPv4 address */ unsigned char buf[4]; TUint32 a; if (!silc_net_addr2bin(ip_addr, buf, sizeof(buf))) return FALSE; SILC_GET32_MSB(a, buf); addr->SetAddress(a); addr->SetPort(port); } else { #ifdef HAVE_IPV6 SILC_LOG_ERROR(("IPv6 not supported")); return FALSE; #else SILC_LOG_ERROR(("Operating System does not support IPv6")); return FALSE; #endif } } else { addr->SetAddress(0); addr->SetPort(port); } return TRUE; }
SilcDList silc_attribute_payload_parse(const unsigned char *payload, SilcUInt32 payload_len) { SilcBufferStruct buffer; SilcDList list; SilcAttributePayload newp; SilcUInt32 len; int ret; SILC_LOG_DEBUG(("Parsing Attribute Payload list")); silc_buffer_set(&buffer, (unsigned char *)payload, payload_len); list = silc_dlist_init(); while (silc_buffer_len(&buffer)) { newp = silc_calloc(1, sizeof(*newp)); if (!newp) goto err; ret = silc_buffer_unformat(&buffer, SILC_STR_UI_CHAR(&newp->attribute), SILC_STR_UI_CHAR(&newp->flags), SILC_STR_UI16_NSTRING_ALLOC(&newp->data, &newp->data_len), SILC_STR_END); if (ret == -1) goto err; if (newp->data_len > silc_buffer_len(&buffer) - 4) { SILC_LOG_ERROR(("Incorrect attribute payload in list")); goto err; } len = 4 + newp->data_len; if (silc_buffer_len(&buffer) < len) break; silc_buffer_pull(&buffer, len); silc_dlist_add(list, newp); } return list; err: silc_attribute_payload_list_free(list); return NULL; }
static void silc_sftp_send_packet(SilcSFTPServer sftp, SilcSFTPPacket type, SilcUInt32 len, ...) { SilcBuffer tmp; va_list vp; int ret; va_start(vp, len); tmp = silc_sftp_packet_encode_vp(type, sftp->packet, len, vp); va_end(vp); if (!tmp) return; sftp->packet = tmp; SILC_LOG_HEXDUMP(("SFTP packet to client"), silc_buffer_data(sftp->packet), silc_buffer_len(sftp->packet)); /* Send the packet */ while (silc_buffer_len(sftp->packet) > 0) { ret = silc_stream_write(sftp->stream, silc_buffer_data(sftp->packet), silc_buffer_len(sftp->packet)); if (ret == -2) { SILC_LOG_ERROR(("Error sending SFTP packet type %d", type)); sftp->error((SilcSFTP)sftp, SILC_SFTP_STATUS_NO_CONNECTION, sftp->context); silc_buffer_reset(sftp->packet); return; } if (ret == 0) { sftp->error((SilcSFTP)sftp, SILC_SFTP_STATUS_EOF, sftp->context); silc_buffer_reset(sftp->packet); return; } if (ret == -1) return; silc_buffer_pull(sftp->packet, ret); } /* Clear packet */ silc_buffer_reset(sftp->packet); }
SilcAsyncOperation silc_client_connect_to_server(SilcClient client, SilcClientConnectionParams *params, SilcPublicKey public_key, SilcPrivateKey private_key, char *remote_host, int port, SilcClientConnectCallback callback, void *context) { SilcClientConnection conn; SILC_LOG_DEBUG(("Connecting to server")); if (!client || !remote_host) return NULL; if (client->internal->run_callback) { SILC_LOG_ERROR(("Client library is not started yet. SilcClientRunning " "callback has not been called yet.")); return NULL; } /* Add new connection */ conn = silc_client_add_connection(client, SILC_CONN_SERVER, TRUE, params, public_key, private_key, remote_host, port, callback, context); if (!conn) { callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL, context); return NULL; } client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, "Connecting to port %d of server %s", port, remote_host); /* Signal connection machine to start connecting */ conn->internal->connect = TRUE; return conn->internal->cop; }
SilcAsyncOperation silc_client_connect_to_client(SilcClient client, SilcClientConnectionParams *params, SilcPublicKey public_key, SilcPrivateKey private_key, char *remote_host, int port, SilcClientConnectCallback callback, void *context) { SilcClientConnection conn; SILC_LOG_DEBUG(("Connecting to client")); if (!client || !remote_host) return NULL; if (client->internal->run_callback) { SILC_LOG_ERROR(("Client library is not started yet. SilcClientRunning " "callback has not been called yet.")); return NULL; } if (params) params->no_authentication = TRUE; /* Add new connection */ conn = silc_client_add_connection(client, SILC_CONN_CLIENT, TRUE, params, public_key, private_key, remote_host, port, callback, context); if (!conn) { callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL, context); return NULL; } /* Signal connection machine to start connecting */ conn->internal->connect = TRUE; return conn->internal->cop; }
SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr, const char *remote_ip_addr, int remote_port, SilcSchedule schedule, SilcNetCallback callback, void *context) { SilcSymbianTCPConnect *conn; TInetAddr local, remote; SilcResult status; TInt ret; if (!schedule) { schedule = silc_schedule_get_global(); if (!schedule) { silc_set_errno(SILC_ERR_INVALID_ARGUMENT); return NULL; } } if (!remote_ip_addr || remote_port < 1 || !callback) { silc_set_errno(SILC_ERR_INVALID_ARGUMENT); return NULL; } SILC_LOG_DEBUG(("Creating connection to host %s port %d", remote_ip_addr, remote_port)); conn = new SilcSymbianTCPConnect; if (!conn) { callback(SILC_ERR_OUT_OF_MEMORY, NULL, context); return NULL; } conn->schedule = schedule; conn->callback = callback; conn->context = context; conn->port = remote_port; conn->remote = strdup(remote_ip_addr); if (!conn->remote) { status = SILC_ERR_OUT_OF_MEMORY; goto err; } /* Allocate socket */ conn->sock = new RSocket; if (!conn->sock) { status = SILC_ERR_OUT_OF_MEMORY; goto err; } /* Allocate socket server */ conn->ss = new RSocketServ; if (!conn->ss) { status = SILC_ERR_OUT_OF_MEMORY; goto err; } /* Connect to socket server */ ret = conn->ss->Connect(); if (ret != KErrNone) { SILC_LOG_ERROR(("Error connecting to socket server, error %d", ret)); status = SILC_ERR; goto err; } #ifdef SILC_THREADS /* Make our socket shareable between threads */ conn->ss->ShareAuto(); #endif /* SILC_THREADS */ /* Start async operation */ conn->op = silc_async_alloc(silc_net_connect_abort, NULL, (void *)conn); if (!conn->op) { status = SILC_ERR_OUT_OF_MEMORY; goto err; } /* Do host lookup */ if (!silc_net_gethostbyname(remote_ip_addr, FALSE, conn->remote_ip, sizeof(conn->remote_ip))) { SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the " "host", conn->remote)); status = SILC_ERR_UNREACHABLE; goto err; } /* Create the connection socket */ ret = conn->sock->Open(*conn->ss, KAfInet, KSockStream, KProtocolInetTcp); if (ret != KErrNone) { SILC_LOG_ERROR(("Cannot create socket, error %d", ret)); status = SILC_ERR; goto err; } /* Set appropriate options */ conn->sock->SetOpt(KSoTcpNoDelay, KSolInetTcp, 1); conn->sock->SetOpt(KSoTcpKeepAlive, KSolInetTcp, 1); /* Bind to the local address if provided */ if (local_ip_addr) if (silc_net_set_sockaddr(&local, local_ip_addr, 0)) conn->sock->Bind(local); /* Connect to the host */ if (!silc_net_set_sockaddr(&remote, conn->remote_ip, remote_port)) { SILC_LOG_ERROR(("Cannot connect (cannot set address)")); status = SILC_ERR; goto err; } conn->Connect(remote); SILC_LOG_DEBUG(("Connection operation in progress")); return conn->op; err: if (conn->ss) { conn->ss->Close(); delete conn->ss; } if (conn->sock) delete conn->sock; if (conn->remote) silc_free(conn->remote); if (conn->op) silc_async_free(conn->op); callback(status, NULL, context); delete conn; return NULL; }
static char silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd) { SilcServer server = cmd->server; unsigned char *id_data, *umodes; char *nickname, *username, *realname, *tmp; unsigned char *fingerprint; SilcID id; SilcClientEntry client; char global = FALSE; char nick[128 + 1], servername[256 + 1], uname[128 + 1]; SilcUInt32 mode = 0, len, len2, id_len, flen; const char *hostname, *ip; silc_socket_stream_get_info(silc_packet_stream_get_stream(cmd->sock), NULL, &hostname, &ip, NULL); id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len); nickname = silc_argument_get_arg_type(cmd->args, 3, &len); username = silc_argument_get_arg_type(cmd->args, 4, &len); realname = silc_argument_get_arg_type(cmd->args, 5, &len); if (!id_data || !nickname || !username || !realname) return FALSE; tmp = silc_argument_get_arg_type(cmd->args, 7, &len); if (tmp) SILC_GET32_MSB(mode, tmp); if (!silc_id_payload_parse_id(id_data, id_len, &id)) return FALSE; fingerprint = silc_argument_get_arg_type(cmd->args, 9, &flen); /* Check if we have this client cached already. */ client = silc_idlist_find_client_by_id(server->local_list, SILC_ID_GET_ID(id), FALSE, NULL); if (!client) { client = silc_idlist_find_client_by_id(server->global_list, SILC_ID_GET_ID(id), FALSE, NULL); global = TRUE; } if (!client) { /* If router did not find such Client ID in its lists then this must be bogus client or some router in the net is buggy. */ if (server->server_type != SILC_SERVER) return FALSE; /* Take hostname out of nick string if it includes it. */ silc_parse_userfqdn(nickname, nick, sizeof(nick), servername, sizeof(servername)); /* We don't have that client anywhere, add it. The client is added to global list since server didn't have it in the lists so it must be global. This will check for valid nickname and username strings. */ client = silc_idlist_add_client(server->global_list, strdup(nick), username, strdup(realname), silc_id_dup(SILC_ID_GET_ID(id), SILC_ID_CLIENT), silc_packet_get_context(cmd->sock), NULL); if (!client) { SILC_LOG_ERROR(("Could not add new client to the ID Cache")); return FALSE; } client->data.status |= (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED); client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; client->mode = mode; client->servername = servername[0] ? strdup(servername) : NULL; SILC_LOG_DEBUG(("stat.clients %d->%d", server->stat.clients, server->stat.clients + 1)); server->stat.clients++; } else { /* We have the client already, update the data */ SILC_LOG_DEBUG(("Updating client data")); /* Check nickname */ silc_parse_userfqdn(nickname, nick, sizeof(nick), servername, sizeof(servername)); nickname = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8, 128, NULL); if (!nickname) { SILC_LOG_ERROR(("Malformed nickname '%s' received in WHOIS reply " "from %s", hostname ? hostname : "", nick)); return FALSE; } /* Check username */ silc_parse_userfqdn(username, uname, sizeof(uname), NULL, 0); if (!silc_identifier_verify(uname, strlen(uname), SILC_STRING_UTF8, 128)) { SILC_LOG_ERROR(("Malformed username '%s' received in WHOIS reply " "from %s", hostname ? hostname : "", tmp)); return FALSE; } /* Update entry */ silc_idcache_update_by_context(global ? server->global_list->clients : server->local_list->clients, client, NULL, nickname, TRUE); silc_free(client->nickname); silc_free(client->username); silc_free(client->userinfo); silc_free(client->servername); client->nickname = strdup(nick); client->username = strdup(username); client->userinfo = strdup(realname); client->servername = servername[0] ? strdup(servername) : NULL; client->mode = mode; client->data.status |= SILC_IDLIST_STATUS_RESOLVED; client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; } /* Save channel list if it was sent to us */ if (server->server_type == SILC_SERVER) { tmp = silc_argument_get_arg_type(cmd->args, 6, &len); umodes = silc_argument_get_arg_type(cmd->args, 10, &len2); if (tmp && umodes) { SilcBufferStruct channels_buf, umodes_buf; silc_buffer_set(&channels_buf, tmp, len); silc_buffer_set(&umodes_buf, umodes, len2); silc_server_save_user_channels(server, cmd->sock, client, &channels_buf, &umodes_buf); } else { silc_server_save_user_channels(server, cmd->sock, client, NULL, NULL); } } if (fingerprint && flen == sizeof(client->data.fingerprint)) memcpy(client->data.fingerprint, fingerprint, flen); /* Take Requested Attributes if set. */ tmp = silc_argument_get_arg_type(cmd->args, 11, &len); if (tmp) { silc_free(client->attrs); client->attrs = silc_memdup(tmp, len); client->attrs_len = len; /* Try to take public key from attributes if present and we don't have the key already. Do this only on normal server. Routers do GETKEY for all clients anyway. */ if (server->server_type != SILC_ROUTER && !client->data.public_key) { SilcAttributePayload attr; SilcAttributeObjPk pk; unsigned char f[SILC_HASH_MAXLEN]; SilcDList attrs = silc_attribute_payload_parse(tmp, len); SILC_LOG_DEBUG(("Take client public key from attributes")); if (attrs) { silc_dlist_start(attrs); while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) { if (silc_attribute_get_attribute(attr) == SILC_ATTRIBUTE_USER_PUBLIC_KEY) { if (!silc_attribute_get_object(attr, &pk, sizeof(pk))) continue; /* Take only SILC public keys */ if (strcmp(pk.type, "silc-rsa")) { silc_free(pk.type); silc_free(pk.data); continue; } /* Verify that the server provided fingerprint matches the key */ silc_hash_make(server->sha1hash, pk.data, pk.data_len, f); if (memcmp(f, client->data.fingerprint, sizeof(f))) { silc_free(pk.type); silc_free(pk.data); continue; } /* Save the public key. */ if (!silc_pkcs_public_key_alloc(SILC_PKCS_SILC, pk.data, pk.data_len, &client->data.public_key)) { silc_free(pk.type); silc_free(pk.data); continue; } SILC_LOG_DEBUG(("Saved client public key from attributes")); /* Add client's public key to repository */ if (!silc_server_get_public_key_by_client(server, client, NULL)) silc_skr_add_public_key_simple(server->repository, client->data.public_key, SILC_SKR_USAGE_IDENTIFICATION, client, NULL); silc_free(pk.type); silc_free(pk.data); break; } } silc_attribute_payload_list_free(attrs); } } } return TRUE; }
SilcBool silc_client_init(SilcClient client, const char *username, const char *hostname, const char *realname, SilcClientRunning running, void *context) { SILC_LOG_DEBUG(("Initializing client")); if (!client) return FALSE; if (!username || !hostname) { SILC_LOG_ERROR(("Username and hostname must be given to " "silc_client_init")); return FALSE; } if (!realname) realname = username; /* Validate essential strings */ if (!silc_identifier_verify(username, strlen(username), SILC_STRING_UTF8, 128)) { SILC_LOG_ERROR(("Malformed username '%s'. Username must be UTF-8 string", client->username)); return FALSE; } if (!silc_identifier_verify(hostname, strlen(hostname), SILC_STRING_UTF8, 256)) { SILC_LOG_ERROR(("Malformed hostname '%s'. Hostname must be UTF-8 string", client->hostname)); return FALSE; } if (!silc_utf8_valid(realname, strlen(realname))) { SILC_LOG_ERROR(("Malformed realname '%s'. Realname must be UTF-8 string", client->realname)); return FALSE; } /* Take the name strings */ client->username = strdup(username); client->hostname = strdup(hostname); client->realname = strdup(realname); if (!username || !hostname || !realname) return FALSE; client->internal->ftp_sessions = silc_dlist_init(); if (!client->internal->ftp_sessions) return FALSE; if (!client->internal->params->dont_register_crypto_library) { /* Initialize the crypto library. If application has done this already this has no effect. Also, we will not be overriding something application might have registered earlier. */ silc_cipher_register_default(); silc_pkcs_register_default(); silc_hash_register_default(); silc_hmac_register_default(); } /* Initialize random number generator */ client->rng = silc_rng_alloc(); if (!client->rng) return FALSE; silc_rng_init(client->rng); silc_rng_global_init(client->rng); /* Initialize the scheduler */ client->schedule = silc_schedule_init(0, client); if (!client->schedule) return FALSE; /* Allocate client lock */ silc_mutex_alloc(&client->internal->lock); /* Register commands */ silc_client_commands_register(client); /* Start packet engine */ client->internal->packet_engine = silc_packet_engine_start(client->rng, FALSE, &silc_client_stream_cbs, client); if (!client->internal->packet_engine) return FALSE; /* Initialize and start the client FSM */ client->internal->running = running; client->internal->running_context = context; silc_fsm_init(&client->internal->fsm, client, NULL, NULL, client->schedule); silc_fsm_event_init(&client->internal->wait_event, &client->internal->fsm); silc_fsm_start_sync(&client->internal->fsm, silc_client_st_run); /* Signal the application when we are running */ client->internal->run_callback = TRUE; SILC_FSM_EVENT_SIGNAL(&client->internal->wait_event); return TRUE; }
static char silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd) { SilcServer server = cmd->server; SilcUInt32 len, id_len; unsigned char *id_data; char *nickname, *username, *realname; SilcID id; SilcClientEntry client; SilcIDCacheEntry cache = NULL; char nick[128 + 1], servername[256 + 1], uname[128 + 1]; int global = FALSE; const char *hostname, *ip; silc_socket_stream_get_info(silc_packet_stream_get_stream(cmd->sock), NULL, &hostname, &ip, NULL); id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len); nickname = silc_argument_get_arg_type(cmd->args, 3, &len); username = silc_argument_get_arg_type(cmd->args, 4, &len); if (!id_data || !nickname || !username) return FALSE; realname = silc_argument_get_arg_type(cmd->args, 5, &len); if (!silc_id_payload_parse_id(id_data, id_len, &id)) return FALSE; /* Check if we have this client cached already. */ client = silc_idlist_find_client_by_id(server->local_list, SILC_ID_GET_ID(id), FALSE, &cache); if (!client) { client = silc_idlist_find_client_by_id(server->global_list, SILC_ID_GET_ID(id), FALSE, &cache); global = TRUE; } if (!client) { /* If router did not find such Client ID in its lists then this must be bogus client or some router in the net is buggy. */ if (server->server_type != SILC_SERVER) return FALSE; /* Take hostname out of nick string if it includes it. */ silc_parse_userfqdn(nickname, nick, sizeof(nick), servername, sizeof(servername)); /* We don't have that client anywhere, add it. The client is added to global list since server didn't have it in the lists so it must be global. */ client = silc_idlist_add_client(server->global_list, strdup(nick), username, strdup(realname), silc_id_dup(SILC_ID_GET_ID(id), SILC_ID_CLIENT), silc_packet_get_context(cmd->sock), NULL); if (!client) { SILC_LOG_ERROR(("Could not add new client to the ID Cache")); return FALSE; } client->data.status |= SILC_IDLIST_STATUS_RESOLVED; client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; client->servername = servername[0] ? strdup(servername) : NULL; } else { /* We have the client already, update the data */ /* Check nickname */ silc_parse_userfqdn(nickname, nick, sizeof(nick), servername, sizeof(servername)); nickname = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8, 128, NULL); if (!nickname) { SILC_LOG_ERROR(("Malformed nickname '%s' received in WHOWAS reply " "from %s", nick, hostname ? hostname : "")); return FALSE; } /* Check username */ silc_parse_userfqdn(username, uname, sizeof(uname), NULL, 0); if (!silc_identifier_verify(uname, strlen(uname), SILC_STRING_UTF8, 128)) return FALSE; silc_free(client->nickname); silc_free(client->username); silc_free(client->servername); client->nickname = strdup(nick); client->username = strdup(username); client->servername = servername[0] ? strdup(servername) : NULL; client->data.status |= SILC_IDLIST_STATUS_RESOLVED; client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; /* Update cache entry */ silc_idcache_update_by_context(global ? server->global_list->clients : server->local_list->clients, client, NULL, nickname, TRUE); } /* If client is global and is not on any channel then add that we'll expire the entry after a while. */ if (global) { client = silc_idlist_find_client_by_id(server->global_list, client->id, FALSE, &cache); if (client && !silc_hash_table_count(client->channels)) { client->data.created = silc_time(); silc_dlist_del(server->expired_clients, client); silc_dlist_add(server->expired_clients, client); } } return TRUE; }
static char silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd) { SilcServer server = cmd->server; SilcUInt32 len, id_len; unsigned char *id_data; char *name, *info; SilcClientID client_id; SilcServerID server_id; SilcChannelID channel_id; SilcClientEntry client; SilcServerEntry server_entry; SilcChannelEntry channel; char global = FALSE; char nick[128 + 1]; SilcIDPayload idp = NULL; SilcIdType id_type; id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len); if (!id_data) return FALSE; idp = silc_id_payload_parse(id_data, id_len); if (!idp) return FALSE; name = silc_argument_get_arg_type(cmd->args, 3, &len); info = silc_argument_get_arg_type(cmd->args, 4, &len); id_type = silc_id_payload_get_type(idp); switch (id_type) { case SILC_ID_CLIENT: if (!silc_id_payload_get_id(idp, &client_id, sizeof(client_id))) goto error; SILC_LOG_DEBUG(("Received client information")); client = silc_idlist_find_client_by_id(server->local_list, &client_id, FALSE, NULL); if (!client) { client = silc_idlist_find_client_by_id(server->global_list, &client_id, FALSE, NULL); global = TRUE; } if (!client) { /* If router did not find such Client ID in its lists then this must be bogus client or some router in the net is buggy. */ if (server->server_type != SILC_SERVER) goto error; /* Take nickname */ if (name) silc_parse_userfqdn(name, nick, sizeof(nick), NULL, 0); /* We don't have that client anywhere, add it. The client is added to global list since server didn't have it in the lists so it must be global. */ client = silc_idlist_add_client(server->global_list, nick[0] ? strdup(nick) : NULL, info ? strdup(info) : NULL, NULL, silc_id_dup(&client_id, SILC_ID_CLIENT), silc_packet_get_context(cmd->sock), NULL); if (!client) { SILC_LOG_ERROR(("Could not add new client to the ID Cache")); goto error; } client->data.status |= SILC_IDLIST_STATUS_REGISTERED; client->data.status |= SILC_IDLIST_STATUS_RESOLVED; client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; SILC_LOG_DEBUG(("stat.clients %d->%d", server->stat.clients, server->stat.clients + 1)); server->stat.clients++; } else { /* We have the client already, update the data */ SILC_LOG_DEBUG(("Updating client data")); /* Take nickname */ if (name) { silc_parse_userfqdn(name, nick, sizeof(nick), NULL, 0); /* Check nickname */ name = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8, 128, NULL); if (!name) { SILC_LOG_ERROR(("Malformed nickname '%s' received in IDENTIFY " "reply ", nick)); return FALSE; } silc_free(client->nickname); client->nickname = strdup(nick); /* Update the context */ silc_idcache_update_by_context(global ? server->global_list->clients : server->local_list->clients, client, NULL, name, TRUE); } if (info) { silc_free(client->username); client->username = strdup(info); } client->data.status |= SILC_IDLIST_STATUS_RESOLVED; client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; } break; case SILC_ID_SERVER: if (!name) goto error; if (!silc_id_payload_get_id(idp, &server_id, sizeof(server_id))) goto error; SILC_LOG_DEBUG(("Received server information")); server_entry = silc_idlist_find_server_by_id(server->local_list, &server_id, FALSE, NULL); if (!server_entry) server_entry = silc_idlist_find_server_by_id(server->global_list, &server_id, FALSE, NULL); if (!server_entry) { /* If router did not find such Server ID in its lists then this must be bogus server or some router in the net is buggy. */ if (server->server_type != SILC_SERVER) goto error; /* We don't have that server anywhere, add it. */ server_entry = silc_idlist_add_server(server->global_list, strdup(name), 0, silc_id_dup(&server_id, SILC_ID_SERVER), server->router, SILC_PRIMARY_ROUTE(server)); if (!server_entry) goto error; server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED; server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED; server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; } break; case SILC_ID_CHANNEL: if (!name) goto error; if (!silc_id_payload_get_id(idp, &channel_id, sizeof(channel_id))) goto error; SILC_LOG_DEBUG(("Received channel information")); /* Check channel name */ info = silc_channel_name_check(name, strlen(name), SILC_STRING_UTF8, 256, NULL); if (!info) goto error; channel = silc_idlist_find_channel_by_name(server->local_list, info, NULL); if (!channel) channel = silc_idlist_find_channel_by_name(server->global_list, info, NULL); if (!channel) { /* If router did not find such Channel ID in its lists then this must be bogus channel or some router in the net is buggy. */ if (server->server_type != SILC_SERVER) { silc_free(info); goto error; } /* We don't have that channel anywhere, add it. */ channel = silc_idlist_add_channel(server->global_list, strdup(name), SILC_CHANNEL_MODE_NONE, silc_id_dup(&channel_id, SILC_ID_CHANNEL), server->router, NULL, NULL, 0); if (!channel) { silc_free(info); goto error; } silc_free(info); } break; } silc_id_payload_free(idp); return TRUE; error: silc_id_payload_free(idp); return FALSE; }
SilcStream silc_net_udp_connect(const char *local_ip_addr, int local_port, const char *remote_ip_addr, int remote_port, SilcSchedule schedule) { SilcStream stream; SilcSockaddr server; int sock = -1, rval; const char *ipany = "0.0.0.0"; SILC_LOG_DEBUG(("Creating UDP stream")); if (!schedule) goto err; /* Bind to local addresses */ SILC_LOG_DEBUG(("Binding to local address %s", local_ip_addr ? local_ip_addr : ipany)); /* Set sockaddr for server */ if (!silc_net_set_sockaddr(&server, local_ip_addr ? local_ip_addr : ipany, local_port)) goto err; /* Create the socket */ sock = socket(server.sin.sin_family, SOCK_DGRAM, 0); if (sock < 0) { SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno))); goto err; } /* Set the socket options */ rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1); if (rval < 0) { SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno))); goto err; } #ifdef SO_REUSEPORT rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEPORT, 1); if (rval < 0) { SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno))); goto err; } #endif /* SO_REUSEPORT */ /* Bind the listener socket */ rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server)); if (rval < 0) { SILC_LOG_DEBUG(("Cannot bind socket: %s", strerror(errno))); goto err; } /* Set to connected state if remote address is provided. */ if (remote_ip_addr && remote_port) { if (!silc_net_set_sockaddr(&server, remote_ip_addr, remote_port)) goto err; rval = connect(sock, &server.sa, SIZEOF_SOCKADDR(server)); if (rval < 0) { SILC_LOG_DEBUG(("Cannot connect UDP stream: %s", strerror(errno))); goto err; } } /* Set send and receive buffer size */ #ifdef SO_SNDBUF rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_SNDBUF, 765535); if (rval < 0) { rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_SNDBUF, 65535); if (rval < 0) { SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno))); goto err; } } #endif /* SO_SNDBUF */ #ifdef SO_RCVBUF rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_RCVBUF, 765535); if (rval < 0) { rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_RCVBUF, 65535); if (rval < 0) { SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno))); goto err; } } #endif /* SO_RCVBUF */ /* Encapsulate into socket stream */ stream = silc_socket_udp_stream_create(sock, local_ip_addr ? silc_net_is_ip6(local_ip_addr) : FALSE, remote_ip_addr ? TRUE : FALSE, schedule); if (!stream) goto err; SILC_LOG_DEBUG(("UDP stream created, fd=%d", sock)); return stream; err: if (sock != -1) close(sock); return NULL; }
SilcPrivateKey silc_acc_private_key(SilcAccelerator acc, SilcPrivateKey private_key) { SilcPrivateKey privkey; SilcAcceleratorPrivateKey acc_privkey; const SilcPKCSAlgorithm *alg; int i; if (!acc || !private_key) return NULL; SILC_LOG_DEBUG(("Accelerate private key %p with accelerator %s", private_key, acc->name)); if (!acc->pkcs) { SILC_LOG_ERROR(("Accelerator '%s' does not support private key " "acceleration", acc->name)); return NULL; } if (silc_acc_get_private_key(NULL, private_key)) { SILC_LOG_DEBUG(("Private key %p is already accelerated", private_key)); return NULL; } /* Check that accelerator supports this private key algorithm */ alg = silc_pkcs_get_algorithm(private_key); if (!alg) return NULL; for (i = 0; acc->pkcs[i].name; i++) { if ((!strcmp(acc->pkcs[i].name, alg->name) && !strcmp(acc->pkcs[i].scheme, alg->scheme)) || !strcmp(acc->pkcs[i].name, "any")) { alg = NULL; break; } } if (alg) { SILC_LOG_DEBUG(("Accelerator %s does not support %s/%s acceleration", acc->name, alg->name, alg->scheme)); return NULL; } privkey = silc_calloc(1, sizeof(*privkey)); if (!privkey) return NULL; /* Allocate PKCS operations */ privkey->pkcs = silc_calloc(1, sizeof(*privkey->pkcs)); if (!privkey->pkcs) { silc_free(privkey); return NULL; } *privkey->pkcs = silc_acc_pkcs; privkey->pkcs->type = silc_pkcs_get_type(private_key); privkey->alg = silc_pkcs_get_algorithm(private_key); /* Allocate accelerator public key */ acc_privkey = silc_calloc(1, sizeof(*acc_privkey)); if (!acc_privkey) { silc_free(privkey->pkcs); silc_free(privkey); return NULL; } acc_privkey->magic = SILC_ACC_KEY_MAGIC; acc_privkey->accelerated = private_key; acc_privkey->acc = acc; acc_privkey->pkcs_index = i; /* Accelerate the public key. Returns accelerator context. The import_public_key operation is used to accelerate the key. */ if (!acc->pkcs[i].import_private_key(&acc->pkcs[i], private_key, 0, &acc_privkey->context)) { SILC_LOG_ERROR(("Error accelerating private key with accelerator '%s'", acc->name)); silc_free(acc_privkey); silc_free(privkey->pkcs); silc_free(privkey); return NULL; } privkey->private_key = acc_privkey; SILC_LOG_DEBUG(("New accelerated private key %p", privkey)); return privkey; }
SilcNetListener silc_net_tcp_create_listener2(const char *local_ip_addr, int *ports, SilcUInt32 port_count, SilcBool ignore_port_error, SilcBool lookup, SilcBool require_fqdn, SilcSchedule schedule, SilcNetCallback callback, void *context) { SilcNetListener listener = NULL; SilcSymbianTCPListener *l = NULL; TInetAddr server; TInt ret; int i; SILC_LOG_DEBUG(("Creating TCP listener")); if (!schedule) { schedule = silc_schedule_get_global(); if (!schedule) { silc_set_errno(SILC_ERR_INVALID_ARGUMENT); goto err; } } if (!callback) { silc_set_errno(SILC_ERR_INVALID_ARGUMENT); goto err; } listener = (SilcNetListener)silc_calloc(1, sizeof(*listener)); if (!listener) { callback(SILC_ERR_OUT_OF_MEMORY, NULL, context); return NULL; } listener->schedule = schedule; listener->callback = callback; listener->context = context; listener->require_fqdn = require_fqdn; listener->lookup = lookup; if (port_count > 0) { listener->socks = (SilcSocket *)silc_calloc(port_count, sizeof(*listener->socks)); if (!listener->socks) { callback(SILC_ERR_OUT_OF_MEMORY, NULL, context); return NULL; } } else { listener->socks = (SilcSocket *)silc_calloc(1, sizeof(*listener->socks)); if (!listener->socks) { callback(SILC_ERR_OUT_OF_MEMORY, NULL, context); return NULL; } port_count = 1; } /* Bind to ports */ for (i = 0; i < port_count; i++) { SILC_LOG_DEBUG(("Binding to local address %s:%d", local_ip_addr ? local_ip_addr : "0.0.0.0", ports ? ports[i] : 0)); l = new SilcSymbianTCPListener; if (!l) goto err; /* Connect to socket server */ ret = l->ss.Connect(); if (ret != KErrNone) goto err; #ifdef SILC_THREADS /* Make our socket shareable between threads */ l->ss.ShareAuto(); #endif /* SILC_THREADS */ /* Set listener address */ if (!silc_net_set_sockaddr(&server, local_ip_addr, ports ? ports[i] : 0)) { if (ignore_port_error) { delete l; continue; } goto err; } /* Create the socket */ ret = l->sock.Open(l->ss, KAfInet, KSockStream, KProtocolInetTcp); if (ret != KErrNone) { if (ignore_port_error) { delete l; continue; } SILC_LOG_ERROR(("Cannot create socket, error %d", ret)); goto err; } /* Set the socket options */ ret = l->sock.SetOpt(KSoReuseAddr, KSolInetIp, 1); if (ret != KErrNone) { if (ignore_port_error) { delete l; continue; } SILC_LOG_ERROR(("Cannot set socket options, error %d", ret)); goto err; } /* Bind the listener socket */ ret = l->sock.Bind(server); if (ret != KErrNone) { if (ignore_port_error) { delete l; continue; } SILC_LOG_DEBUG(("Cannot bind socket, error %d", ret)); goto err; } /* Specify that we are listenning */ ret = l->sock.Listen(5); if (ret != KErrNone) { if (ignore_port_error) { delete l; continue; } SILC_LOG_ERROR(("Cannot set socket listenning, error %d", ret)); goto err; } l->Listen(); l->listener = listener; listener->socks[i] = (SilcSocket)l; listener->socks_count++; } if (ignore_port_error && !listener->socks_count) { l = NULL; goto err; } SILC_LOG_DEBUG(("TCP listener created")); return listener; err: if (l) delete l; if (callback) callback(SILC_ERR, NULL, context); if (listener) silc_net_close_listener(listener); return NULL; }
SilcCipher silc_acc_cipher(SilcAccelerator acc, SilcCipher cipher) { SilcCipher c; SilcAcceleratorCipher acc_cipher; const SilcCipherObject *alg; int i; if (!acc || !cipher) return NULL; SILC_LOG_DEBUG(("Accelerate cipher %p with accelerator %s", cipher, acc->name)); if (!acc->cipher) { SILC_LOG_ERROR(("Accelerator '%s' does not support cipher acceleration ", acc->name)); return NULL; } if (silc_acc_get_cipher(NULL, cipher)) { SILC_LOG_DEBUG(("Cipher %p is already accelerated", cipher)); return NULL; } /* Check that accelerator supports this cipher algorithm */ alg = cipher->cipher; for (i = 0; acc->cipher[i].alg_name; i++) { if ((!strcmp(acc->cipher[i].alg_name, alg->alg_name) || !strcmp(acc->cipher[i].alg_name, "any")) && (acc->cipher[i].mode == alg->mode || acc->cipher[i].mode == 0) && (acc->cipher[i].key_len == alg->key_len || acc->cipher[i].key_len == 0)) { alg = NULL; break; } } if (alg) { SILC_LOG_DEBUG(("Accelerator %s does not support %s (mode %d) " "acceleration", acc->name, alg->name, alg->mode)); return NULL; } /* Allocate cipher context for the SILC Cipher API */ c = silc_calloc(1, sizeof(*c)); if (!c) return NULL; /* Allocate cipher operations */ c->cipher = silc_calloc(1, sizeof(SilcCipherObject)); if (!c->cipher) { silc_free(c); return NULL; } *c->cipher = silc_acc_ciph; /* Allocate cipher context */ c->context = acc_cipher = silc_calloc(1, sizeof(*acc_cipher)); if (!acc_cipher) { silc_free(c->cipher); silc_free(c); return NULL; } acc_cipher->cipher = cipher; /* Allocate the actual algorithm accelerator. */ acc_cipher->acc_cipher = silc_calloc(1, sizeof(*acc_cipher->acc_cipher)); if (!acc_cipher->acc_cipher) { silc_free(c->cipher); silc_free(c); silc_free(acc_cipher); } /* Initialize the algorithm accelerator */ acc_cipher->acc_cipher->context = acc->cipher[i].init((struct SilcCipherObjectStruct *)&acc->cipher[i]); if (!acc_cipher->acc_cipher->context) { silc_free(c->cipher); silc_free(c); silc_free(acc_cipher->acc_cipher); silc_free(acc_cipher); return NULL; } /* Allocate algorithm accelerator operations */ acc_cipher->acc_cipher->cipher = silc_calloc(1, sizeof(SilcCipherObject)); if (!acc_cipher->acc_cipher->cipher) { silc_free(c->cipher); silc_free(c); silc_free(acc_cipher->acc_cipher->context); silc_free(acc_cipher->acc_cipher); silc_free(acc_cipher); return NULL; } /* Set algorithm accelerator operations. They are copied from the accelerator, but algorithm specific things come from associated cipher. This way accelerators get the associated cipher details. */ *acc_cipher->acc_cipher->cipher = acc->cipher[i]; acc_cipher->acc_cipher->cipher->alg_name = (char *)silc_cipher_get_alg_name(cipher); acc_cipher->acc_cipher->cipher->key_len = silc_cipher_get_key_len(cipher); acc_cipher->acc_cipher->cipher->block_len = silc_cipher_get_block_len(cipher); acc_cipher->acc_cipher->cipher->iv_len = silc_cipher_get_iv_len(cipher); /* Set for the accelerator cipher too */ c->cipher->key_len = silc_cipher_get_key_len(cipher); c->cipher->block_len = silc_cipher_get_block_len(cipher); c->cipher->iv_len = silc_cipher_get_iv_len(cipher); /* Start the accelerator. The accelerator is started by setting key with NULL key. */ if (!silc_cipher_set_key(acc_cipher->acc_cipher, NULL, 0, FALSE)) { SilcCipherObject *ops = acc_cipher->acc_cipher->cipher; silc_cipher_free(acc_cipher->acc_cipher); silc_free(ops); silc_free(c->cipher); silc_free(c); return NULL; } SILC_LOG_DEBUG(("New accelerated cipher %p", c)); return c; }
SilcBool silc_client_send_channel_message(SilcClient client, SilcClientConnection conn, SilcChannelEntry channel, SilcChannelPrivateKey key, SilcMessageFlags flags, SilcHash hash, unsigned char *data, SilcUInt32 data_len) { SilcChannelUser chu; SilcBuffer buffer; SilcCipher cipher; SilcHmac hmac; SilcBool ret; SilcID sid, rid; SILC_LOG_DEBUG(("Sending channel message")); if (silc_unlikely(!client || !conn || !channel)) return FALSE; if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash)) return FALSE; if (silc_unlikely(conn->internal->disconnected)) return FALSE; chu = silc_client_on_channel(channel, conn->local_entry); if (silc_unlikely(!chu)) { client->internal->ops->say(conn->client, conn, SILC_CLIENT_MESSAGE_AUDIT, "Cannot talk to channel: not joined"); return FALSE; } /* Check if it is allowed to send messages to this channel by us. */ if (silc_unlikely(channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && !chu->mode)) return FALSE; if (silc_unlikely(channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS && chu->mode & SILC_CHANNEL_UMODE_CHANOP && !(chu->mode & SILC_CHANNEL_UMODE_CHANFO))) return FALSE; if (silc_unlikely(chu->mode & SILC_CHANNEL_UMODE_QUIET)) return FALSE; /* Take the key to be used */ if (channel->internal.private_keys) { if (key) { /* Use key application specified */ cipher = key->send_key; hmac = key->hmac; } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY && channel->internal.curr_key) { /* Use current private key */ cipher = channel->internal.curr_key->send_key; hmac = channel->internal.curr_key->hmac; } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY && !channel->internal.curr_key && channel->internal.private_keys) { /* Use just some private key since we don't know what to use and private keys are set. */ silc_dlist_start(channel->internal.private_keys); key = silc_dlist_get(channel->internal.private_keys); cipher = key->send_key; hmac = key->hmac; /* Use this key as current private key */ channel->internal.curr_key = key; } else { /* Use normal channel key generated by the server */ cipher = channel->internal.send_key; hmac = channel->internal.hmac; } } else { /* Use normal channel key generated by the server */ cipher = channel->internal.send_key; hmac = channel->internal.hmac; } if (silc_unlikely(!cipher || !hmac)) { SILC_LOG_ERROR(("No cipher and HMAC for channel")); return FALSE; } /* Encode the message payload. This also encrypts the message payload. */ sid.type = SILC_ID_CLIENT; sid.u.client_id = chu->client->id; rid.type = SILC_ID_CHANNEL; rid.u.channel_id = chu->channel->id; buffer = silc_message_payload_encode(flags, data, data_len, TRUE, FALSE, cipher, hmac, client->rng, NULL, conn->private_key, hash, &sid, &rid, NULL); if (silc_unlikely(!buffer)) { SILC_LOG_ERROR(("Error encoding channel message")); return FALSE; } /* Send the channel message */ ret = silc_packet_send_ext(conn->stream, SILC_PACKET_CHANNEL_MESSAGE, 0, 0, NULL, SILC_ID_CHANNEL, &channel->id, silc_buffer_datalen(buffer), NULL, NULL); silc_buffer_free(buffer); return ret; }
SilcStream silc_net_udp_connect(const char *local_ip_addr, int local_port, const char *remote_ip_addr, int remote_port, SilcSchedule schedule) { SilcSymbianSocket *s; SilcStream stream; TInetAddr local, remote; TRequestStatus status; RSocket *sock = NULL; RSocketServ *ss = NULL; TInt ret; SILC_LOG_DEBUG(("Creating UDP stream")); if (!schedule) { schedule = silc_schedule_get_global(); if (!schedule) { silc_set_errno(SILC_ERR_INVALID_ARGUMENT); goto err; } } SILC_LOG_DEBUG(("Binding to local address %s", local_ip_addr ? local_ip_addr : "0.0.0.0")); sock = new RSocket; if (!sock) goto err; ss = new RSocketServ; if (!ss) goto err; /* Open socket server */ ret = ss->Connect(); if (ret != KErrNone) goto err; #ifdef SILC_THREADS /* Make our socket shareable between threads */ ss->ShareAuto(); #endif /* SILC_THREADS */ /* Get local bind address */ if (!silc_net_set_sockaddr(&local, local_ip_addr, local_port)) goto err; /* Create the socket */ ret = sock->Open(*ss, KAfInet, KSockDatagram, KProtocolInetUdp); if (ret != KErrNone) { SILC_LOG_ERROR(("Cannot create socket")); goto err; } /* Set the socket options */ sock->SetOpt(KSoReuseAddr, KSolInetIp, 1); /* Bind the listener socket */ ret = sock->Bind(local); if (ret != KErrNone) { SILC_LOG_DEBUG(("Cannot bind socket")); goto err; } /* Set to connected state if remote address is provided. */ if (remote_ip_addr && remote_port) { if (silc_net_set_sockaddr(&remote, remote_ip_addr, remote_port)) { sock->Connect(remote, status); if (status != KErrNone) { SILC_LOG_DEBUG(("Cannot connect UDP stream")); goto err; } } } /* Encapsulate into socket stream */ s = silc_create_symbian_socket(sock, ss); if (!s) goto err; stream = silc_socket_udp_stream_create((SilcSocket)s, local_ip_addr ? silc_net_is_ip6(local_ip_addr) : FALSE, remote_ip_addr ? TRUE : FALSE, schedule); if (!stream) goto err; SILC_LOG_DEBUG(("UDP stream created, fd=%d", sock)); return stream; err: if (sock) delete sock; if (ss) { ss->Close(); delete ss; } return NULL; }
SilcNetListener silc_net_tcp_create_listener(const char **local_ip_addr, SilcUInt32 local_ip_count, int port, SilcBool lookup, SilcBool require_fqdn, SilcSchedule schedule, SilcNetCallback callback, void *context) { SilcNetListener listener = NULL; SilcSockaddr server; int i, sock, rval; const char *ipany = "0.0.0.0"; SILC_LOG_DEBUG(("Creating TCP listener")); if (port < 0 || !schedule || !callback) goto err; listener = silc_calloc(1, sizeof(*listener)); if (!listener) return NULL; listener->schedule = schedule; listener->callback = callback; listener->context = context; listener->require_fqdn = require_fqdn; listener->lookup = lookup; if (local_ip_count > 0) { listener->socks = silc_calloc(local_ip_count, sizeof(*listener->socks)); if (!listener->socks) return NULL; } else { listener->socks = silc_calloc(1, sizeof(*listener->socks)); if (!listener->socks) return NULL; local_ip_count = 1; } /* Bind to local addresses */ for (i = 0; i < local_ip_count; i++) { SILC_LOG_DEBUG(("Binding to local address %s:%d", local_ip_addr ? local_ip_addr[i] : ipany, port)); /* Set sockaddr for server */ if (!silc_net_set_sockaddr(&server, local_ip_addr ? local_ip_addr[i] : ipany, port)) goto err; /* Create the socket */ sock = socket(server.sin.sin_family, SOCK_STREAM, 0); if (sock < 0) { SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno))); goto err; } /* Set the socket options */ rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1); if (rval < 0) { SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno))); close(sock); goto err; } /* Bind the listener socket */ rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server)); if (rval < 0) { SILC_LOG_ERROR(("Cannot bind socket: %s", strerror(errno))); close(sock); goto err; } /* Specify that we are listenning */ rval = listen(sock, 64); if (rval < 0) { SILC_LOG_ERROR(("Cannot set socket listenning: %s", strerror(errno))); close(sock); goto err; } /* Set the server socket to non-blocking mode */ silc_net_set_socket_nonblock(sock); /* Schedule for incoming connections */ silc_schedule_task_add_fd(schedule, sock, silc_net_accept, listener); SILC_LOG_DEBUG(("TCP listener created, fd=%d", sock)); listener->socks[i] = sock; listener->socks_count++; } return listener; err: if (listener) silc_net_close_listener(listener); return NULL; }