diff options
author | Colin Watson <cjwatson@debian.org> | 2014-10-07 13:33:15 +0100 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2014-10-07 14:27:30 +0100 |
commit | f0b009aea83e9ff3a50be30f51012099a5143c16 (patch) | |
tree | 3825e6f7e3b7ea4481d06ed89aba9a7a95150df5 /buffer.c | |
parent | 47f0bad4330b16ec3bad870fcf9839c196e42c12 (diff) | |
parent | 762c062828f5a8f6ed189ed6e44ad38fd92f8b36 (diff) |
Merge 6.7p1.
* New upstream release (http://www.openssh.com/txt/release-6.7):
- sshd(8): The default set of ciphers and MACs has been altered to
remove unsafe algorithms. In particular, CBC ciphers and arcfour* are
disabled by default. The full set of algorithms remains available if
configured explicitly via the Ciphers and MACs sshd_config options.
- ssh(1), sshd(8): Add support for Unix domain socket forwarding. A
remote TCP port may be forwarded to a local Unix domain socket and
vice versa or both ends may be a Unix domain socket (closes: #236718).
- ssh(1), ssh-keygen(1): Add support for SSHFP DNS records for ED25519
key types.
- sftp(1): Allow resumption of interrupted uploads.
- ssh(1): When rekeying, skip file/DNS lookups of the hostkey if it is
the same as the one sent during initial key exchange.
- sshd(8): Allow explicit ::1 and 127.0.0.1 forwarding bind addresses
when GatewayPorts=no; allows client to choose address family.
- sshd(8): Add a sshd_config PermitUserRC option to control whether
~/.ssh/rc is executed, mirroring the no-user-rc authorized_keys
option.
- ssh(1): Add a %C escape sequence for LocalCommand and ControlPath that
expands to a unique identifer based on a hash of the tuple of (local
host, remote user, hostname, port). Helps avoid exceeding miserly
pathname limits for Unix domain sockets in multiplexing control paths.
- sshd(8): Make the "Too many authentication failures" message include
the user, source address, port and protocol in a format similar to the
authentication success / failure messages.
- Use CLOCK_BOOTTIME in preference to CLOCK_MONOTONIC when it is
available. It considers time spent suspended, thereby ensuring
timeouts (e.g. for expiring agent keys) fire correctly (closes:
#734553).
- Use prctl() to prevent sftp-server from accessing
/proc/self/{mem,maps}.
* Restore TCP wrappers support, removed upstream in 6.7. It is true that
dropping this reduces preauth attack surface in sshd. On the other
hand, this support seems to be quite widely used, and abruptly dropping
it (from the perspective of users who don't read openssh-unix-dev) could
easily cause more serious problems in practice. It's not entirely clear
what the right long-term answer for Debian is, but it at least probably
doesn't involve dropping this feature shortly before a freeze.
* Replace patch to disable OpenSSL version check with an updated version
of Kurt Roeckx's patch from #732940 to just avoid checking the status
field.
Diffstat (limited to 'buffer.c')
-rw-r--r-- | buffer.c | 245 |
1 files changed, 55 insertions, 190 deletions
@@ -1,253 +1,118 @@ | |||
1 | /* $OpenBSD: buffer.c,v 1.35 2014/02/02 03:44:31 djm Exp $ */ | 1 | /* $OpenBSD: buffer.c,v 1.36 2014/04/30 05:29:56 djm Exp $ */ |
2 | |||
2 | /* | 3 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Copyright (c) 2012 Damien Miller <djm@mindrot.org> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 5 | * |
5 | * All rights reserved | 6 | * Permission to use, copy, modify, and distribute this software for any |
6 | * Functions for manipulating fifo buffers (that can grow if needed). | 7 | * purpose with or without fee is hereby granted, provided that the above |
8 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | 9 | * |
8 | * As far as I am concerned, the code I have written for this software | 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | * can be used freely for any purpose. Any derived versions of this | 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | * software must be clearly marked as such, and if the derived work is | 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
11 | * incompatible with the protocol description in the RFC file, it must be | 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | * called by a name other than "ssh" or "Secure Shell". | 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
13 | */ | 17 | */ |
14 | 18 | ||
15 | #include "includes.h" | 19 | /* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */ |
16 | 20 | ||
17 | #include <sys/param.h> | 21 | #include "includes.h" |
18 | 22 | ||
19 | #include <stdio.h> | 23 | #include <sys/types.h> |
20 | #include <string.h> | ||
21 | #include <stdarg.h> | ||
22 | #include <stdlib.h> | ||
23 | 24 | ||
24 | #include "xmalloc.h" | ||
25 | #include "buffer.h" | 25 | #include "buffer.h" |
26 | #include "log.h" | 26 | #include "log.h" |
27 | 27 | #include "ssherr.h" | |
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 | 28 | ||
72 | void | 29 | void |
73 | buffer_append(Buffer *buffer, const void *data, u_int len) | 30 | buffer_append(Buffer *buffer, const void *data, u_int len) |
74 | { | 31 | { |
75 | void *p; | 32 | int ret; |
76 | p = buffer_append_space(buffer, len); | ||
77 | memcpy(p, data, len); | ||
78 | } | ||
79 | 33 | ||
80 | static int | 34 | if ((ret = sshbuf_put(buffer, data, len)) != 0) |
81 | buffer_compact(Buffer *buffer) | 35 | fatal("%s: %s", __func__, ssh_err(ret)); |
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 | } | 36 | } |
96 | 37 | ||
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 * | 38 | void * |
104 | buffer_append_space(Buffer *buffer, u_int len) | 39 | buffer_append_space(Buffer *buffer, u_int len) |
105 | { | 40 | { |
106 | u_int newlen; | 41 | int ret; |
107 | void *p; | 42 | u_char *p; |
108 | 43 | ||
109 | if (len > BUFFER_MAX_CHUNK) | 44 | if ((ret = sshbuf_reserve(buffer, len, &p)) != 0) |
110 | fatal("buffer_append_space: len %u not supported", len); | 45 | fatal("%s: %s", __func__, ssh_err(ret)); |
111 | 46 | return p; | |
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 | } | 47 | } |
139 | 48 | ||
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 | 49 | int |
145 | buffer_check_alloc(Buffer *buffer, u_int len) | 50 | buffer_check_alloc(Buffer *buffer, u_int len) |
146 | { | 51 | { |
147 | if (buffer->offset == buffer->end) { | 52 | int ret = sshbuf_check_reserve(buffer, len); |
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 | 53 | ||
163 | u_int | 54 | if (ret == 0) |
164 | buffer_len(const Buffer *buffer) | 55 | return 1; |
165 | { | 56 | if (ret == SSH_ERR_NO_BUFFER_SPACE) |
166 | return buffer->end - buffer->offset; | 57 | return 0; |
58 | fatal("%s: %s", __func__, ssh_err(ret)); | ||
167 | } | 59 | } |
168 | 60 | ||
169 | /* Gets data from the beginning of the buffer. */ | ||
170 | |||
171 | int | 61 | int |
172 | buffer_get_ret(Buffer *buffer, void *buf, u_int len) | 62 | buffer_get_ret(Buffer *buffer, void *buf, u_int len) |
173 | { | 63 | { |
174 | if (len > buffer->end - buffer->offset) { | 64 | int ret; |
175 | error("buffer_get_ret: trying to get more bytes %d than in buffer %d", | 65 | |
176 | len, buffer->end - buffer->offset); | 66 | if ((ret = sshbuf_get(buffer, buf, len)) != 0) { |
177 | return (-1); | 67 | error("%s: %s", __func__, ssh_err(ret)); |
68 | return -1; | ||
178 | } | 69 | } |
179 | memcpy(buf, buffer->buf + buffer->offset, len); | 70 | return 0; |
180 | buffer->offset += len; | ||
181 | return (0); | ||
182 | } | 71 | } |
183 | 72 | ||
184 | void | 73 | void |
185 | buffer_get(Buffer *buffer, void *buf, u_int len) | 74 | buffer_get(Buffer *buffer, void *buf, u_int len) |
186 | { | 75 | { |
187 | if (buffer_get_ret(buffer, buf, len) == -1) | 76 | if (buffer_get_ret(buffer, buf, len) == -1) |
188 | fatal("buffer_get: buffer error"); | 77 | fatal("%s: buffer error", __func__); |
189 | } | 78 | } |
190 | 79 | ||
191 | /* Consumes the given number of bytes from the beginning of the buffer. */ | ||
192 | |||
193 | int | 80 | int |
194 | buffer_consume_ret(Buffer *buffer, u_int bytes) | 81 | buffer_consume_ret(Buffer *buffer, u_int bytes) |
195 | { | 82 | { |
196 | if (bytes > buffer->end - buffer->offset) { | 83 | int ret = sshbuf_consume(buffer, bytes); |
197 | error("buffer_consume_ret: trying to get more bytes than in buffer"); | 84 | |
198 | return (-1); | 85 | if (ret == 0) |
199 | } | 86 | return 0; |
200 | buffer->offset += bytes; | 87 | if (ret == SSH_ERR_MESSAGE_INCOMPLETE) |
201 | return (0); | 88 | return -1; |
89 | fatal("%s: %s", __func__, ssh_err(ret)); | ||
202 | } | 90 | } |
203 | 91 | ||
204 | void | 92 | void |
205 | buffer_consume(Buffer *buffer, u_int bytes) | 93 | buffer_consume(Buffer *buffer, u_int bytes) |
206 | { | 94 | { |
207 | if (buffer_consume_ret(buffer, bytes) == -1) | 95 | if (buffer_consume_ret(buffer, bytes) == -1) |
208 | fatal("buffer_consume: buffer error"); | 96 | fatal("%s: buffer error", __func__); |
209 | } | 97 | } |
210 | 98 | ||
211 | /* Consumes the given number of bytes from the end of the buffer. */ | ||
212 | |||
213 | int | 99 | int |
214 | buffer_consume_end_ret(Buffer *buffer, u_int bytes) | 100 | buffer_consume_end_ret(Buffer *buffer, u_int bytes) |
215 | { | 101 | { |
216 | if (bytes > buffer->end - buffer->offset) | 102 | int ret = sshbuf_consume_end(buffer, bytes); |
217 | return (-1); | 103 | |
218 | buffer->end -= bytes; | 104 | if (ret == 0) |
219 | return (0); | 105 | return 0; |
106 | if (ret == SSH_ERR_MESSAGE_INCOMPLETE) | ||
107 | return -1; | ||
108 | fatal("%s: %s", __func__, ssh_err(ret)); | ||
220 | } | 109 | } |
221 | 110 | ||
222 | void | 111 | void |
223 | buffer_consume_end(Buffer *buffer, u_int bytes) | 112 | buffer_consume_end(Buffer *buffer, u_int bytes) |
224 | { | 113 | { |
225 | if (buffer_consume_end_ret(buffer, bytes) == -1) | 114 | if (buffer_consume_end_ret(buffer, bytes) == -1) |
226 | fatal("buffer_consume_end: trying to get more bytes than in buffer"); | 115 | fatal("%s: buffer error", __func__); |
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 | } | 116 | } |
236 | 117 | ||
237 | /* Dumps the contents of the buffer to stderr. */ | ||
238 | 118 | ||
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 | } | ||