summaryrefslogtreecommitdiff
path: root/src/protocol/internal/fqterm_ssh_buffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/protocol/internal/fqterm_ssh_buffer.cpp')
-rw-r--r--src/protocol/internal/fqterm_ssh_buffer.cpp302
1 files changed, 302 insertions, 0 deletions
diff --git a/src/protocol/internal/fqterm_ssh_buffer.cpp b/src/protocol/internal/fqterm_ssh_buffer.cpp
new file mode 100644
index 0000000..d95497a
--- /dev/null
+++ b/src/protocol/internal/fqterm_ssh_buffer.cpp
@@ -0,0 +1,302 @@
+/***************************************************************************
+ * fqterm, a terminal emulator for both BBS and *nix. *
+ * Copyright (C) 2008 fqterm development group. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. *
+ ***************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <vector>
+
+#include "fqterm_trace.h"
+#include "fqterm_ssh_buffer.h"
+#include "fqterm_serialization.h"
+
+namespace FQTerm {
+//==============================================================================
+// FQTermSSHBuffer
+//==============================================================================
+
+FQTermSSHBuffer::FQTermSSHBuffer(int size) {
+ alloc_size_ = size;
+ buffer_size_ = 0;
+ offset_ = 0;
+ buffer_ = new u_char[alloc_size_];
+}
+
+FQTermSSHBuffer::~FQTermSSHBuffer() {
+ delete [] buffer_;
+ offset_ = 0;
+ buffer_size_ = 0;
+ alloc_size_ = 0;
+}
+
+void FQTermSSHBuffer::ensure(int len) {
+ if (len <= (alloc_size_ - (offset_ + buffer_size_))) {
+ return ;
+ } else {
+ alloc_size_ = buffer_size_ + len;
+ rebuffer();
+ }
+}
+
+void FQTermSSHBuffer::rebuffer() {
+ u_char *newBuffer;
+ newBuffer = new u_char[alloc_size_];
+ memset(newBuffer, 0, alloc_size_);
+ memcpy(newBuffer, buffer_ + offset_, buffer_size_);
+ delete [] buffer_;
+ buffer_ = newBuffer;
+ offset_ = 0;
+}
+
+void FQTermSSHBuffer::clear() {
+ memset(buffer_, 0, alloc_size_);
+ offset_ = 0;
+ buffer_size_ = 0;
+}
+
+void FQTermSSHBuffer::consume(int len) {
+ if (len > buffer_size_) {
+ len = buffer_size_;
+ }
+
+ offset_ += len;
+ buffer_size_ -= len;
+}
+
+void FQTermSSHBuffer::putRawData(const char *data, int len) {
+ if (len < 0) {
+ FQ_TRACE("sshbuffer", 0) << "Write data error.";
+ }
+
+ ensure(len);
+ memcpy((buffer_ + offset_ + buffer_size_), data, len);
+ buffer_size_ += len;
+}
+
+void FQTermSSHBuffer::getRawData(char *data, int len) {
+ if (len <= buffer_size_ && len >= 0) {
+ memcpy(data, buffer_ + offset_, len);
+ consume(len);
+ } else {
+ FQ_TRACE("sshbuffer", 0) << "Read too many data: " << len << " bytes.";
+ }
+}
+
+//==============================================================================
+// Store an BIGNUM in the buffer with a 2-byte msb first bit count, followed by
+// (bits+7)/8 bytes of binary data, msb first.
+//==============================================================================
+
+void FQTermSSHBuffer::putSSH1BN(BIGNUM *bignum) {
+ int bits = BN_num_bits(bignum);
+ int bin_size = (bits + 7) / 8;
+ u_char *buf = new u_char[bin_size];
+ int oi;
+ u_char msg[2];
+
+ // Get the value of in binary
+ oi = BN_bn2bin(bignum, buf);
+ if (oi != bin_size) {
+ FQ_TRACE("sshbuffer", 0) << "BN_bn2bin() failed: oi = " << oi
+ << " != bin_size." << bin_size;
+ }
+
+ // Store the number of bits in the buffer in two bytes, msb first
+ htonu16(msg, bits);
+ putRawData((char*)msg, 2);
+ // Store the binary data.
+ putRawData((char*)buf, oi);
+
+ memset(buf, 0, bin_size);
+ delete [] buf;
+}
+
+
+
+void FQTermSSHBuffer::putSSH2BN(BIGNUM *bignum) {
+ // FIXME: support negative number and add error handling.
+
+ FQ_VERIFY(!bignum->neg); // currently we don't support negative big number.
+
+ if (BN_is_zero(bignum)) {
+ this->putInt(0);
+ } else {
+ u_int bytes = BN_num_bytes(bignum) + 1;
+
+ FQ_VERIFY(bytes >= 2); // currently we don't support big numbers so small
+
+ std::vector<u_char> buf(bytes);
+ buf[0] = 0;
+
+ int bin_len = BN_bn2bin(bignum, &buf[0] + 1);
+
+ FQ_VERIFY(bin_len == (int)bytes - 1);
+
+ u_int no_high_bit = (buf[1] & 0x80) ? 0 : 1;
+
+ this->putInt(bytes - no_high_bit);
+ this->putRawData((const char *)&buf[0] + no_high_bit, bytes - no_high_bit);
+ }
+}
+
+//==============================================================================
+// Retrieves a BIGNUM from the buffer.
+//==============================================================================
+
+void FQTermSSHBuffer::getSSH1BN(BIGNUM *bignum) {
+ int bits, bytes;
+ u_char buf[2];
+ u_char *bin;
+
+ // Get the number for bits.
+ getRawData((char*)buf, 2);
+ bits = ntohu16(buf);
+ // Compute the number of binary bytes that follow.
+ bytes = (bits + 7) / 8;
+ if (bytes > 8 *1024) {
+ FQ_TRACE("sshbuffer", 0) << "Can't handle BN of size " << bytes;
+ return ;
+ }
+ if (len() < bytes) {
+ FQ_TRACE("sshbuffer", 0) << "The input buffer is too small.";
+ return ;
+ }
+ bin = data();
+ BN_bin2bn(bin, bytes, bignum);
+ consume(bytes);
+}
+
+void FQTermSSHBuffer::getSSH2BN(BIGNUM *bignum) {
+ // FIXME: support negative numbers and error handling
+ int len;
+ unsigned char *hex_data = (unsigned char *)getString(&len);
+
+ FQ_VERIFY(!(len > 0 && (hex_data[0] & 0x80))); // don't support negative numbers.
+
+ FQ_VERIFY(len < 10240); // don't support so large numbers.
+
+ BIGNUM *res = BN_bin2bn(hex_data, len, bignum);
+
+ FQ_VERIFY(res != NULL);
+
+ delete hex_data;
+}
+
+u_short FQTermSSHBuffer::getWord() {
+ u_char buf[2];
+ u_short data;
+
+ getRawData((char*)buf, 2);
+ data = ntohu16(buf);
+ return data;
+}
+
+void FQTermSSHBuffer::putWord(u_short data) {
+ u_char buf[2];
+
+ htonu16(buf, data);
+ putRawData((char*)buf, 2);
+}
+
+u_int FQTermSSHBuffer::getInt() {
+ u_char buf[4];
+ u_int data;
+ getRawData((char*)buf, 4);
+ data = ntohu32(buf);
+ return data;
+}
+
+void FQTermSSHBuffer::putInt(u_int data) {
+ u_char buf[4];
+
+ htonu32(buf, data);
+ putRawData((char*)buf, 4);
+}
+
+//==============================================================================
+// Return a character from the buffer (0-255).
+//==============================================================================
+
+u_char FQTermSSHBuffer::getByte() {
+ u_char ch;
+
+ getRawData((char*) &ch, 1);
+ return ch;
+}
+
+//==============================================================================
+// Stores a character in the buffer.
+//==============================================================================
+
+void FQTermSSHBuffer::putByte(int data) {
+ u_char ch = data;
+
+ putRawData((char*) &ch, 1);
+}
+
+//==============================================================================
+// Stores an arbitrary binary string in the buffer.
+//==============================================================================
+
+void FQTermSSHBuffer::putString(const char *str, int len) {
+ if (str == NULL) {
+ FQ_TRACE("sshbuffer", 0) << "Can't put a null pointer string.";
+ return ;
+ }
+
+ if (len < 0) {
+ len = strlen(str);
+ }
+
+ putInt(len);
+ putRawData(str, len);
+}
+
+//==============================================================================
+// Return an arbitrary binary string from the buffer. The string cannot be
+// longer than 256k. The returned value points to memory allocated with new;
+// It is the responsibility of the calling function to free the data.
+//==============================================================================
+
+void *FQTermSSHBuffer::getString(int *length) {
+ u_char *data;
+ u_int len;
+
+ // Get the length.
+ len = getInt();
+ if ((long)len > buffer_size_) {
+ FQ_TRACE("sshbuffer", 0)
+ << "String length " << len
+ << " is greater than buffer size " << buffer_size_;
+ return 0;
+ }
+ // Allocate space for the string. Add one byte for a null character.
+ data = new u_char[len + 1];
+ // Get the string.
+ getRawData((char*)data, len);
+ // Append a null character to make processing easier.
+ data[len] = 0;
+ if (length != NULL) {
+ *length = len;
+ }
+ // return the length of the string.
+ return data;
+}
+
+} // namespace FQTerm