|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* buffer.c - buffer functions
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* This file is part of the SSH Library
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* The SSH Library is free software; you can redistribute it and/or modify
|
|
Packit Service |
31306d |
* it under the terms of the GNU Lesser General Public License as published by
|
|
Packit Service |
31306d |
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
|
Packit Service |
31306d |
* option) any later version.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* The SSH Library is distributed in the hope that it will be useful, but
|
|
Packit Service |
31306d |
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
Packit Service |
31306d |
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
|
Packit Service |
31306d |
* License for more details.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit Service |
31306d |
* along with the SSH Library; see the file COPYING. If not, write to
|
|
Packit Service |
31306d |
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
Packit Service |
31306d |
* MA 02111-1307, USA.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#include "config.h"
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#include <limits.h>
|
|
Packit Service |
31306d |
#include <stdarg.h>
|
|
Packit Service |
31306d |
#include <stdbool.h>
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#ifndef _WIN32
|
|
Packit Service |
31306d |
#include <netinet/in.h>
|
|
Packit Service |
31306d |
#include <arpa/inet.h>
|
|
Packit Service |
31306d |
#endif
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#include "libssh/priv.h"
|
|
Packit Service |
31306d |
#include "libssh/buffer.h"
|
|
Packit Service |
31306d |
#include "libssh/misc.h"
|
|
Packit Service |
31306d |
#include "libssh/bignum.h"
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* Describes a buffer state
|
|
Packit Service |
31306d |
* [XXXXXXXXXXXXDATA PAYLOAD XXXXXXXXXXXXXXXXXXXXXXXX]
|
|
Packit Service |
31306d |
* ^ ^ ^ ^]
|
|
Packit Service |
31306d |
* \_data points\_pos points here \_used points here | /
|
|
Packit Service |
31306d |
* here Allocated
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
struct ssh_buffer_struct {
|
|
Packit Service |
31306d |
bool secure;
|
|
Packit Service |
31306d |
size_t used;
|
|
Packit Service |
31306d |
size_t allocated;
|
|
Packit Service |
31306d |
size_t pos;
|
|
Packit Service |
31306d |
uint8_t *data;
|
|
Packit Service |
31306d |
};
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Buffer size maximum is 256M */
|
|
Packit Service |
31306d |
#define BUFFER_SIZE_MAX 0x10000000
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @defgroup libssh_buffer The SSH buffer functions.
|
|
Packit Service |
31306d |
* @ingroup libssh
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* Functions to handle SSH buffers.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @{
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#ifdef DEBUG_BUFFER
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @brief Check that preconditions and postconditions are valid.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buf The buffer to check.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
static void buffer_verify(ssh_buffer buf)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
bool do_abort = false;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (buf->data == NULL) {
|
|
Packit Service |
31306d |
return;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (buf->used > buf->allocated) {
|
|
Packit Service |
31306d |
fprintf(stderr,
|
|
Packit Service |
31306d |
"BUFFER ERROR: allocated %zu, used %zu\n",
|
|
Packit Service |
31306d |
buf->allocated,
|
|
Packit Service |
31306d |
buf->used);
|
|
Packit Service |
31306d |
do_abort = true;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (buf->pos > buf->used) {
|
|
Packit Service |
31306d |
fprintf(stderr,
|
|
Packit Service |
31306d |
"BUFFER ERROR: position %zu, used %zu\n",
|
|
Packit Service |
31306d |
buf->pos,
|
|
Packit Service |
31306d |
buf->used);
|
|
Packit Service |
31306d |
do_abort = true;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (buf->pos > buf->allocated) {
|
|
Packit Service |
31306d |
fprintf(stderr,
|
|
Packit Service |
31306d |
"BUFFER ERROR: position %zu, allocated %zu\n",
|
|
Packit Service |
31306d |
buf->pos,
|
|
Packit Service |
31306d |
buf->allocated);
|
|
Packit Service |
31306d |
do_abort = true;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (do_abort) {
|
|
Packit Service |
31306d |
abort();
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#else
|
|
Packit Service |
31306d |
#define buffer_verify(x)
|
|
Packit Service |
31306d |
#endif
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @brief Create a new SSH buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @return A newly initialized SSH buffer, NULL on error.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
struct ssh_buffer_struct *ssh_buffer_new(void)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
struct ssh_buffer_struct *buf = NULL;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buf = calloc(1, sizeof(struct ssh_buffer_struct));
|
|
Packit Service |
31306d |
if (buf == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* Always preallocate 64 bytes.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* -1 for ralloc_buffer magic.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
rc = ssh_buffer_allocate_size(buf, 64 - 1);
|
|
Packit Service |
31306d |
if (rc != 0) {
|
|
Packit Service |
31306d |
SAFE_FREE(buf);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
buffer_verify(buf);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return buf;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @brief Deallocate a SSH buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* \param[in] buffer The buffer to free.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
void ssh_buffer_free(struct ssh_buffer_struct *buffer)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
return;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (buffer->secure && buffer->allocated > 0) {
|
|
Packit Service |
31306d |
/* burn the data */
|
|
Packit Service |
31306d |
explicit_bzero(buffer->data, buffer->allocated);
|
|
Packit Service |
31306d |
SAFE_FREE(buffer->data);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
explicit_bzero(buffer, sizeof(struct ssh_buffer_struct));
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
SAFE_FREE(buffer->data);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SAFE_FREE(buffer);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @brief Sets the buffer as secure.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* A secure buffer will never leave cleartext data in the heap
|
|
Packit Service |
31306d |
* after being reallocated or freed.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer buffer to set secure.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
void ssh_buffer_set_secure(ssh_buffer buffer)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
buffer->secure = true;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
static int realloc_buffer(struct ssh_buffer_struct *buffer, size_t needed)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
size_t smallest = 1;
|
|
Packit Service |
31306d |
uint8_t *new = NULL;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Find the smallest power of two which is greater or equal to needed */
|
|
Packit Service |
31306d |
while(smallest <= needed) {
|
|
Packit Service |
31306d |
if (smallest == 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
smallest <<= 1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
needed = smallest;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (needed > BUFFER_SIZE_MAX) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (buffer->secure) {
|
|
Packit Service |
31306d |
new = malloc(needed);
|
|
Packit Service |
31306d |
if (new == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
memcpy(new, buffer->data, buffer->used);
|
|
Packit Service |
31306d |
explicit_bzero(buffer->data, buffer->used);
|
|
Packit Service |
31306d |
SAFE_FREE(buffer->data);
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
new = realloc(buffer->data, needed);
|
|
Packit Service |
31306d |
if (new == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
buffer->data = new;
|
|
Packit Service |
31306d |
buffer->allocated = needed;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/** @internal
|
|
Packit Service |
31306d |
* @brief shifts a buffer to remove unused data in the beginning
|
|
Packit Service |
31306d |
* @param buffer SSH buffer
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
static void buffer_shift(ssh_buffer buffer)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
size_t burn_pos = buffer->pos;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (buffer->pos == 0) {
|
|
Packit Service |
31306d |
return;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
memmove(buffer->data,
|
|
Packit Service |
31306d |
buffer->data + buffer->pos,
|
|
Packit Service |
31306d |
buffer->used - buffer->pos);
|
|
Packit Service |
31306d |
buffer->used -= buffer->pos;
|
|
Packit Service |
31306d |
buffer->pos = 0;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (buffer->secure) {
|
|
Packit Service |
31306d |
void *ptr = buffer->data + buffer->used;
|
|
Packit Service |
31306d |
explicit_bzero(ptr, burn_pos);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @brief Reinitialize a SSH buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* In case the buffer has exceeded 64K in size, the buffer will be reallocated
|
|
Packit Service |
31306d |
* to 64K.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to reinitialize.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @return 0 on success, < 0 on error.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_buffer_reinit(struct ssh_buffer_struct *buffer)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (buffer->secure && buffer->allocated > 0) {
|
|
Packit Service |
31306d |
explicit_bzero(buffer->data, buffer->allocated);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
buffer->used = 0;
|
|
Packit Service |
31306d |
buffer->pos = 0;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* If the buffer is bigger then 64K, reset it to 64K */
|
|
Packit Service |
31306d |
if (buffer->allocated > 65536) {
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* -1 for realloc_buffer magic */
|
|
Packit Service |
31306d |
rc = realloc_buffer(buffer, 65536 - 1);
|
|
Packit Service |
31306d |
if (rc != 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @brief Add data at the tail of a buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to add the data.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] data A pointer to the data to add.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] len The length of the data to add.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @return 0 on success, < 0 on error.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_buffer_add_data(struct ssh_buffer_struct *buffer, const void *data, uint32_t len)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (data == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (buffer->used + len < len) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (buffer->allocated < (buffer->used + len)) {
|
|
Packit Service |
31306d |
if(buffer->pos > 0)
|
|
Packit Service |
31306d |
buffer_shift(buffer);
|
|
Packit Service |
31306d |
if (realloc_buffer(buffer, buffer->used + len) < 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
memcpy(buffer->data+buffer->used, data, len);
|
|
Packit Service |
31306d |
buffer->used+=len;
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @brief Ensure the buffer has at least a certain preallocated size.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to enlarge.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] len The length to ensure as allocated.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @return 0 on success, < 0 on error.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_buffer_allocate_size(struct ssh_buffer_struct *buffer,
|
|
Packit Service |
31306d |
uint32_t len)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (buffer->allocated < len) {
|
|
Packit Service |
31306d |
if (buffer->pos > 0) {
|
|
Packit Service |
31306d |
buffer_shift(buffer);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (realloc_buffer(buffer, len) < 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @brief Allocate space for data at the tail of a buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to add the data.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] len The length of the data to add.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @return Pointer on the allocated space
|
|
Packit Service |
31306d |
* NULL on error.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
void *ssh_buffer_allocate(struct ssh_buffer_struct *buffer, uint32_t len)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
void *ptr;
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (buffer->used + len < len) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (buffer->allocated < (buffer->used + len)) {
|
|
Packit Service |
31306d |
if (buffer->pos > 0) {
|
|
Packit Service |
31306d |
buffer_shift(buffer);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (realloc_buffer(buffer, buffer->used + len) < 0) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ptr = buffer->data + buffer->used;
|
|
Packit Service |
31306d |
buffer->used+=len;
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return ptr;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @brief Add a SSH string to the tail of a buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to add the string.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] string The SSH String to add.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @return 0 on success, < 0 on error.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_buffer_add_ssh_string(struct ssh_buffer_struct *buffer,
|
|
Packit Service |
31306d |
struct ssh_string_struct *string) {
|
|
Packit Service |
31306d |
uint32_t len = 0;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (string == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
len = ssh_string_len(string);
|
|
Packit Service |
31306d |
if (ssh_buffer_add_data(buffer, string, len + sizeof(uint32_t)) < 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @brief Add a 32 bits unsigned integer to the tail of a buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to add the integer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] data The 32 bits integer to add.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @return 0 on success, -1 on error.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_buffer_add_u32(struct ssh_buffer_struct *buffer,uint32_t data)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_data(buffer, &data, sizeof(data));
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @brief Add a 16 bits unsigned integer to the tail of a buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to add the integer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] data The 16 bits integer to add.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @return 0 on success, -1 on error.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_buffer_add_u16(struct ssh_buffer_struct *buffer,uint16_t data)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_data(buffer, &data, sizeof(data));
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @brief Add a 64 bits unsigned integer to the tail of a buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to add the integer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] data The 64 bits integer to add.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @return 0 on success, -1 on error.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_buffer_add_u64(struct ssh_buffer_struct *buffer, uint64_t data)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_data(buffer, &data, sizeof(data));
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @brief Add a 8 bits unsigned integer to the tail of a buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to add the integer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] data The 8 bits integer to add.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @return 0 on success, -1 on error.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_buffer_add_u8(struct ssh_buffer_struct *buffer,uint8_t data)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_data(buffer, &data, sizeof(uint8_t));
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @brief Add data at the head of a buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to add the data.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] data The data to prepend.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] len The length of data to prepend.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @return 0 on success, -1 on error.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_buffer_prepend_data(struct ssh_buffer_struct *buffer, const void *data,
|
|
Packit Service |
31306d |
uint32_t len) {
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if(len <= buffer->pos){
|
|
Packit Service |
31306d |
/* It's possible to insert data between begin and pos */
|
|
Packit Service |
31306d |
memcpy(buffer->data + (buffer->pos - len), data, len);
|
|
Packit Service |
31306d |
buffer->pos -= len;
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
/* pos isn't high enough */
|
|
Packit Service |
31306d |
if (buffer->used - buffer->pos + len < len) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (buffer->allocated < (buffer->used - buffer->pos + len)) {
|
|
Packit Service |
31306d |
if (realloc_buffer(buffer, buffer->used - buffer->pos + len) < 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
memmove(buffer->data + len, buffer->data + buffer->pos, buffer->used - buffer->pos);
|
|
Packit Service |
31306d |
memcpy(buffer->data, data, len);
|
|
Packit Service |
31306d |
buffer->used += len - buffer->pos;
|
|
Packit Service |
31306d |
buffer->pos = 0;
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @brief Append data from a buffer to the tail of another buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The destination buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] source The source buffer to append. It doesn't take the
|
|
Packit Service |
31306d |
* position of the buffer into account.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @return 0 on success, -1 on error.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_buffer_add_buffer(struct ssh_buffer_struct *buffer,
|
|
Packit Service |
31306d |
struct ssh_buffer_struct *source)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_data(buffer,
|
|
Packit Service |
31306d |
ssh_buffer_get(source),
|
|
Packit Service |
31306d |
ssh_buffer_get_len(source));
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @brief Get a pointer to the head of a buffer at the current position.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to get the head pointer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @return A pointer to the data from current position.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @see ssh_buffer_get_len()
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
void *ssh_buffer_get(struct ssh_buffer_struct *buffer){
|
|
Packit Service |
31306d |
return buffer->data + buffer->pos;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @brief Get the length of the buffer from the current position.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to get the length from.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @return The length of the buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @see ssh_buffer_get()
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
uint32_t ssh_buffer_get_len(struct ssh_buffer_struct *buffer){
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
return buffer->used - buffer->pos;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @brief Advance the position in the buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* This has effect to "eat" bytes at head of the buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to advance the position.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] len The number of bytes to eat.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @return The new size of the buffer.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
uint32_t ssh_buffer_pass_bytes(struct ssh_buffer_struct *buffer, uint32_t len){
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (buffer->pos + len < len || buffer->used < buffer->pos + len) {
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer->pos+=len;
|
|
Packit Service |
31306d |
/* if the buffer is empty after having passed the whole bytes into it, we can clean it */
|
|
Packit Service |
31306d |
if(buffer->pos==buffer->used){
|
|
Packit Service |
31306d |
buffer->pos=0;
|
|
Packit Service |
31306d |
buffer->used=0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
return len;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @brief Cut the end of the buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to cut.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] len The number of bytes to remove from the tail.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @return The new size of the buffer.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
uint32_t ssh_buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t len){
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (buffer->used < len) {
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer->used-=len;
|
|
Packit Service |
31306d |
buffer_verify(buffer);
|
|
Packit Service |
31306d |
return len;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @brief Get the remaining data out of the buffer and adjust the read pointer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to read.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] data The data buffer where to store the data.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] len The length to read from the buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @returns 0 if there is not enough data in buffer, len otherwise.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
uint32_t ssh_buffer_get_data(struct ssh_buffer_struct *buffer, void *data, uint32_t len)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* Check for a integer overflow first, then check if not enough data is in
|
|
Packit Service |
31306d |
* the buffer.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
rc = ssh_buffer_validate_length(buffer, len);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
memcpy(data,buffer->data+buffer->pos,len);
|
|
Packit Service |
31306d |
buffer->pos+=len;
|
|
Packit Service |
31306d |
return len; /* no yet support for partial reads (is it really needed ?? ) */
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @brief Get a 8 bits unsigned int out of the buffer and adjusts the read
|
|
Packit Service |
31306d |
* pointer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to read.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] data A pointer to a uint8_t where to store the data.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @returns 0 if there is not enough data in buffer, 1 otherwise.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_buffer_get_u8(struct ssh_buffer_struct *buffer, uint8_t *data){
|
|
Packit Service |
31306d |
return ssh_buffer_get_data(buffer,data,sizeof(uint8_t));
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @brief gets a 32 bits unsigned int out of the buffer. Adjusts the read pointer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to read.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] data A pointer to a uint32_t where to store the data.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @returns 0 if there is not enough data in buffer, 4 otherwise.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_buffer_get_u32(struct ssh_buffer_struct *buffer, uint32_t *data){
|
|
Packit Service |
31306d |
return ssh_buffer_get_data(buffer,data,sizeof(uint32_t));
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @brief Get a 64 bits unsigned int out of the buffer and adjusts the read
|
|
Packit Service |
31306d |
* pointer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to read.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] data A pointer to a uint64_t where to store the data.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @returns 0 if there is not enough data in buffer, 8 otherwise.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_buffer_get_u64(struct ssh_buffer_struct *buffer, uint64_t *data){
|
|
Packit Service |
31306d |
return ssh_buffer_get_data(buffer,data,sizeof(uint64_t));
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @brief Valdiates that the given length can be obtained from the buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to read from.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] len The length to be checked.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @return SSH_OK if the length is valid, SSH_ERROR otherwise.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_buffer_validate_length(struct ssh_buffer_struct *buffer, size_t len)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
if (buffer->pos + len < len || buffer->pos + len > buffer->used) {
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return SSH_OK;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @brief Get a SSH String out of the buffer and adjusts the read pointer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to read.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @returns The SSH String, NULL on error.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
struct ssh_string_struct *
|
|
Packit Service |
31306d |
ssh_buffer_get_ssh_string(struct ssh_buffer_struct *buffer)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
uint32_t stringlen;
|
|
Packit Service |
31306d |
uint32_t hostlen;
|
|
Packit Service |
31306d |
struct ssh_string_struct *str = NULL;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_get_u32(buffer, &stringlen);
|
|
Packit Service |
31306d |
if (rc == 0) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
hostlen = ntohl(stringlen);
|
|
Packit Service |
31306d |
/* verify if there is enough space in buffer to get it */
|
|
Packit Service |
31306d |
rc = ssh_buffer_validate_length(buffer, hostlen);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
return NULL; /* it is indeed */
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
str = ssh_string_new(hostlen);
|
|
Packit Service |
31306d |
if (str == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
stringlen = ssh_buffer_get_data(buffer, ssh_string_data(str), hostlen);
|
|
Packit Service |
31306d |
if (stringlen != hostlen) {
|
|
Packit Service |
31306d |
/* should never happen */
|
|
Packit Service |
31306d |
SAFE_FREE(str);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return str;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @brief Pre-calculate the size we need for packing the buffer.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* This makes sure that enough memory is allocated for packing the buffer and
|
|
Packit Service |
31306d |
* we only have to do one memory allocation.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to allocate
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] format A format string of arguments.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] argc The number of arguments.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] ap The va_list of arguments.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @return SSH_OK on success, SSH_ERROR on error.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
static int ssh_buffer_pack_allocate_va(struct ssh_buffer_struct *buffer,
|
|
Packit Service |
31306d |
const char *format,
|
|
Packit Service |
31306d |
size_t argc,
|
|
Packit Service |
31306d |
va_list ap)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
const char *p = NULL;
|
|
Packit Service |
31306d |
ssh_string string = NULL;
|
|
Packit Service |
31306d |
char *cstring = NULL;
|
|
Packit Service |
31306d |
size_t needed_size = 0;
|
|
Packit Service |
31306d |
size_t len;
|
|
Packit Service |
31306d |
size_t count;
|
|
Packit Service |
31306d |
int rc = SSH_OK;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
for (p = format, count = 0; *p != '\0'; p++, count++) {
|
|
Packit Service |
31306d |
/* Invalid number of arguments passed */
|
|
Packit Service |
31306d |
if (count > argc) {
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
switch(*p) {
|
|
Packit Service |
31306d |
case 'b':
|
|
Packit Service |
31306d |
va_arg(ap, unsigned int);
|
|
Packit Service |
31306d |
needed_size += sizeof(uint8_t);
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'w':
|
|
Packit Service |
31306d |
va_arg(ap, unsigned int);
|
|
Packit Service |
31306d |
needed_size += sizeof(uint16_t);
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'd':
|
|
Packit Service |
31306d |
va_arg(ap, uint32_t);
|
|
Packit Service |
31306d |
needed_size += sizeof(uint32_t);
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'q':
|
|
Packit Service |
31306d |
va_arg(ap, uint64_t);
|
|
Packit Service |
31306d |
needed_size += sizeof(uint64_t);
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'S':
|
|
Packit Service |
31306d |
string = va_arg(ap, ssh_string);
|
|
Packit Service |
31306d |
needed_size += 4 + ssh_string_len(string);
|
|
Packit Service |
31306d |
string = NULL;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 's':
|
|
Packit Service |
31306d |
cstring = va_arg(ap, char *);
|
|
Packit Service |
31306d |
needed_size += sizeof(uint32_t) + strlen(cstring);
|
|
Packit Service |
31306d |
cstring = NULL;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'P':
|
|
Packit Service |
31306d |
len = va_arg(ap, size_t);
|
|
Packit Service |
31306d |
needed_size += len;
|
|
Packit Service |
31306d |
va_arg(ap, void *);
|
|
Packit Service |
31306d |
count++; /* increase argument count */
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'B':
|
|
Packit Service |
31306d |
va_arg(ap, bignum);
|
|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* Use a fixed size for a bignum
|
|
Packit Service |
31306d |
* (they should normaly be around 32)
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
needed_size += 64;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 't':
|
|
Packit Service |
31306d |
cstring = va_arg(ap, char *);
|
|
Packit Service |
31306d |
needed_size += strlen(cstring);
|
|
Packit Service |
31306d |
cstring = NULL;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_WARN, "Invalid buffer format %c", *p);
|
|
Packit Service |
31306d |
rc = SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (rc != SSH_OK){
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (argc != count) {
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (rc != SSH_ERROR){
|
|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* Check if our canary is intact, if not, something really bad happened.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
uint32_t canary = va_arg(ap, uint32_t);
|
|
Packit Service |
31306d |
if (canary != SSH_BUFFER_PACK_END) {
|
|
Packit Service |
31306d |
abort();
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_allocate_size(buffer, needed_size);
|
|
Packit Service |
31306d |
if (rc != 0) {
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return SSH_OK;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/** @internal
|
|
Packit Service |
31306d |
* @brief Add multiple values in a buffer on a single function call
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to add to
|
|
Packit Service |
31306d |
* @param[in] format A format string of arguments.
|
|
Packit Service |
31306d |
* @param[in] ap A va_list of arguments.
|
|
Packit Service |
31306d |
* @returns SSH_OK on success
|
|
Packit Service |
31306d |
* SSH_ERROR on error
|
|
Packit Service |
31306d |
* @see ssh_buffer_add_format() for format list values.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
|
Packit Service |
31306d |
const char *format,
|
|
Packit Service |
31306d |
size_t argc,
|
|
Packit Service |
31306d |
va_list ap)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
int rc = SSH_ERROR;
|
|
Packit Service |
31306d |
const char *p;
|
|
Packit Service |
31306d |
union {
|
|
Packit Service |
31306d |
uint8_t byte;
|
|
Packit Service |
31306d |
uint16_t word;
|
|
Packit Service |
31306d |
uint32_t dword;
|
|
Packit Service |
31306d |
uint64_t qword;
|
|
Packit Service |
31306d |
ssh_string string;
|
|
Packit Service |
31306d |
void *data;
|
|
Packit Service |
31306d |
} o;
|
|
Packit Service |
31306d |
char *cstring;
|
|
Packit Service |
31306d |
bignum b;
|
|
Packit Service |
31306d |
size_t len;
|
|
Packit Service |
31306d |
size_t count;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (argc > 256) {
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
for (p = format, count = 0; *p != '\0'; p++, count++) {
|
|
Packit Service |
31306d |
/* Invalid number of arguments passed */
|
|
Packit Service |
31306d |
if (count > argc) {
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
switch(*p) {
|
|
Packit Service |
31306d |
case 'b':
|
|
Packit Service |
31306d |
o.byte = (uint8_t)va_arg(ap, unsigned int);
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_u8(buffer, o.byte);
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'w':
|
|
Packit Service |
31306d |
o.word = (uint16_t)va_arg(ap, unsigned int);
|
|
Packit Service |
31306d |
o.word = htons(o.word);
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_u16(buffer, o.word);
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'd':
|
|
Packit Service |
31306d |
o.dword = va_arg(ap, uint32_t);
|
|
Packit Service |
31306d |
o.dword = htonl(o.dword);
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_u32(buffer, o.dword);
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'q':
|
|
Packit Service |
31306d |
o.qword = va_arg(ap, uint64_t);
|
|
Packit Service |
31306d |
o.qword = htonll(o.qword);
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_u64(buffer, o.qword);
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'S':
|
|
Packit Service |
31306d |
o.string = va_arg(ap, ssh_string);
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_ssh_string(buffer, o.string);
|
|
Packit Service |
31306d |
o.string = NULL;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 's':
|
|
Packit Service |
31306d |
cstring = va_arg(ap, char *);
|
|
Packit Service |
31306d |
len = strlen(cstring);
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_u32(buffer, htonl(len));
|
|
Packit Service |
31306d |
if (rc == SSH_OK){
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_data(buffer, cstring, len);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
cstring = NULL;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'P':
|
|
Packit Service |
31306d |
len = va_arg(ap, size_t);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
o.data = va_arg(ap, void *);
|
|
Packit Service |
31306d |
count++; /* increase argument count */
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_data(buffer, o.data, len);
|
|
Packit Service |
31306d |
o.data = NULL;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'B':
|
|
Packit Service |
31306d |
b = va_arg(ap, bignum);
|
|
Packit Service |
31306d |
o.string = ssh_make_bignum_string(b);
|
|
Packit Service |
31306d |
if(o.string == NULL){
|
|
Packit Service |
31306d |
rc = SSH_ERROR;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_ssh_string(buffer, o.string);
|
|
Packit Service |
31306d |
SAFE_FREE(o.string);
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 't':
|
|
Packit Service |
31306d |
cstring = va_arg(ap, char *);
|
|
Packit Service |
31306d |
len = strlen(cstring);
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_data(buffer, cstring, len);
|
|
Packit Service |
31306d |
cstring = NULL;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_WARN, "Invalid buffer format %c", *p);
|
|
Packit Service |
31306d |
rc = SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (rc != SSH_OK){
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (argc != count) {
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (rc != SSH_ERROR){
|
|
Packit Service |
31306d |
/* Check if our canary is intact, if not something really bad happened */
|
|
Packit Service |
31306d |
uint32_t canary = va_arg(ap, uint32_t);
|
|
Packit Service |
31306d |
if (canary != SSH_BUFFER_PACK_END) {
|
|
Packit Service |
31306d |
abort();
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
return rc;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/** @internal
|
|
Packit Service |
31306d |
* @brief Add multiple values in a buffer on a single function call
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to add to
|
|
Packit Service |
31306d |
* @param[in] format A format string of arguments. This string contains single
|
|
Packit Service |
31306d |
* letters describing the order and type of arguments:
|
|
Packit Service |
31306d |
* 'b': uint8_t (pushed in network byte order)
|
|
Packit Service |
31306d |
* 'w': uint16_t (pushed in network byte order)
|
|
Packit Service |
31306d |
* 'd': uint32_t (pushed in network byte order)
|
|
Packit Service |
31306d |
* 'q': uint64_t (pushed in network byte order)
|
|
Packit Service |
31306d |
* 'S': ssh_string
|
|
Packit Service |
31306d |
* 's': char * (C string, pushed as SSH string)
|
|
Packit Service |
31306d |
* 't': char * (C string, pushed as free text)
|
|
Packit Service |
31306d |
* 'P': size_t, void * (len of data, pointer to data)
|
|
Packit Service |
31306d |
* only pushes data.
|
|
Packit Service |
31306d |
* 'B': bignum (pushed as SSH string)
|
|
Packit Service |
31306d |
* @returns SSH_OK on success
|
|
Packit Service |
31306d |
* SSH_ERROR on error
|
|
Packit Service |
31306d |
* @warning when using 'P' with a constant size (e.g. 8), do not
|
|
Packit Service |
31306d |
* forget to cast to (size_t).
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int _ssh_buffer_pack(struct ssh_buffer_struct *buffer,
|
|
Packit Service |
31306d |
const char *format,
|
|
Packit Service |
31306d |
size_t argc,
|
|
Packit Service |
31306d |
...)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
va_list ap;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (argc > 256) {
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
va_start(ap, argc);
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack_allocate_va(buffer, format, argc, ap);
|
|
Packit Service |
31306d |
va_end(ap);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
return rc;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
va_start(ap, argc);
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack_va(buffer, format, argc, ap);
|
|
Packit Service |
31306d |
va_end(ap);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return rc;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/** @internal
|
|
Packit Service |
31306d |
* @brief Get multiple values from a buffer on a single function call
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to get from
|
|
Packit Service |
31306d |
* @param[in] format A format string of arguments.
|
|
Packit Service |
31306d |
* @param[in] ap A va_list of arguments.
|
|
Packit Service |
31306d |
* @returns SSH_OK on success
|
|
Packit Service |
31306d |
* SSH_ERROR on error
|
|
Packit Service |
31306d |
* @see ssh_buffer_get_format() for format list values.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
|
Packit Service |
31306d |
const char *format,
|
|
Packit Service |
31306d |
size_t argc,
|
|
Packit Service |
31306d |
va_list ap)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
int rc = SSH_ERROR;
|
|
Packit Service |
31306d |
const char *p = format, *last;
|
|
Packit Service |
31306d |
union {
|
|
Packit Service |
31306d |
uint8_t *byte;
|
|
Packit Service |
31306d |
uint16_t *word;
|
|
Packit Service |
31306d |
uint32_t *dword;
|
|
Packit Service |
31306d |
uint64_t *qword;
|
|
Packit Service |
31306d |
ssh_string *string;
|
|
Packit Service |
31306d |
char **cstring;
|
|
Packit Service |
31306d |
bignum *bignum;
|
|
Packit Service |
31306d |
void **data;
|
|
Packit Service |
31306d |
} o;
|
|
Packit Service |
31306d |
size_t len, rlen, max_len;
|
|
Packit Service |
31306d |
ssh_string tmp_string = NULL;
|
|
Packit Service |
31306d |
va_list ap_copy;
|
|
Packit Service |
31306d |
size_t count;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
max_len = ssh_buffer_get_len(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* copy the argument list in case a rollback is needed */
|
|
Packit Service |
31306d |
va_copy(ap_copy, ap);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (argc > 256) {
|
|
Packit Service |
31306d |
rc = SSH_ERROR;
|
|
Packit Service |
31306d |
goto cleanup;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
for (count = 0; *p != '\0'; p++, count++) {
|
|
Packit Service |
31306d |
/* Invalid number of arguments passed */
|
|
Packit Service |
31306d |
if (count > argc) {
|
|
Packit Service |
31306d |
rc = SSH_ERROR;
|
|
Packit Service |
31306d |
goto cleanup;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = SSH_ERROR;
|
|
Packit Service |
31306d |
switch (*p) {
|
|
Packit Service |
31306d |
case 'b':
|
|
Packit Service |
31306d |
o.byte = va_arg(ap, uint8_t *);
|
|
Packit Service |
31306d |
rlen = ssh_buffer_get_u8(buffer, o.byte);
|
|
Packit Service |
31306d |
rc = rlen==1 ? SSH_OK : SSH_ERROR;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'w':
|
|
Packit Service |
31306d |
o.word = va_arg(ap, uint16_t *);
|
|
Packit Service |
31306d |
rlen = ssh_buffer_get_data(buffer, o.word, sizeof(uint16_t));
|
|
Packit Service |
31306d |
if (rlen == 2) {
|
|
Packit Service |
31306d |
*o.word = ntohs(*o.word);
|
|
Packit Service |
31306d |
rc = SSH_OK;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'd':
|
|
Packit Service |
31306d |
o.dword = va_arg(ap, uint32_t *);
|
|
Packit Service |
31306d |
rlen = ssh_buffer_get_u32(buffer, o.dword);
|
|
Packit Service |
31306d |
if (rlen == 4) {
|
|
Packit Service |
31306d |
*o.dword = ntohl(*o.dword);
|
|
Packit Service |
31306d |
rc = SSH_OK;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'q':
|
|
Packit Service |
31306d |
o.qword = va_arg(ap, uint64_t*);
|
|
Packit Service |
31306d |
rlen = ssh_buffer_get_u64(buffer, o.qword);
|
|
Packit Service |
31306d |
if (rlen == 8) {
|
|
Packit Service |
31306d |
*o.qword = ntohll(*o.qword);
|
|
Packit Service |
31306d |
rc = SSH_OK;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'B':
|
|
Packit Service |
31306d |
o.bignum = va_arg(ap, bignum *);
|
|
Packit Service |
31306d |
*o.bignum = NULL;
|
|
Packit Service |
31306d |
tmp_string = ssh_buffer_get_ssh_string(buffer);
|
|
Packit Service |
31306d |
if (tmp_string == NULL) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
*o.bignum = ssh_make_string_bn(tmp_string);
|
|
Packit Service |
31306d |
ssh_string_burn(tmp_string);
|
|
Packit Service |
31306d |
SSH_STRING_FREE(tmp_string);
|
|
Packit Service |
31306d |
rc = (*o.bignum != NULL) ? SSH_OK : SSH_ERROR;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'S':
|
|
Packit Service |
31306d |
o.string = va_arg(ap, ssh_string *);
|
|
Packit Service |
31306d |
*o.string = ssh_buffer_get_ssh_string(buffer);
|
|
Packit Service |
31306d |
rc = *o.string != NULL ? SSH_OK : SSH_ERROR;
|
|
Packit Service |
31306d |
o.string = NULL;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 's': {
|
|
Packit Service |
31306d |
uint32_t u32len = 0;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
o.cstring = va_arg(ap, char **);
|
|
Packit Service |
31306d |
*o.cstring = NULL;
|
|
Packit Service |
31306d |
rlen = ssh_buffer_get_u32(buffer, &u32len);
|
|
Packit Service |
31306d |
if (rlen != 4){
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
len = ntohl(u32len);
|
|
Packit Service |
31306d |
if (len > max_len - 1) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_validate_length(buffer, len);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
*o.cstring = malloc(len + 1);
|
|
Packit Service |
31306d |
if (*o.cstring == NULL){
|
|
Packit Service |
31306d |
rc = SSH_ERROR;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
rlen = ssh_buffer_get_data(buffer, *o.cstring, len);
|
|
Packit Service |
31306d |
if (rlen != len){
|
|
Packit Service |
31306d |
SAFE_FREE(*o.cstring);
|
|
Packit Service |
31306d |
rc = SSH_ERROR;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
(*o.cstring)[len] = '\0';
|
|
Packit Service |
31306d |
o.cstring = NULL;
|
|
Packit Service |
31306d |
rc = SSH_OK;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
case 'P':
|
|
Packit Service |
31306d |
len = va_arg(ap, size_t);
|
|
Packit Service |
31306d |
if (len > max_len - 1) {
|
|
Packit Service |
31306d |
rc = SSH_ERROR;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_validate_length(buffer, len);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
o.data = va_arg(ap, void **);
|
|
Packit Service |
31306d |
count++;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
*o.data = malloc(len);
|
|
Packit Service |
31306d |
if(*o.data == NULL){
|
|
Packit Service |
31306d |
rc = SSH_ERROR;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
rlen = ssh_buffer_get_data(buffer, *o.data, len);
|
|
Packit Service |
31306d |
if (rlen != len){
|
|
Packit Service |
31306d |
SAFE_FREE(*o.data);
|
|
Packit Service |
31306d |
rc = SSH_ERROR;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
o.data = NULL;
|
|
Packit Service |
31306d |
rc = SSH_OK;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_WARN, "Invalid buffer format %c", *p);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (argc != count) {
|
|
Packit Service |
31306d |
rc = SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
cleanup:
|
|
Packit Service |
31306d |
if (rc != SSH_ERROR){
|
|
Packit Service |
31306d |
/* Check if our canary is intact, if not something really bad happened */
|
|
Packit Service |
31306d |
uint32_t canary = va_arg(ap, uint32_t);
|
|
Packit Service |
31306d |
if (canary != SSH_BUFFER_PACK_END){
|
|
Packit Service |
31306d |
abort();
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (rc != SSH_OK){
|
|
Packit Service |
31306d |
/* Reset the format string and erase everything that was allocated */
|
|
Packit Service |
31306d |
last = p;
|
|
Packit Service |
31306d |
for(p=format;p
|
|
Packit Service |
31306d |
switch(*p){
|
|
Packit Service |
31306d |
case 'b':
|
|
Packit Service |
31306d |
o.byte = va_arg(ap_copy, uint8_t *);
|
|
Packit Service |
31306d |
if (buffer->secure) {
|
|
Packit Service |
31306d |
explicit_bzero(o.byte, sizeof(uint8_t));
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'w':
|
|
Packit Service |
31306d |
o.word = va_arg(ap_copy, uint16_t *);
|
|
Packit Service |
31306d |
if (buffer->secure) {
|
|
Packit Service |
31306d |
explicit_bzero(o.word, sizeof(uint16_t));
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'd':
|
|
Packit Service |
31306d |
o.dword = va_arg(ap_copy, uint32_t *);
|
|
Packit Service |
31306d |
if (buffer->secure) {
|
|
Packit Service |
31306d |
explicit_bzero(o.dword, sizeof(uint32_t));
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'q':
|
|
Packit Service |
31306d |
o.qword = va_arg(ap_copy, uint64_t *);
|
|
Packit Service |
31306d |
if (buffer->secure) {
|
|
Packit Service |
31306d |
explicit_bzero(o.qword, sizeof(uint64_t));
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'B':
|
|
Packit Service |
31306d |
o.bignum = va_arg(ap_copy, bignum *);
|
|
Packit Service |
31306d |
bignum_safe_free(*o.bignum);
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'S':
|
|
Packit Service |
31306d |
o.string = va_arg(ap_copy, ssh_string *);
|
|
Packit Service |
31306d |
if (buffer->secure) {
|
|
Packit Service |
31306d |
ssh_string_burn(*o.string);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SAFE_FREE(*o.string);
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 's':
|
|
Packit Service |
31306d |
o.cstring = va_arg(ap_copy, char **);
|
|
Packit Service |
31306d |
if (buffer->secure) {
|
|
Packit Service |
31306d |
explicit_bzero(*o.cstring, strlen(*o.cstring));
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SAFE_FREE(*o.cstring);
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case 'P':
|
|
Packit Service |
31306d |
len = va_arg(ap_copy, size_t);
|
|
Packit Service |
31306d |
o.data = va_arg(ap_copy, void **);
|
|
Packit Service |
31306d |
if (buffer->secure) {
|
|
Packit Service |
31306d |
explicit_bzero(*o.data, len);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SAFE_FREE(*o.data);
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
(void)va_arg(ap_copy, void *);
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
va_end(ap_copy);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return rc;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/** @internal
|
|
Packit Service |
31306d |
* @brief Get multiple values from a buffer on a single function call
|
|
Packit Service |
31306d |
* @param[in] buffer The buffer to get from
|
|
Packit Service |
31306d |
* @param[in] format A format string of arguments. This string contains single
|
|
Packit Service |
31306d |
* letters describing the order and type of arguments:
|
|
Packit Service |
31306d |
* 'b': uint8_t * (pulled in network byte order)
|
|
Packit Service |
31306d |
* 'w': uint16_t * (pulled in network byte order)
|
|
Packit Service |
31306d |
* 'd': uint32_t * (pulled in network byte order)
|
|
Packit Service |
31306d |
* 'q': uint64_t * (pulled in network byte order)
|
|
Packit Service |
31306d |
* 'S': ssh_string *
|
|
Packit Service |
31306d |
* 's': char ** (C string, pulled as SSH string)
|
|
Packit Service |
31306d |
* 'P': size_t, void ** (len of data, pointer to data)
|
|
Packit Service |
31306d |
* only pulls data.
|
|
Packit Service |
31306d |
* 'B': bignum * (pulled as SSH string)
|
|
Packit Service |
31306d |
* @returns SSH_OK on success
|
|
Packit Service |
31306d |
* SSH_ERROR on error
|
|
Packit Service |
31306d |
* @warning when using 'P' with a constant size (e.g. 8), do not
|
|
Packit Service |
31306d |
* forget to cast to (size_t).
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int _ssh_buffer_unpack(struct ssh_buffer_struct *buffer,
|
|
Packit Service |
31306d |
const char *format,
|
|
Packit Service |
31306d |
size_t argc,
|
|
Packit Service |
31306d |
...)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
va_list ap;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
va_start(ap, argc);
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack_va(buffer, format, argc, ap);
|
|
Packit Service |
31306d |
va_end(ap);
|
|
Packit Service |
31306d |
return rc;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/** @} */
|