buffer.c   buffer.c 
/* /*
* buffer.c - buffer functions * buffer.c - buffer functions
* *
* This file is part of the SSH Library * This file is part of the SSH Library
* *
* Copyright (c) 2003-2008 by Aris Adamantiadis * Copyright (c) 2003-2009 by Aris Adamantiadis
* *
* The SSH Library is free software; you can redistribute it and/or modify * The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your * the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version. * option) any later version.
* *
* The SSH Library is distributed in the hope that it will be useful, but * The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILI TY * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILI TY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details. * License for more details.
skipping to change at line 32 skipping to change at line 32
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifndef _WIN32 #ifndef _WIN32
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif
#include "libssh/priv.h" #include "libssh/priv.h"
#include "libssh/buffer.h"
/** \defgroup ssh_buffer SSH Buffers /** \defgroup ssh_buffer SSH Buffers
* \brief buffer handling * \brief buffer handling
*/ */
/** \addtogroup ssh_buffer /** \addtogroup ssh_buffer
* @{ * @{
*/ */
/** \brief checks that preconditions and postconditions are valid
* \internal
*/
#ifdef DEBUG_BUFFER
static void buffer_verify(struct buffer_struct *buf){
int doabort=0;
if(buf->data == NULL)
return;
if(buf->used > buf->allocated){
fprintf(stderr,"Buffer error : allocated %u, used %u\n",buf->allocated,
buf->used);
doabort=1;
}
if(buf->pos > buf->used){
fprintf(stderr,"Buffer error : position %u, used %u\n",buf->pos, buf->u
sed);
doabort=1;
}
if(buf->pos > buf->allocated){
fprintf(stderr,"Buffer error : position %u, allocated %u\n",buf->pos,
buf->allocated);
doabort=1;
}
if(doabort)
abort();
}
#else
#define buffer_verify(x)
#endif
/** \brief creates a new buffer /** \brief creates a new buffer
* \return a new initialized buffer, NULL on error. * \return a new initialized buffer, NULL on error.
*/ */
struct buffer_struct *buffer_new(void) { struct ssh_buffer_struct *buffer_new(void) {
struct buffer_struct *buf = malloc(sizeof(struct buffer_struct)); struct ssh_buffer_struct *buf = malloc(sizeof(struct ssh_buffer_struct));
if (buf == NULL) { if (buf == NULL) {
return NULL; return NULL;
} }
memset(buf, 0, sizeof(struct buffer_struct)); memset(buf, 0, sizeof(struct ssh_buffer_struct));
buffer_verify(buf);
return buf; return buf;
} }
/** \brief deallocate a buffer /** \brief deallocate a buffer
* \param buffer buffer to free * \param buffer buffer to free
*/ */
void buffer_free(struct buffer_struct *buffer) { void buffer_free(struct ssh_buffer_struct *buffer) {
if (buffer == NULL) { if (buffer == NULL) {
return; return;
} }
buffer_verify(buffer);
if (buffer->data) { if (buffer->data) {
/* burn the data */ /* burn the data */
memset(buffer->data, 0, buffer->allocated); memset(buffer->data, 0, buffer->allocated);
SAFE_FREE(buffer->data); SAFE_FREE(buffer->data);
} }
memset(buffer, 'X', sizeof(*buffer)); memset(buffer, 'X', sizeof(*buffer));
SAFE_FREE(buffer); SAFE_FREE(buffer);
} }
static int realloc_buffer(struct buffer_struct *buffer, int needed) { static int realloc_buffer(struct ssh_buffer_struct *buffer, int needed) {
int smallest = 1; int smallest = 1;
char *new = NULL; char *new = NULL;
buffer_verify(buffer);
/* Find the smallest power of two which is greater or equal to needed */ /* Find the smallest power of two which is greater or equal to needed */
while(smallest <= needed) { while(smallest < needed) {
smallest <<= 1; smallest <<= 1;
} }
needed = smallest; needed = smallest;
new = realloc(buffer->data, needed); new = realloc(buffer->data, needed);
if (new == NULL) { if (new == NULL) {
return -1; return -1;
} }
buffer->data = new; buffer->data = new;
buffer->allocated = needed; buffer->allocated = needed;
buffer_verify(buffer);
return 0; return 0;
} }
/* \internal /* \internal
* \brief reinitialize a buffer * \brief reinitialize a buffer
* \param buffer buffer * \param buffer buffer
* \return 0 on sucess, < 0 on error * \return 0 on sucess, < 0 on error
*/ */
int buffer_reinit(struct buffer_struct *buffer) { int buffer_reinit(struct ssh_buffer_struct *buffer) {
buffer_verify(buffer);
memset(buffer->data, 0, buffer->used); memset(buffer->data, 0, buffer->used);
buffer->used = 0; buffer->used = 0;
buffer->pos = 0; buffer->pos = 0;
if(buffer->allocated > 127) { if(buffer->allocated > 127) {
if (realloc_buffer(buffer, 127) < 0) { if (realloc_buffer(buffer, 127) < 0) {
return -1; return -1;
} }
} }
buffer_verify(buffer);
return 0; return 0;
} }
/** \internal /** \internal
* \brief add data at tail of the buffer * \brief add data at tail of the buffer
* \param buffer buffer * \param buffer buffer
* \param data data pointer * \param data data pointer
* \param len length of data * \param len length of data
*/ */
int buffer_add_data(struct buffer_struct *buffer, const void *data, u32 len int buffer_add_data(struct ssh_buffer_struct *buffer, const void *data, uin
) { t32_t len) {
buffer_verify(buffer);
if (buffer->allocated < (buffer->used + len)) { if (buffer->allocated < (buffer->used + len)) {
if (realloc_buffer(buffer, buffer->used + len) < 0) { if (realloc_buffer(buffer, buffer->used + len) < 0) {
return -1; return -1;
} }
} }
memcpy(buffer->data+buffer->used, data, len); memcpy(buffer->data+buffer->used, data, len);
buffer->used+=len; buffer->used+=len;
buffer_verify(buffer);
return 0; return 0;
} }
/** \internal /** \internal
* \brief add a SSH string to the tail of buffer * \brief add a SSH string to the tail of buffer
* \param buffer buffer * \param buffer buffer
* \param string SSH String to add * \param string SSH String to add
* \return 0 on success, -1 on error. * \return 0 on success, -1 on error.
*/ */
int buffer_add_ssh_string(struct buffer_struct *buffer, int buffer_add_ssh_string(struct ssh_buffer_struct *buffer,
struct string_struct *string) { struct ssh_string_struct *string) {
u32 len = 0; uint32_t len = 0;
len = ntohl(string->size); len = string_len(string);
if (buffer_add_data(buffer, string, len + sizeof(u32)) < 0) { if (buffer_add_data(buffer, string, len + sizeof(uint32_t)) < 0) {
return -1; return -1;
} }
return 0; return 0;
} }
/** \internal /** \internal
* \brief add a 32 bits unsigned integer to the tail of buffer * \brief add a 32 bits unsigned integer to the tail of buffer
* \param buffer buffer * \param buffer buffer
* \param data 32 bits integer * \param data 32 bits integer
* \return 0 on success, -1 on error. * \return 0 on success, -1 on error.
*/ */
int buffer_add_u32(struct buffer_struct *buffer,u32 data){ int buffer_add_u32(struct ssh_buffer_struct *buffer,uint32_t data){
if (buffer_add_data(buffer, &data, sizeof(data)) < 0) {
return -1;
}
return 0;
}
/** \internal
* \brief add a 16 bits unsigned integer to the tail of buffer
* \param buffer buffer
* \param data 16 bits integer
* \return 0 on success, -1 on error.
*/
int buffer_add_u16(struct ssh_buffer_struct *buffer,uint16_t data){
if (buffer_add_data(buffer, &data, sizeof(data)) < 0) { if (buffer_add_data(buffer, &data, sizeof(data)) < 0) {
return -1; return -1;
} }
return 0; return 0;
} }
/** \internal /** \internal
* \brief add a 64 bits unsigned integer to the tail of buffer * \brief add a 64 bits unsigned integer to the tail of buffer
* \param buffer buffer * \param buffer buffer
* \param data 64 bits integer * \param data 64 bits integer
* \return 0 on success, -1 on error. * \return 0 on success, -1 on error.
*/ */
int buffer_add_u64(struct buffer_struct *buffer, u64 data){ int buffer_add_u64(struct ssh_buffer_struct *buffer, uint64_t data){
if (buffer_add_data(buffer, &data, sizeof(data)) < 0) { if (buffer_add_data(buffer, &data, sizeof(data)) < 0) {
return -1; return -1;
} }
return 0; return 0;
} }
/** \internal /** \internal
* \brief add a 8 bits unsigned integer to the tail of buffer * \brief add a 8 bits unsigned integer to the tail of buffer
* \param buffer buffer * \param buffer buffer
* \param data 8 bits integer * \param data 8 bits integer
* \return 0 on success, -1 on error. * \return 0 on success, -1 on error.
*/ */
int buffer_add_u8(struct buffer_struct *buffer,u8 data){ int buffer_add_u8(struct ssh_buffer_struct *buffer,uint8_t data){
if (buffer_add_data(buffer, &data, sizeof(u8)) < 0) { if (buffer_add_data(buffer, &data, sizeof(uint8_t)) < 0) {
return -1; return -1;
} }
return 0; return 0;
} }
/** \internal /** \internal
* \brief add data at head of a buffer * \brief add data at head of a buffer
* \param buffer buffer * \param buffer buffer
* \param data data to add * \param data data to add
* \param len length of data * \param len length of data
* \return 0 on success, -1 on error. * \return 0 on success, -1 on error.
*/ */
int buffer_prepend_data(struct buffer_struct *buffer, const void *data, int buffer_prepend_data(struct ssh_buffer_struct *buffer, const void *data,
u32 len) { uint32_t len) {
buffer_verify(buffer);
if (buffer->allocated < (buffer->used + len)) { if (buffer->allocated < (buffer->used + len)) {
if (realloc_buffer(buffer, buffer->used + len) < 0) { if (realloc_buffer(buffer, buffer->used + len) < 0) {
return -1; return -1;
} }
} }
memmove(buffer->data + len, buffer->data, buffer->used); memmove(buffer->data + len, buffer->data, buffer->used);
memcpy(buffer->data, data, len); memcpy(buffer->data, data, len);
buffer->used += len; buffer->used += len;
buffer_verify(buffer);
return 0; return 0;
} }
/** \internal /** \internal
* \brief append data from a buffer to tail of another * \brief append data from a buffer to tail of another
* \param buffer destination buffer * \param buffer destination buffer
* \param source source buffer. Doesn't take position in buffer into accoun t * \param source source buffer. Doesn't take position in buffer into accoun t
* \return 0 on success, -1 on error. * \return 0 on success, -1 on error.
*/ */
int buffer_add_buffer(struct buffer_struct *buffer, int buffer_add_buffer(struct ssh_buffer_struct *buffer,
struct buffer_struct *source) { struct ssh_buffer_struct *source) {
if (buffer_add_data(buffer, buffer_get(source), buffer_get_len(source)) < 0) { if (buffer_add_data(buffer, buffer_get(source), buffer_get_len(source)) < 0) {
return -1; return -1;
} }
return 0; return 0;
} }
/** \brief get a pointer on the head of the buffer /** \brief get a pointer on the head of the buffer
* \param buffer buffer * \param buffer buffer
* \return data pointer on the head. Doesn't take position into account. * \return data pointer on the head. Doesn't take position into account.
* \warning don't expect data to be nul-terminated * \warning don't expect data to be nul-terminated
* \see buffer_get_rest() * \see buffer_get_rest()
* \see buffer_get_len() * \see buffer_get_len()
*/ */
void *buffer_get(struct buffer_struct *buffer){ void *buffer_get(struct ssh_buffer_struct *buffer){
return buffer->data; return buffer->data;
} }
/** \internal /** \internal
* \brief get a pointer to head of the buffer at current position * \brief get a pointer to head of the buffer at current position
* \param buffer buffer * \param buffer buffer
* \return pointer to the data from current position * \return pointer to the data from current position
* \see buffer_get_rest_len() * \see buffer_get_rest_len()
* \see buffer_get() * \see buffer_get()
*/ */
void *buffer_get_rest(struct buffer_struct *buffer){ void *buffer_get_rest(struct ssh_buffer_struct *buffer){
return buffer->data + buffer->pos; return buffer->data + buffer->pos;
} }
/** \brief get length of the buffer, not counting position /** \brief get length of the buffer, not counting position
* \param buffer * \param buffer
* \return length of the buffer * \return length of the buffer
* \see buffer_get() * \see buffer_get()
*/ */
u32 buffer_get_len(struct buffer_struct *buffer){ uint32_t buffer_get_len(struct ssh_buffer_struct *buffer){
return buffer->used; return buffer->used;
} }
/** \internal /** \internal
* \brief get length of the buffer from the current position * \brief get length of the buffer from the current position
* \param buffer * \param buffer
* \return length of the buffer * \return length of the buffer
* \see buffer_get_rest() * \see buffer_get_rest()
*/ */
u32 buffer_get_rest_len(struct buffer_struct *buffer){ uint32_t buffer_get_rest_len(struct ssh_buffer_struct *buffer){
return buffer->used - buffer->pos; buffer_verify(buffer);
return buffer->used - buffer->pos;
} }
/** \internal /** \internal
* has effect to "eat" bytes at head of the buffer * has effect to "eat" bytes at head of the buffer
* \brief advance the position in the buffer * \brief advance the position in the buffer
* \param buffer buffer * \param buffer buffer
* \param len number of bytes to eat * \param len number of bytes to eat
* \return new size of the buffer * \return new size of the buffer
*/ */
u32 buffer_pass_bytes(struct buffer_struct *buffer, u32 len){ uint32_t buffer_pass_bytes(struct ssh_buffer_struct *buffer, uint32_t len){
buffer_verify(buffer);
if(buffer->used < buffer->pos+len) if(buffer->used < buffer->pos+len)
return 0; return 0;
buffer->pos+=len; buffer->pos+=len;
/* if the buffer is empty after having passed the whole bytes into it, we can clean it */ /* if the buffer is empty after having passed the whole bytes into it, we can clean it */
if(buffer->pos==buffer->used){ if(buffer->pos==buffer->used){
buffer->pos=0; buffer->pos=0;
buffer->used=0; buffer->used=0;
} }
buffer_verify(buffer);
return len; return len;
} }
/** \internal /** \internal
* \brief cut the end of the buffer * \brief cut the end of the buffer
* \param buffer buffer * \param buffer buffer
* \param len number of bytes to remove from tail * \param len number of bytes to remove from tail
* \return new size of the buffer * \return new size of the buffer
*/ */
u32 buffer_pass_bytes_end(struct buffer_struct *buffer, u32 len){ uint32_t buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t l
if(buffer->used < buffer->pos + len) en){
return 0; buffer_verify(buffer);
buffer->used-=len; if(buffer->used < buffer->pos + len)
return len; return 0;
buffer->used-=len;
buffer_verify(buffer);
return len;
} }
/** \internal /** \internal
* \brief gets remaining data out of the buffer. Adjust the read pointer. * \brief gets remaining data out of the buffer. Adjust the read pointer.
* \param buffer Buffer to read * \param buffer Buffer to read
* \param data data buffer where to store the data * \param data data buffer where to store the data
* \param len length to read from the buffer * \param len length to read from the buffer
* \returns 0 if there is not enough data in buffer * \returns 0 if there is not enough data in buffer
* \returns len otherwise. * \returns len otherwise.
*/ */
u32 buffer_get_data(struct buffer_struct *buffer, void *data, u32 len){ uint32_t buffer_get_data(struct ssh_buffer_struct *buffer, void *data, uint 32_t len){
/* /*
* Check for a integer overflow first, then check if not enough data is in * Check for a integer overflow first, then check if not enough data is in
* the buffer. * the buffer.
*/ */
if (buffer->pos + len < len || buffer->pos + len > buffer->used) { if (buffer->pos + len < len || buffer->pos + len > buffer->used) {
return 0; return 0;
} }
memcpy(data,buffer->data+buffer->pos,len); memcpy(data,buffer->data+buffer->pos,len);
buffer->pos+=len; buffer->pos+=len;
return len; /* no yet support for partial reads (is it really needed ?? ) */ return len; /* no yet support for partial reads (is it really needed ?? ) */
} }
/** \internal /** \internal
* \brief gets a 8 bits unsigned int out of the buffer. Adjusts the read po inter. * \brief gets a 8 bits unsigned int out of the buffer. Adjusts the read po inter.
* \param buffer Buffer to read * \param buffer Buffer to read
* \param data pointer to a u8 where to store the data * \param data pointer to a uint8_t where to store the data
* \returns 0 if there is not enough data in buffer * \returns 0 if there is not enough data in buffer
* \returns 1 otherwise. * \returns 1 otherwise.
*/ */
int buffer_get_u8(struct buffer_struct *buffer, u8 *data){ int buffer_get_u8(struct ssh_buffer_struct *buffer, uint8_t *data){
return buffer_get_data(buffer,data,sizeof(u8)); return buffer_get_data(buffer,data,sizeof(uint8_t));
} }
/** \internal /** \internal
* \brief gets a 32 bits unsigned int out of the buffer. Adjusts the read p ointer. * \brief gets a 32 bits unsigned int out of the buffer. Adjusts the read p ointer.
* \param buffer Buffer to read * \param buffer Buffer to read
* \param data pointer to a u32 where to store the data * \param data pointer to a uint32_t where to store the data
* \returns 0 if there is not enough data in buffer * \returns 0 if there is not enough data in buffer
* \returns 4 otherwise. * \returns 4 otherwise.
*/ */
int buffer_get_u32(struct buffer_struct *buffer, u32 *data){ int buffer_get_u32(struct ssh_buffer_struct *buffer, uint32_t *data){
return buffer_get_data(buffer,data,sizeof(u32)); return buffer_get_data(buffer,data,sizeof(uint32_t));
} }
/** \internal /** \internal
* \brief gets a 64 bits unsigned int out of the buffer. Adjusts the read p ointer. * \brief gets a 64 bits unsigned int out of the buffer. Adjusts the read p ointer.
* \param buffer Buffer to read * \param buffer Buffer to read
* \param data pointer to a u64 where to store the data * \param data pointer to a uint64_t where to store the data
* \returns 0 if there is not enough data in buffer * \returns 0 if there is not enough data in buffer
* \returns 8 otherwise. * \returns 8 otherwise.
*/ */
int buffer_get_u64(struct buffer_struct *buffer, u64 *data){ int buffer_get_u64(struct ssh_buffer_struct *buffer, uint64_t *data){
return buffer_get_data(buffer,data,sizeof(u64)); return buffer_get_data(buffer,data,sizeof(uint64_t));
} }
/** \internal /** \internal
* \brief gets a SSH String out of the buffer. Adjusts the read pointer. * \brief gets a SSH String out of the buffer. Adjusts the read pointer.
* \param buffer Buffer to read * \param buffer Buffer to read
* \returns The SSH String read * \returns The SSH String read
* \returns NULL otherwise. * \returns NULL otherwise.
*/ */
struct string_struct *buffer_get_ssh_string(struct buffer_struct *buffer) { struct ssh_string_struct *buffer_get_ssh_string(struct ssh_buffer_struct *b
u32 stringlen; uffer) {
u32 hostlen; uint32_t stringlen;
struct string_struct *str = NULL; uint32_t hostlen;
struct ssh_string_struct *str = NULL;
if (buffer_get_u32(buffer, &stringlen) == 0) { if (buffer_get_u32(buffer, &stringlen) == 0) {
return NULL; return NULL;
} }
hostlen = ntohl(stringlen); hostlen = ntohl(stringlen);
/* verify if there is enough space in buffer to get it */ /* verify if there is enough space in buffer to get it */
if ((buffer->pos + hostlen) > buffer->used) { if ((buffer->pos + hostlen) > buffer->used) {
return NULL; /* it is indeed */ return NULL; /* it is indeed */
} }
str = string_new(hostlen); str = string_new(hostlen);
if (str == NULL) { if (str == NULL) {
return NULL; return NULL;
} }
if (buffer_get_data(buffer, str->string, hostlen) != hostlen) { if (buffer_get_data(buffer, string_data(str), hostlen) != hostlen) {
/* should never happen */ /* should never happen */
SAFE_FREE(str); SAFE_FREE(str);
return NULL; return NULL;
} }
return str; return str;
} }
/** \internal /** \internal
* \brief gets a mpint out of the buffer. Adjusts the read pointer. * \brief gets a mpint out of the buffer. Adjusts the read pointer.
* SSH-1 only * SSH-1 only
* \param buffer Buffer to read * \param buffer Buffer to read
* \returns the SSH String containing the mpint * \returns the SSH String containing the mpint
* \returns NULL otherwise * \returns NULL otherwise
*/ */
struct string_struct *buffer_get_mpint(struct buffer_struct *buffer) { struct ssh_string_struct *buffer_get_mpint(struct ssh_buffer_struct *buffer
u16 bits; ) {
u32 len; uint16_t bits;
struct string_struct *str = NULL; uint32_t len;
struct ssh_string_struct *str = NULL;
if (buffer_get_data(buffer, &bits, sizeof(u16)) != sizeof(u16)) { if (buffer_get_data(buffer, &bits, sizeof(uint16_t)) != sizeof(uint16_t)) {
return NULL; return NULL;
} }
bits = ntohs(bits); bits = ntohs(bits);
len = (bits + 7) / 8; len = (bits + 7) / 8;
if ((buffer->pos + len) > buffer->used) { if ((buffer->pos + len) > buffer->used) {
return NULL; return NULL;
} }
str = string_new(len); str = string_new(len);
if (str == NULL) { if (str == NULL) {
return NULL; return NULL;
} }
if (buffer_get_data(buffer, str->string, len) != len) { if (buffer_get_data(buffer, string_data(str), len) != len) {
SAFE_FREE(str); SAFE_FREE(str);
return NULL; return NULL;
} }
return str; return str;
} }
/** @} */ /** @} */
/* vim: set ts=2 sw=2 et cindent: */ /* vim: set ts=2 sw=2 et cindent: */
 End of changes. 43 change blocks. 
59 lines changed or deleted 121 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/