]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - crypto/openssh/buffer.c
MFH (r291198, r291260, r291261, r291375, r294325, r294335, r294563)
[FreeBSD/stable/10.git] / crypto / openssh / buffer.c
1 /* $OpenBSD: buffer.c,v 1.35 2014/02/02 03:44:31 djm Exp $ */
2 /*
3  * Author: Tatu Ylonen <ylo@cs.hut.fi>
4  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5  *                    All rights reserved
6  * Functions for manipulating fifo buffers (that can grow if needed).
7  *
8  * As far as I am concerned, the code I have written for this software
9  * can be used freely for any purpose.  Any derived versions of this
10  * software must be clearly marked as such, and if the derived work is
11  * incompatible with the protocol description in the RFC file, it must be
12  * called by a name other than "ssh" or "Secure Shell".
13  */
14
15 #include "includes.h"
16
17 #include <sys/param.h>
18
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdarg.h>
22 #include <stdlib.h>
23
24 #include "xmalloc.h"
25 #include "buffer.h"
26 #include "log.h"
27
28 #define BUFFER_MAX_CHUNK        0x100000
29 #define BUFFER_MAX_LEN          0xa00000
30 #define BUFFER_ALLOCSZ          0x008000
31
32 /* Initializes the buffer structure. */
33
34 void
35 buffer_init(Buffer *buffer)
36 {
37         const u_int len = 4096;
38
39         buffer->alloc = 0;
40         buffer->buf = xmalloc(len);
41         buffer->alloc = len;
42         buffer->offset = 0;
43         buffer->end = 0;
44 }
45
46 /* Frees any memory used for the buffer. */
47
48 void
49 buffer_free(Buffer *buffer)
50 {
51         if (buffer->alloc > 0) {
52                 explicit_bzero(buffer->buf, buffer->alloc);
53                 buffer->alloc = 0;
54                 free(buffer->buf);
55         }
56 }
57
58 /*
59  * Clears any data from the buffer, making it empty.  This does not actually
60  * zero the memory.
61  */
62
63 void
64 buffer_clear(Buffer *buffer)
65 {
66         buffer->offset = 0;
67         buffer->end = 0;
68 }
69
70 /* Appends data to the buffer, expanding it if necessary. */
71
72 void
73 buffer_append(Buffer *buffer, const void *data, u_int len)
74 {
75         void *p;
76         p = buffer_append_space(buffer, len);
77         memcpy(p, data, len);
78 }
79
80 static int
81 buffer_compact(Buffer *buffer)
82 {
83         /*
84          * If the buffer is quite empty, but all data is at the end, move the
85          * data to the beginning.
86          */
87         if (buffer->offset > MIN(buffer->alloc, BUFFER_MAX_CHUNK)) {
88                 memmove(buffer->buf, buffer->buf + buffer->offset,
89                         buffer->end - buffer->offset);
90                 buffer->end -= buffer->offset;
91                 buffer->offset = 0;
92                 return (1);
93         }
94         return (0);
95 }
96
97 /*
98  * Appends space to the buffer, expanding the buffer if necessary. This does
99  * not actually copy the data into the buffer, but instead returns a pointer
100  * to the allocated region.
101  */
102
103 void *
104 buffer_append_space(Buffer *buffer, u_int len)
105 {
106         u_int newlen;
107         void *p;
108
109         if (len > BUFFER_MAX_CHUNK)
110                 fatal("buffer_append_space: len %u not supported", len);
111
112         /* If the buffer is empty, start using it from the beginning. */
113         if (buffer->offset == buffer->end) {
114                 buffer->offset = 0;
115                 buffer->end = 0;
116         }
117 restart:
118         /* If there is enough space to store all data, store it now. */
119         if (buffer->end + len < buffer->alloc) {
120                 p = buffer->buf + buffer->end;
121                 buffer->end += len;
122                 return p;
123         }
124
125         /* Compact data back to the start of the buffer if necessary */
126         if (buffer_compact(buffer))
127                 goto restart;
128
129         /* Increase the size of the buffer and retry. */
130         newlen = roundup(buffer->alloc + len, BUFFER_ALLOCSZ);
131         if (newlen > BUFFER_MAX_LEN)
132                 fatal("buffer_append_space: alloc %u not supported",
133                     newlen);
134         buffer->buf = xrealloc(buffer->buf, 1, newlen);
135         buffer->alloc = newlen;
136         goto restart;
137         /* NOTREACHED */
138 }
139
140 /*
141  * Check whether an allocation of 'len' will fit in the buffer
142  * This must follow the same math as buffer_append_space
143  */
144 int
145 buffer_check_alloc(Buffer *buffer, u_int len)
146 {
147         if (buffer->offset == buffer->end) {
148                 buffer->offset = 0;
149                 buffer->end = 0;
150         }
151  restart:
152         if (buffer->end + len < buffer->alloc)
153                 return (1);
154         if (buffer_compact(buffer))
155                 goto restart;
156         if (roundup(buffer->alloc + len, BUFFER_ALLOCSZ) <= BUFFER_MAX_LEN)
157                 return (1);
158         return (0);
159 }
160
161 /* Returns the number of bytes of data in the buffer. */
162
163 u_int
164 buffer_len(const Buffer *buffer)
165 {
166         return buffer->end - buffer->offset;
167 }
168
169 /* Gets data from the beginning of the buffer. */
170
171 int
172 buffer_get_ret(Buffer *buffer, void *buf, u_int len)
173 {
174         if (len > buffer->end - buffer->offset) {
175                 error("buffer_get_ret: trying to get more bytes %d than in buffer %d",
176                     len, buffer->end - buffer->offset);
177                 return (-1);
178         }
179         memcpy(buf, buffer->buf + buffer->offset, len);
180         buffer->offset += len;
181         return (0);
182 }
183
184 void
185 buffer_get(Buffer *buffer, void *buf, u_int len)
186 {
187         if (buffer_get_ret(buffer, buf, len) == -1)
188                 fatal("buffer_get: buffer error");
189 }
190
191 /* Consumes the given number of bytes from the beginning of the buffer. */
192
193 int
194 buffer_consume_ret(Buffer *buffer, u_int bytes)
195 {
196         if (bytes > buffer->end - buffer->offset) {
197                 error("buffer_consume_ret: trying to get more bytes than in buffer");
198                 return (-1);
199         }
200         buffer->offset += bytes;
201         return (0);
202 }
203
204 void
205 buffer_consume(Buffer *buffer, u_int bytes)
206 {
207         if (buffer_consume_ret(buffer, bytes) == -1)
208                 fatal("buffer_consume: buffer error");
209 }
210
211 /* Consumes the given number of bytes from the end of the buffer. */
212
213 int
214 buffer_consume_end_ret(Buffer *buffer, u_int bytes)
215 {
216         if (bytes > buffer->end - buffer->offset)
217                 return (-1);
218         buffer->end -= bytes;
219         return (0);
220 }
221
222 void
223 buffer_consume_end(Buffer *buffer, u_int bytes)
224 {
225         if (buffer_consume_end_ret(buffer, bytes) == -1)
226                 fatal("buffer_consume_end: trying to get more bytes than in buffer");
227 }
228
229 /* Returns a pointer to the first used byte in the buffer. */
230
231 void *
232 buffer_ptr(const Buffer *buffer)
233 {
234         return buffer->buf + buffer->offset;
235 }
236
237 /* Dumps the contents of the buffer to stderr. */
238
239 void
240 buffer_dump(const Buffer *buffer)
241 {
242         u_int i;
243         u_char *ucp = buffer->buf;
244
245         for (i = buffer->offset; i < buffer->end; i++) {
246                 fprintf(stderr, "%02x", ucp[i]);
247                 if ((i-buffer->offset)%16==15)
248                         fprintf(stderr, "\r\n");
249                 else if ((i-buffer->offset)%2==1)
250                         fprintf(stderr, " ");
251         }
252         fprintf(stderr, "\r\n");
253 }