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; }
void *silc_realloc(void *ptr, size_t size) { void *addr; if (silc_unlikely(size <= 0 || size >= SILC_MAX_ALLOC)) { if (size == 0) silc_set_errno_nofail(SILC_ERR_ZERO_ALLOCATION); else silc_set_errno_reason_nofail(SILC_ERR_TOO_LARGE_ALLOCATION, "Allocation by %d", size); return NULL; } addr = realloc(ptr, size); if (silc_unlikely(!addr)) silc_set_errno_nofail(SILC_ERR_OUT_OF_MEMORY); return addr; }
void *silc_memdup(const void *ptr, size_t size) { unsigned char *addr; addr = silc_malloc(size + 1); if (silc_unlikely(!addr)) { silc_set_errno_nofail(SILC_ERR_OUT_OF_MEMORY); return NULL; } memcpy((void *)addr, ptr, size); addr[size] = '\0'; return (void *)addr; }
void *silc_scalloc(SilcStack stack, SilcUInt32 items, SilcUInt32 size) { unsigned char *addr; if (!stack) return silc_calloc(items, size); addr = silc_stack_malloc(stack, items * size); if (silc_unlikely(!addr)) return NULL; memset(addr, 0, items * size); return (void *)addr; }
SilcBool silc_file_fstat(int fd, SilcFileStat return_stat) { struct stat status; if (silc_unlikely(fstat(fd, &status) != 0)) { silc_set_errno_posix(errno); return FALSE; } if (return_stat) silc_file_fill_stat(&status, return_stat); return TRUE; }
void *silc_smemdup(SilcStack stack, const void *ptr, SilcUInt32 size) { unsigned char *addr; if (!stack) return silc_memdup(ptr, size); addr = silc_stack_malloc(stack, size + 1); if (silc_unlikely(!addr)) return NULL; memcpy((void *)addr, ptr, size); addr[size] = '\0'; return (void *)addr; }
SilcBool silc_file_stat(const char *filename, SilcBool follow_symlinks, SilcFileStat return_stat) { struct stat status; if (silc_unlikely(!filename)) { silc_set_errno(SILC_ERR_INVALID_ARGUMENT); return FALSE; } SILC_LOG_DEBUG(("Get status for file '%s'", filename)); if (!follow_symlinks) { if (silc_unlikely(stat(filename, &status) != 0)) { silc_set_errno_posix(errno); return FALSE; } } else { #ifdef HAVE_LSTAT if (silc_unlikely(lstat(filename, &status) != 0)) { silc_set_errno_posix(errno); return FALSE; } #else if (silc_unlikely(stat(filename, &status) != 0)) { silc_set_errno_posix(errno); return FALSE; } #endif /* HAVE_LSTAT */ } if (return_stat) silc_file_fill_stat(&status, return_stat); return TRUE; }
char *silc_sstrdup(SilcStack stack, const char *str) { SilcInt32 size = strlen(str); char *addr; if (!stack) return silc_memdup(str, size); addr = silc_stack_malloc(stack, size + 1); if (silc_unlikely(!addr)) return NULL; memcpy((void *)addr, str, size); addr[size] = '\0'; return addr; }
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; }
static void silc_buffer_stream_io(SilcStream stream, SilcStreamStatus status, void *context) { SilcBufferStream bs = context; SilcBuffer buffer = NULL; SilcUInt32 buf_len; int ret, len; if (bs->closed) return; if (status == SILC_STREAM_CAN_READ) { /* Read data */ SILC_LOG_DEBUG(("Read data from buffer stream %p", bs)); while ((ret = silc_stream_read(bs->stream, bs->inbuf->tail, silc_buffer_taillen(bs->inbuf))) > 0) { if (!buffer) { buffer = silc_buffer_alloc(0); if (!buffer) return; } silc_buffer_pull_tail(bs->inbuf, ret); /* Parse the buffer */ while ((len = silc_buffer_unformat(bs->inbuf, SILC_STR_BUFFER_ALLOC(buffer), SILC_STR_END)) > 0) { /* Deliver the buffer */ SILC_LOG_HEXDUMP(("Received buffer, size %d", silc_buffer_len(buffer)), silc_buffer_data(buffer), silc_buffer_len(buffer)); bs->receiver(SILC_OK, (SilcStream)bs, buffer, bs->context); silc_buffer_pull(bs->inbuf, len); buffer = silc_buffer_alloc(0); if (!buffer) return; } if (silc_buffer_len(bs->inbuf) > 0) { /* Not complete buffer, read more data */ buf_len = 4; if (silc_buffer_len(bs->inbuf) >= 4) { SILC_GET32_MSB(buf_len, bs->inbuf->data); SILC_LOG_DEBUG(("Incomplete buffer, wait for rest, buffer size %d", buf_len)); } /* Enlarge inbuf if needed */ if (silc_buffer_taillen(bs->inbuf) < buf_len) silc_buffer_realloc(bs->inbuf, silc_buffer_truelen(bs->inbuf) + buf_len); continue; } /* All data read, read more */ silc_buffer_reset(bs->inbuf); } silc_buffer_free(buffer); if (ret == 0 || ret == -2) { bs->receiver(silc_errno, (SilcStream)bs, NULL, bs->context); return; } } else { /* Write any pending data */ SILC_LOG_DEBUG(("Write pending data to buffer stream %p", bs)); while (silc_buffer_len(&bs->queue) > 0) { ret = silc_stream_write(bs->stream, silc_buffer_data(&bs->queue), silc_buffer_len(&bs->queue)); if (silc_unlikely(ret == 0)) return; if (silc_unlikely(ret == -2)) return; if (silc_unlikely(ret == -1)) { SILC_LOG_DEBUG(("Buffer stream %p would block, send later", bs)); return; } /* Wrote data */ silc_buffer_pull(&bs->queue, ret); } memset(&bs->queue, 0, sizeof(bs->queue)); silc_buffer_reset(bs->outbuf); } }
SilcBool silc_buffer_stream_send(SilcStream stream, SilcBuffer buffer) { SilcBufferStream bs = stream; int ret; SILC_LOG_HEXDUMP(("Send to buffer stream %p %d bytes", bs, silc_buffer_len(buffer)), silc_buffer_data(buffer), silc_buffer_len(buffer)); if (silc_unlikely(!SILC_IS_BUFFER_STREAM(bs))) { silc_set_errno(SILC_ERR_INVALID_ARGUMENT); return FALSE; } if (silc_unlikely(!buffer)) { silc_set_errno(SILC_ERR_INVALID_ARGUMENT); return FALSE; } if (silc_unlikely(bs->closed)) { SILC_LOG_DEBUG(("Buffer stream %p is closed", bs)); silc_set_errno(SILC_ERR_NOT_VALID); return FALSE; } /* Put to queue */ if (silc_buffer_format(bs->outbuf, SILC_STR_ADVANCE, SILC_STR_BUFFER(buffer), SILC_STR_END) < 0) return FALSE; ret = silc_buffer_headlen(&bs->queue); bs->queue.head = bs->outbuf->head; bs->queue.data = bs->queue.head + ret; bs->queue.tail = bs->outbuf->data; bs->queue.end = bs->outbuf->end; /* Write the queue buffer */ while (silc_buffer_len(&bs->queue) > 0) { ret = silc_stream_write(bs->stream, silc_buffer_data(&bs->queue), silc_buffer_len(&bs->queue)); if (silc_unlikely(ret == 0)) return FALSE; if (silc_unlikely(ret == -2)) return FALSE; if (silc_unlikely(ret == -1)) { SILC_LOG_DEBUG(("Buffer stream %p would block, send later", bs)); return TRUE; } /* Wrote data */ silc_buffer_pull(&bs->queue, ret); } memset(&bs->queue, 0, sizeof(bs->queue)); silc_buffer_reset(bs->outbuf); SILC_LOG_DEBUG(("Buffer sent to buffer stream %p", bs)); return TRUE; }