14f52dfbbSDag-Erling Smørgrav /* $OpenBSD: sshbuf-getput-basic.c,v 1.7 2017/06/01 04:51:58 djm Exp $ */
2a0ee8cc6SDag-Erling Smørgrav /*
3a0ee8cc6SDag-Erling Smørgrav * Copyright (c) 2011 Damien Miller
4a0ee8cc6SDag-Erling Smørgrav *
5a0ee8cc6SDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any
6a0ee8cc6SDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above
7a0ee8cc6SDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies.
8a0ee8cc6SDag-Erling Smørgrav *
9a0ee8cc6SDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10a0ee8cc6SDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11a0ee8cc6SDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12a0ee8cc6SDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13a0ee8cc6SDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14a0ee8cc6SDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15a0ee8cc6SDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16a0ee8cc6SDag-Erling Smørgrav */
17a0ee8cc6SDag-Erling Smørgrav
18a0ee8cc6SDag-Erling Smørgrav #define SSHBUF_INTERNAL
19a0ee8cc6SDag-Erling Smørgrav #include "includes.h"
20a0ee8cc6SDag-Erling Smørgrav
21a0ee8cc6SDag-Erling Smørgrav #include <sys/types.h>
22076ad2f8SDag-Erling Smørgrav
23076ad2f8SDag-Erling Smørgrav #include <stdarg.h>
24a0ee8cc6SDag-Erling Smørgrav #include <stdlib.h>
25a0ee8cc6SDag-Erling Smørgrav #include <stdio.h>
26a0ee8cc6SDag-Erling Smørgrav #include <string.h>
27a0ee8cc6SDag-Erling Smørgrav
28fc3c19a9SEd Maste #include "xmalloc.h"
29a0ee8cc6SDag-Erling Smørgrav #include "ssherr.h"
30a0ee8cc6SDag-Erling Smørgrav #include "sshbuf.h"
31a0ee8cc6SDag-Erling Smørgrav
32a0ee8cc6SDag-Erling Smørgrav int
sshbuf_get(struct sshbuf * buf,void * v,size_t len)33a0ee8cc6SDag-Erling Smørgrav sshbuf_get(struct sshbuf *buf, void *v, size_t len)
34a0ee8cc6SDag-Erling Smørgrav {
35a0ee8cc6SDag-Erling Smørgrav const u_char *p = sshbuf_ptr(buf);
36a0ee8cc6SDag-Erling Smørgrav int r;
37a0ee8cc6SDag-Erling Smørgrav
38a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_consume(buf, len)) < 0)
39a0ee8cc6SDag-Erling Smørgrav return r;
40bc5531deSDag-Erling Smørgrav if (v != NULL && len != 0)
41a0ee8cc6SDag-Erling Smørgrav memcpy(v, p, len);
42a0ee8cc6SDag-Erling Smørgrav return 0;
43a0ee8cc6SDag-Erling Smørgrav }
44a0ee8cc6SDag-Erling Smørgrav
45a0ee8cc6SDag-Erling Smørgrav int
sshbuf_get_u64(struct sshbuf * buf,u_int64_t * valp)46a0ee8cc6SDag-Erling Smørgrav sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp)
47a0ee8cc6SDag-Erling Smørgrav {
48a0ee8cc6SDag-Erling Smørgrav const u_char *p = sshbuf_ptr(buf);
49a0ee8cc6SDag-Erling Smørgrav int r;
50a0ee8cc6SDag-Erling Smørgrav
51a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_consume(buf, 8)) < 0)
52a0ee8cc6SDag-Erling Smørgrav return r;
53a0ee8cc6SDag-Erling Smørgrav if (valp != NULL)
54a0ee8cc6SDag-Erling Smørgrav *valp = PEEK_U64(p);
55a0ee8cc6SDag-Erling Smørgrav return 0;
56a0ee8cc6SDag-Erling Smørgrav }
57a0ee8cc6SDag-Erling Smørgrav
58a0ee8cc6SDag-Erling Smørgrav int
sshbuf_get_u32(struct sshbuf * buf,u_int32_t * valp)59a0ee8cc6SDag-Erling Smørgrav sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp)
60a0ee8cc6SDag-Erling Smørgrav {
61a0ee8cc6SDag-Erling Smørgrav const u_char *p = sshbuf_ptr(buf);
62a0ee8cc6SDag-Erling Smørgrav int r;
63a0ee8cc6SDag-Erling Smørgrav
64a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_consume(buf, 4)) < 0)
65a0ee8cc6SDag-Erling Smørgrav return r;
66a0ee8cc6SDag-Erling Smørgrav if (valp != NULL)
67a0ee8cc6SDag-Erling Smørgrav *valp = PEEK_U32(p);
68a0ee8cc6SDag-Erling Smørgrav return 0;
69a0ee8cc6SDag-Erling Smørgrav }
70a0ee8cc6SDag-Erling Smørgrav
71a0ee8cc6SDag-Erling Smørgrav int
sshbuf_get_u16(struct sshbuf * buf,u_int16_t * valp)72a0ee8cc6SDag-Erling Smørgrav sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp)
73a0ee8cc6SDag-Erling Smørgrav {
74a0ee8cc6SDag-Erling Smørgrav const u_char *p = sshbuf_ptr(buf);
75a0ee8cc6SDag-Erling Smørgrav int r;
76a0ee8cc6SDag-Erling Smørgrav
77a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_consume(buf, 2)) < 0)
78a0ee8cc6SDag-Erling Smørgrav return r;
79a0ee8cc6SDag-Erling Smørgrav if (valp != NULL)
80a0ee8cc6SDag-Erling Smørgrav *valp = PEEK_U16(p);
81a0ee8cc6SDag-Erling Smørgrav return 0;
82a0ee8cc6SDag-Erling Smørgrav }
83a0ee8cc6SDag-Erling Smørgrav
84a0ee8cc6SDag-Erling Smørgrav int
sshbuf_get_u8(struct sshbuf * buf,u_char * valp)85a0ee8cc6SDag-Erling Smørgrav sshbuf_get_u8(struct sshbuf *buf, u_char *valp)
86a0ee8cc6SDag-Erling Smørgrav {
87a0ee8cc6SDag-Erling Smørgrav const u_char *p = sshbuf_ptr(buf);
88a0ee8cc6SDag-Erling Smørgrav int r;
89a0ee8cc6SDag-Erling Smørgrav
90a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_consume(buf, 1)) < 0)
91a0ee8cc6SDag-Erling Smørgrav return r;
92a0ee8cc6SDag-Erling Smørgrav if (valp != NULL)
93a0ee8cc6SDag-Erling Smørgrav *valp = (u_int8_t)*p;
94a0ee8cc6SDag-Erling Smørgrav return 0;
95a0ee8cc6SDag-Erling Smørgrav }
96a0ee8cc6SDag-Erling Smørgrav
97a0ee8cc6SDag-Erling Smørgrav int
sshbuf_get_string(struct sshbuf * buf,u_char ** valp,size_t * lenp)98a0ee8cc6SDag-Erling Smørgrav sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp)
99a0ee8cc6SDag-Erling Smørgrav {
100a0ee8cc6SDag-Erling Smørgrav const u_char *val;
101a0ee8cc6SDag-Erling Smørgrav size_t len;
102a0ee8cc6SDag-Erling Smørgrav int r;
103a0ee8cc6SDag-Erling Smørgrav
104a0ee8cc6SDag-Erling Smørgrav if (valp != NULL)
105a0ee8cc6SDag-Erling Smørgrav *valp = NULL;
106a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL)
107a0ee8cc6SDag-Erling Smørgrav *lenp = 0;
108a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_get_string_direct(buf, &val, &len)) < 0)
109a0ee8cc6SDag-Erling Smørgrav return r;
110a0ee8cc6SDag-Erling Smørgrav if (valp != NULL) {
111a0ee8cc6SDag-Erling Smørgrav if ((*valp = malloc(len + 1)) == NULL) {
112a0ee8cc6SDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
113a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL;
114a0ee8cc6SDag-Erling Smørgrav }
115bc5531deSDag-Erling Smørgrav if (len != 0)
116a0ee8cc6SDag-Erling Smørgrav memcpy(*valp, val, len);
117a0ee8cc6SDag-Erling Smørgrav (*valp)[len] = '\0';
118a0ee8cc6SDag-Erling Smørgrav }
119a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL)
120a0ee8cc6SDag-Erling Smørgrav *lenp = len;
121a0ee8cc6SDag-Erling Smørgrav return 0;
122a0ee8cc6SDag-Erling Smørgrav }
123a0ee8cc6SDag-Erling Smørgrav
124a0ee8cc6SDag-Erling Smørgrav int
sshbuf_get_string_direct(struct sshbuf * buf,const u_char ** valp,size_t * lenp)125a0ee8cc6SDag-Erling Smørgrav sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, size_t *lenp)
126a0ee8cc6SDag-Erling Smørgrav {
127a0ee8cc6SDag-Erling Smørgrav size_t len;
128a0ee8cc6SDag-Erling Smørgrav const u_char *p;
129a0ee8cc6SDag-Erling Smørgrav int r;
130a0ee8cc6SDag-Erling Smørgrav
131a0ee8cc6SDag-Erling Smørgrav if (valp != NULL)
132a0ee8cc6SDag-Erling Smørgrav *valp = NULL;
133a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL)
134a0ee8cc6SDag-Erling Smørgrav *lenp = 0;
135a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_peek_string_direct(buf, &p, &len)) < 0)
136a0ee8cc6SDag-Erling Smørgrav return r;
137acc1a9efSDag-Erling Smørgrav if (valp != NULL)
138a0ee8cc6SDag-Erling Smørgrav *valp = p;
139a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL)
140a0ee8cc6SDag-Erling Smørgrav *lenp = len;
141a0ee8cc6SDag-Erling Smørgrav if (sshbuf_consume(buf, len + 4) != 0) {
142a0ee8cc6SDag-Erling Smørgrav /* Shouldn't happen */
143a0ee8cc6SDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
144a0ee8cc6SDag-Erling Smørgrav SSHBUF_ABORT();
145a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR;
146a0ee8cc6SDag-Erling Smørgrav }
147a0ee8cc6SDag-Erling Smørgrav return 0;
148a0ee8cc6SDag-Erling Smørgrav }
149a0ee8cc6SDag-Erling Smørgrav
150a0ee8cc6SDag-Erling Smørgrav int
sshbuf_peek_string_direct(const struct sshbuf * buf,const u_char ** valp,size_t * lenp)151a0ee8cc6SDag-Erling Smørgrav sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp,
152a0ee8cc6SDag-Erling Smørgrav size_t *lenp)
153a0ee8cc6SDag-Erling Smørgrav {
154a0ee8cc6SDag-Erling Smørgrav u_int32_t len;
155a0ee8cc6SDag-Erling Smørgrav const u_char *p = sshbuf_ptr(buf);
156a0ee8cc6SDag-Erling Smørgrav
157a0ee8cc6SDag-Erling Smørgrav if (valp != NULL)
158a0ee8cc6SDag-Erling Smørgrav *valp = NULL;
159a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL)
160a0ee8cc6SDag-Erling Smørgrav *lenp = 0;
161a0ee8cc6SDag-Erling Smørgrav if (sshbuf_len(buf) < 4) {
162a0ee8cc6SDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
163a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_MESSAGE_INCOMPLETE;
164a0ee8cc6SDag-Erling Smørgrav }
165a0ee8cc6SDag-Erling Smørgrav len = PEEK_U32(p);
166a0ee8cc6SDag-Erling Smørgrav if (len > SSHBUF_SIZE_MAX - 4) {
167a0ee8cc6SDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE"));
168a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_STRING_TOO_LARGE;
169a0ee8cc6SDag-Erling Smørgrav }
170a0ee8cc6SDag-Erling Smørgrav if (sshbuf_len(buf) - 4 < len) {
171a0ee8cc6SDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
172a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_MESSAGE_INCOMPLETE;
173a0ee8cc6SDag-Erling Smørgrav }
174acc1a9efSDag-Erling Smørgrav if (valp != NULL)
175a0ee8cc6SDag-Erling Smørgrav *valp = p + 4;
176a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL)
177a0ee8cc6SDag-Erling Smørgrav *lenp = len;
178a0ee8cc6SDag-Erling Smørgrav return 0;
179a0ee8cc6SDag-Erling Smørgrav }
180a0ee8cc6SDag-Erling Smørgrav
181a0ee8cc6SDag-Erling Smørgrav int
sshbuf_get_cstring(struct sshbuf * buf,char ** valp,size_t * lenp)182a0ee8cc6SDag-Erling Smørgrav sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp)
183a0ee8cc6SDag-Erling Smørgrav {
184a0ee8cc6SDag-Erling Smørgrav size_t len;
185a0ee8cc6SDag-Erling Smørgrav const u_char *p, *z;
186a0ee8cc6SDag-Erling Smørgrav int r;
187a0ee8cc6SDag-Erling Smørgrav
188a0ee8cc6SDag-Erling Smørgrav if (valp != NULL)
189a0ee8cc6SDag-Erling Smørgrav *valp = NULL;
190a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL)
191a0ee8cc6SDag-Erling Smørgrav *lenp = 0;
192a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
193a0ee8cc6SDag-Erling Smørgrav return r;
194a0ee8cc6SDag-Erling Smørgrav /* Allow a \0 only at the end of the string */
195a0ee8cc6SDag-Erling Smørgrav if (len > 0 &&
196a0ee8cc6SDag-Erling Smørgrav (z = memchr(p , '\0', len)) != NULL && z < p + len - 1) {
197a0ee8cc6SDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT"));
198a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_FORMAT;
199a0ee8cc6SDag-Erling Smørgrav }
200a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_skip_string(buf)) != 0)
201a0ee8cc6SDag-Erling Smørgrav return -1;
202a0ee8cc6SDag-Erling Smørgrav if (valp != NULL) {
203a0ee8cc6SDag-Erling Smørgrav if ((*valp = malloc(len + 1)) == NULL) {
204a0ee8cc6SDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
205a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL;
206a0ee8cc6SDag-Erling Smørgrav }
207bc5531deSDag-Erling Smørgrav if (len != 0)
208a0ee8cc6SDag-Erling Smørgrav memcpy(*valp, p, len);
209a0ee8cc6SDag-Erling Smørgrav (*valp)[len] = '\0';
210a0ee8cc6SDag-Erling Smørgrav }
211a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL)
212a0ee8cc6SDag-Erling Smørgrav *lenp = (size_t)len;
213a0ee8cc6SDag-Erling Smørgrav return 0;
214a0ee8cc6SDag-Erling Smørgrav }
215a0ee8cc6SDag-Erling Smørgrav
216a0ee8cc6SDag-Erling Smørgrav int
sshbuf_get_stringb(struct sshbuf * buf,struct sshbuf * v)217a0ee8cc6SDag-Erling Smørgrav sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v)
218a0ee8cc6SDag-Erling Smørgrav {
219a0ee8cc6SDag-Erling Smørgrav u_int32_t len;
220a0ee8cc6SDag-Erling Smørgrav u_char *p;
221a0ee8cc6SDag-Erling Smørgrav int r;
222a0ee8cc6SDag-Erling Smørgrav
223a0ee8cc6SDag-Erling Smørgrav /*
224a0ee8cc6SDag-Erling Smørgrav * Use sshbuf_peek_string_direct() to figure out if there is
225a0ee8cc6SDag-Erling Smørgrav * a complete string in 'buf' and copy the string directly
226a0ee8cc6SDag-Erling Smørgrav * into 'v'.
227a0ee8cc6SDag-Erling Smørgrav */
228a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_peek_string_direct(buf, NULL, NULL)) != 0 ||
229a0ee8cc6SDag-Erling Smørgrav (r = sshbuf_get_u32(buf, &len)) != 0 ||
230a0ee8cc6SDag-Erling Smørgrav (r = sshbuf_reserve(v, len, &p)) != 0 ||
231a0ee8cc6SDag-Erling Smørgrav (r = sshbuf_get(buf, p, len)) != 0)
232a0ee8cc6SDag-Erling Smørgrav return r;
233a0ee8cc6SDag-Erling Smørgrav return 0;
234a0ee8cc6SDag-Erling Smørgrav }
235a0ee8cc6SDag-Erling Smørgrav
236a0ee8cc6SDag-Erling Smørgrav int
sshbuf_put(struct sshbuf * buf,const void * v,size_t len)237a0ee8cc6SDag-Erling Smørgrav sshbuf_put(struct sshbuf *buf, const void *v, size_t len)
238a0ee8cc6SDag-Erling Smørgrav {
239a0ee8cc6SDag-Erling Smørgrav u_char *p;
240a0ee8cc6SDag-Erling Smørgrav int r;
241a0ee8cc6SDag-Erling Smørgrav
242a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_reserve(buf, len, &p)) < 0)
243a0ee8cc6SDag-Erling Smørgrav return r;
244bc5531deSDag-Erling Smørgrav if (len != 0)
245a0ee8cc6SDag-Erling Smørgrav memcpy(p, v, len);
246a0ee8cc6SDag-Erling Smørgrav return 0;
247a0ee8cc6SDag-Erling Smørgrav }
248a0ee8cc6SDag-Erling Smørgrav
249a0ee8cc6SDag-Erling Smørgrav int
sshbuf_putb(struct sshbuf * buf,const struct sshbuf * v)250a0ee8cc6SDag-Erling Smørgrav sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v)
251a0ee8cc6SDag-Erling Smørgrav {
252a0ee8cc6SDag-Erling Smørgrav return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v));
253a0ee8cc6SDag-Erling Smørgrav }
254a0ee8cc6SDag-Erling Smørgrav
255a0ee8cc6SDag-Erling Smørgrav int
sshbuf_putf(struct sshbuf * buf,const char * fmt,...)256a0ee8cc6SDag-Erling Smørgrav sshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
257a0ee8cc6SDag-Erling Smørgrav {
258a0ee8cc6SDag-Erling Smørgrav va_list ap;
259a0ee8cc6SDag-Erling Smørgrav int r;
260a0ee8cc6SDag-Erling Smørgrav
261a0ee8cc6SDag-Erling Smørgrav va_start(ap, fmt);
262a0ee8cc6SDag-Erling Smørgrav r = sshbuf_putfv(buf, fmt, ap);
263a0ee8cc6SDag-Erling Smørgrav va_end(ap);
264a0ee8cc6SDag-Erling Smørgrav return r;
265a0ee8cc6SDag-Erling Smørgrav }
266a0ee8cc6SDag-Erling Smørgrav
267a0ee8cc6SDag-Erling Smørgrav int
sshbuf_putfv(struct sshbuf * buf,const char * fmt,va_list ap)268a0ee8cc6SDag-Erling Smørgrav sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap)
269a0ee8cc6SDag-Erling Smørgrav {
270a0ee8cc6SDag-Erling Smørgrav va_list ap2;
271a0ee8cc6SDag-Erling Smørgrav int r, len;
272a0ee8cc6SDag-Erling Smørgrav u_char *p;
273a0ee8cc6SDag-Erling Smørgrav
274076ad2f8SDag-Erling Smørgrav VA_COPY(ap2, ap);
275a0ee8cc6SDag-Erling Smørgrav if ((len = vsnprintf(NULL, 0, fmt, ap2)) < 0) {
276a0ee8cc6SDag-Erling Smørgrav r = SSH_ERR_INVALID_ARGUMENT;
277a0ee8cc6SDag-Erling Smørgrav goto out;
278a0ee8cc6SDag-Erling Smørgrav }
279a0ee8cc6SDag-Erling Smørgrav if (len == 0) {
280a0ee8cc6SDag-Erling Smørgrav r = 0;
281a0ee8cc6SDag-Erling Smørgrav goto out; /* Nothing to do */
282a0ee8cc6SDag-Erling Smørgrav }
283a0ee8cc6SDag-Erling Smørgrav va_end(ap2);
284076ad2f8SDag-Erling Smørgrav VA_COPY(ap2, ap);
285a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_reserve(buf, (size_t)len + 1, &p)) < 0)
286a0ee8cc6SDag-Erling Smørgrav goto out;
287a0ee8cc6SDag-Erling Smørgrav if ((r = vsnprintf((char *)p, len + 1, fmt, ap2)) != len) {
288a0ee8cc6SDag-Erling Smørgrav r = SSH_ERR_INTERNAL_ERROR;
289a0ee8cc6SDag-Erling Smørgrav goto out; /* Shouldn't happen */
290a0ee8cc6SDag-Erling Smørgrav }
291a0ee8cc6SDag-Erling Smørgrav /* Consume terminating \0 */
292a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_consume_end(buf, 1)) != 0)
293a0ee8cc6SDag-Erling Smørgrav goto out;
294a0ee8cc6SDag-Erling Smørgrav r = 0;
295a0ee8cc6SDag-Erling Smørgrav out:
296a0ee8cc6SDag-Erling Smørgrav va_end(ap2);
297a0ee8cc6SDag-Erling Smørgrav return r;
298a0ee8cc6SDag-Erling Smørgrav }
299a0ee8cc6SDag-Erling Smørgrav
300a0ee8cc6SDag-Erling Smørgrav int
sshbuf_put_u64(struct sshbuf * buf,u_int64_t val)301a0ee8cc6SDag-Erling Smørgrav sshbuf_put_u64(struct sshbuf *buf, u_int64_t val)
302a0ee8cc6SDag-Erling Smørgrav {
303a0ee8cc6SDag-Erling Smørgrav u_char *p;
304a0ee8cc6SDag-Erling Smørgrav int r;
305a0ee8cc6SDag-Erling Smørgrav
306a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_reserve(buf, 8, &p)) < 0)
307a0ee8cc6SDag-Erling Smørgrav return r;
308a0ee8cc6SDag-Erling Smørgrav POKE_U64(p, val);
309a0ee8cc6SDag-Erling Smørgrav return 0;
310a0ee8cc6SDag-Erling Smørgrav }
311a0ee8cc6SDag-Erling Smørgrav
312a0ee8cc6SDag-Erling Smørgrav int
sshbuf_put_u32(struct sshbuf * buf,u_int32_t val)313a0ee8cc6SDag-Erling Smørgrav sshbuf_put_u32(struct sshbuf *buf, u_int32_t val)
314a0ee8cc6SDag-Erling Smørgrav {
315a0ee8cc6SDag-Erling Smørgrav u_char *p;
316a0ee8cc6SDag-Erling Smørgrav int r;
317a0ee8cc6SDag-Erling Smørgrav
318a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_reserve(buf, 4, &p)) < 0)
319a0ee8cc6SDag-Erling Smørgrav return r;
320a0ee8cc6SDag-Erling Smørgrav POKE_U32(p, val);
321a0ee8cc6SDag-Erling Smørgrav return 0;
322a0ee8cc6SDag-Erling Smørgrav }
323a0ee8cc6SDag-Erling Smørgrav
324a0ee8cc6SDag-Erling Smørgrav int
sshbuf_put_u16(struct sshbuf * buf,u_int16_t val)325a0ee8cc6SDag-Erling Smørgrav sshbuf_put_u16(struct sshbuf *buf, u_int16_t val)
326a0ee8cc6SDag-Erling Smørgrav {
327a0ee8cc6SDag-Erling Smørgrav u_char *p;
328a0ee8cc6SDag-Erling Smørgrav int r;
329a0ee8cc6SDag-Erling Smørgrav
330a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_reserve(buf, 2, &p)) < 0)
331a0ee8cc6SDag-Erling Smørgrav return r;
332a0ee8cc6SDag-Erling Smørgrav POKE_U16(p, val);
333a0ee8cc6SDag-Erling Smørgrav return 0;
334a0ee8cc6SDag-Erling Smørgrav }
335a0ee8cc6SDag-Erling Smørgrav
336a0ee8cc6SDag-Erling Smørgrav int
sshbuf_put_u8(struct sshbuf * buf,u_char val)337a0ee8cc6SDag-Erling Smørgrav sshbuf_put_u8(struct sshbuf *buf, u_char val)
338a0ee8cc6SDag-Erling Smørgrav {
339a0ee8cc6SDag-Erling Smørgrav u_char *p;
340a0ee8cc6SDag-Erling Smørgrav int r;
341a0ee8cc6SDag-Erling Smørgrav
342a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_reserve(buf, 1, &p)) < 0)
343a0ee8cc6SDag-Erling Smørgrav return r;
344a0ee8cc6SDag-Erling Smørgrav p[0] = val;
345a0ee8cc6SDag-Erling Smørgrav return 0;
346a0ee8cc6SDag-Erling Smørgrav }
347a0ee8cc6SDag-Erling Smørgrav
348a0ee8cc6SDag-Erling Smørgrav int
sshbuf_put_string(struct sshbuf * buf,const void * v,size_t len)349a0ee8cc6SDag-Erling Smørgrav sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len)
350a0ee8cc6SDag-Erling Smørgrav {
351a0ee8cc6SDag-Erling Smørgrav u_char *d;
352a0ee8cc6SDag-Erling Smørgrav int r;
353a0ee8cc6SDag-Erling Smørgrav
354a0ee8cc6SDag-Erling Smørgrav if (len > SSHBUF_SIZE_MAX - 4) {
355a0ee8cc6SDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
356a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_NO_BUFFER_SPACE;
357a0ee8cc6SDag-Erling Smørgrav }
358a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0)
359a0ee8cc6SDag-Erling Smørgrav return r;
360a0ee8cc6SDag-Erling Smørgrav POKE_U32(d, len);
361bc5531deSDag-Erling Smørgrav if (len != 0)
362a0ee8cc6SDag-Erling Smørgrav memcpy(d + 4, v, len);
363a0ee8cc6SDag-Erling Smørgrav return 0;
364a0ee8cc6SDag-Erling Smørgrav }
365a0ee8cc6SDag-Erling Smørgrav
366a0ee8cc6SDag-Erling Smørgrav int
sshbuf_put_cstring(struct sshbuf * buf,const char * v)367a0ee8cc6SDag-Erling Smørgrav sshbuf_put_cstring(struct sshbuf *buf, const char *v)
368a0ee8cc6SDag-Erling Smørgrav {
3694f52dfbbSDag-Erling Smørgrav return sshbuf_put_string(buf, v, v == NULL ? 0 : strlen(v));
370a0ee8cc6SDag-Erling Smørgrav }
371a0ee8cc6SDag-Erling Smørgrav
372a0ee8cc6SDag-Erling Smørgrav int
sshbuf_put_stringb(struct sshbuf * buf,const struct sshbuf * v)373a0ee8cc6SDag-Erling Smørgrav sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v)
374a0ee8cc6SDag-Erling Smørgrav {
375a0ee8cc6SDag-Erling Smørgrav return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v));
376a0ee8cc6SDag-Erling Smørgrav }
377a0ee8cc6SDag-Erling Smørgrav
378a0ee8cc6SDag-Erling Smørgrav int
sshbuf_froms(struct sshbuf * buf,struct sshbuf ** bufp)379a0ee8cc6SDag-Erling Smørgrav sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp)
380a0ee8cc6SDag-Erling Smørgrav {
381a0ee8cc6SDag-Erling Smørgrav const u_char *p;
382a0ee8cc6SDag-Erling Smørgrav size_t len;
383a0ee8cc6SDag-Erling Smørgrav struct sshbuf *ret;
384a0ee8cc6SDag-Erling Smørgrav int r;
385a0ee8cc6SDag-Erling Smørgrav
386a0ee8cc6SDag-Erling Smørgrav if (buf == NULL || bufp == NULL)
387a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT;
388a0ee8cc6SDag-Erling Smørgrav *bufp = NULL;
389a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
390a0ee8cc6SDag-Erling Smørgrav return r;
391a0ee8cc6SDag-Erling Smørgrav if ((ret = sshbuf_from(p, len)) == NULL)
392a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL;
393a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_consume(buf, len + 4)) != 0 || /* Shouldn't happen */
394a0ee8cc6SDag-Erling Smørgrav (r = sshbuf_set_parent(ret, buf)) != 0) {
395a0ee8cc6SDag-Erling Smørgrav sshbuf_free(ret);
396a0ee8cc6SDag-Erling Smørgrav return r;
397a0ee8cc6SDag-Erling Smørgrav }
398a0ee8cc6SDag-Erling Smørgrav *bufp = ret;
399a0ee8cc6SDag-Erling Smørgrav return 0;
400a0ee8cc6SDag-Erling Smørgrav }
401a0ee8cc6SDag-Erling Smørgrav
402a0ee8cc6SDag-Erling Smørgrav int
sshbuf_put_bignum2_bytes(struct sshbuf * buf,const void * v,size_t len)403a0ee8cc6SDag-Erling Smørgrav sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len)
404a0ee8cc6SDag-Erling Smørgrav {
405a0ee8cc6SDag-Erling Smørgrav u_char *d;
406a0ee8cc6SDag-Erling Smørgrav const u_char *s = (const u_char *)v;
407a0ee8cc6SDag-Erling Smørgrav int r, prepend;
408a0ee8cc6SDag-Erling Smørgrav
409a0ee8cc6SDag-Erling Smørgrav if (len > SSHBUF_SIZE_MAX - 5) {
410a0ee8cc6SDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
411a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_NO_BUFFER_SPACE;
412a0ee8cc6SDag-Erling Smørgrav }
413a0ee8cc6SDag-Erling Smørgrav /* Skip leading zero bytes */
414a0ee8cc6SDag-Erling Smørgrav for (; len > 0 && *s == 0; len--, s++)
415a0ee8cc6SDag-Erling Smørgrav ;
416a0ee8cc6SDag-Erling Smørgrav /*
417a0ee8cc6SDag-Erling Smørgrav * If most significant bit is set then prepend a zero byte to
418a0ee8cc6SDag-Erling Smørgrav * avoid interpretation as a negative number.
419a0ee8cc6SDag-Erling Smørgrav */
420a0ee8cc6SDag-Erling Smørgrav prepend = len > 0 && (s[0] & 0x80) != 0;
421a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_reserve(buf, len + 4 + prepend, &d)) < 0)
422a0ee8cc6SDag-Erling Smørgrav return r;
423a0ee8cc6SDag-Erling Smørgrav POKE_U32(d, len + prepend);
424a0ee8cc6SDag-Erling Smørgrav if (prepend)
425a0ee8cc6SDag-Erling Smørgrav d[4] = 0;
426bc5531deSDag-Erling Smørgrav if (len != 0)
427a0ee8cc6SDag-Erling Smørgrav memcpy(d + 4 + prepend, s, len);
428a0ee8cc6SDag-Erling Smørgrav return 0;
429a0ee8cc6SDag-Erling Smørgrav }
430bc5531deSDag-Erling Smørgrav
431bc5531deSDag-Erling Smørgrav int
sshbuf_get_bignum2_bytes_direct(struct sshbuf * buf,const u_char ** valp,size_t * lenp)432bc5531deSDag-Erling Smørgrav sshbuf_get_bignum2_bytes_direct(struct sshbuf *buf,
433bc5531deSDag-Erling Smørgrav const u_char **valp, size_t *lenp)
434bc5531deSDag-Erling Smørgrav {
435bc5531deSDag-Erling Smørgrav const u_char *d;
436bc5531deSDag-Erling Smørgrav size_t len, olen;
437bc5531deSDag-Erling Smørgrav int r;
438bc5531deSDag-Erling Smørgrav
439bc5531deSDag-Erling Smørgrav if ((r = sshbuf_peek_string_direct(buf, &d, &olen)) < 0)
440bc5531deSDag-Erling Smørgrav return r;
441bc5531deSDag-Erling Smørgrav len = olen;
442bc5531deSDag-Erling Smørgrav /* Refuse negative (MSB set) bignums */
443bc5531deSDag-Erling Smørgrav if ((len != 0 && (*d & 0x80) != 0))
444bc5531deSDag-Erling Smørgrav return SSH_ERR_BIGNUM_IS_NEGATIVE;
445bc5531deSDag-Erling Smørgrav /* Refuse overlong bignums, allow prepended \0 to avoid MSB set */
446bc5531deSDag-Erling Smørgrav if (len > SSHBUF_MAX_BIGNUM + 1 ||
447bc5531deSDag-Erling Smørgrav (len == SSHBUF_MAX_BIGNUM + 1 && *d != 0))
448bc5531deSDag-Erling Smørgrav return SSH_ERR_BIGNUM_TOO_LARGE;
449bc5531deSDag-Erling Smørgrav /* Trim leading zeros */
450bc5531deSDag-Erling Smørgrav while (len > 0 && *d == 0x00) {
451bc5531deSDag-Erling Smørgrav d++;
452bc5531deSDag-Erling Smørgrav len--;
453bc5531deSDag-Erling Smørgrav }
454acc1a9efSDag-Erling Smørgrav if (valp != NULL)
455bc5531deSDag-Erling Smørgrav *valp = d;
456bc5531deSDag-Erling Smørgrav if (lenp != NULL)
457bc5531deSDag-Erling Smørgrav *lenp = len;
458bc5531deSDag-Erling Smørgrav if (sshbuf_consume(buf, olen + 4) != 0) {
459bc5531deSDag-Erling Smørgrav /* Shouldn't happen */
460bc5531deSDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
461bc5531deSDag-Erling Smørgrav SSHBUF_ABORT();
462bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR;
463bc5531deSDag-Erling Smørgrav }
464bc5531deSDag-Erling Smørgrav return 0;
465bc5531deSDag-Erling Smørgrav }
466fc3c19a9SEd Maste
467fc3c19a9SEd Maste /*
468fc3c19a9SEd Maste * store struct pwd
469fc3c19a9SEd Maste */
470fc3c19a9SEd Maste int
sshbuf_put_passwd(struct sshbuf * buf,const struct passwd * pwent)471fc3c19a9SEd Maste sshbuf_put_passwd(struct sshbuf *buf, const struct passwd *pwent)
472fc3c19a9SEd Maste {
473fc3c19a9SEd Maste int r;
474fc3c19a9SEd Maste
475fc3c19a9SEd Maste /*
476fc3c19a9SEd Maste * We never send pointer values of struct passwd.
477fc3c19a9SEd Maste * It is safe from wild pointer even if a new pointer member is added.
478fc3c19a9SEd Maste */
479fc3c19a9SEd Maste
480fc3c19a9SEd Maste if ((r = sshbuf_put_u64(buf, sizeof(*pwent)) != 0) ||
481fc3c19a9SEd Maste (r = sshbuf_put_cstring(buf, pwent->pw_name)) != 0 ||
482fc3c19a9SEd Maste (r = sshbuf_put_cstring(buf, "*")) != 0 ||
483fc3c19a9SEd Maste (r = sshbuf_put_u32(buf, pwent->pw_uid)) != 0 ||
484fc3c19a9SEd Maste (r = sshbuf_put_u32(buf, pwent->pw_gid)) != 0 ||
485*bd393de9SDag-Erling Smørgrav #ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
486*bd393de9SDag-Erling Smørgrav (r = sshbuf_put_time(buf, pwent->pw_change)) != 0 ||
487*bd393de9SDag-Erling Smørgrav #endif
488fc3c19a9SEd Maste #ifdef HAVE_STRUCT_PASSWD_PW_GECOS
489fc3c19a9SEd Maste (r = sshbuf_put_cstring(buf, pwent->pw_gecos)) != 0 ||
490fc3c19a9SEd Maste #endif
491fc3c19a9SEd Maste #ifdef HAVE_STRUCT_PASSWD_PW_CLASS
492fc3c19a9SEd Maste (r = sshbuf_put_cstring(buf, pwent->pw_class)) != 0 ||
493fc3c19a9SEd Maste #endif
494fc3c19a9SEd Maste (r = sshbuf_put_cstring(buf, pwent->pw_dir)) != 0 ||
495fc3c19a9SEd Maste (r = sshbuf_put_cstring(buf, pwent->pw_shell)) != 0 ||
496*bd393de9SDag-Erling Smørgrav #ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
497*bd393de9SDag-Erling Smørgrav (r = sshbuf_put_time(buf, pwent->pw_expire)) != 0 ||
498*bd393de9SDag-Erling Smørgrav #endif
499fc3c19a9SEd Maste (r = sshbuf_put_u32(buf, pwent->pw_fields)) != 0) {
500fc3c19a9SEd Maste return r;
501fc3c19a9SEd Maste }
502fc3c19a9SEd Maste return 0;
503fc3c19a9SEd Maste }
504fc3c19a9SEd Maste
505fc3c19a9SEd Maste /*
506fc3c19a9SEd Maste * extract struct pwd
507fc3c19a9SEd Maste */
508fc3c19a9SEd Maste struct passwd *
sshbuf_get_passwd(struct sshbuf * buf)509fc3c19a9SEd Maste sshbuf_get_passwd(struct sshbuf *buf)
510fc3c19a9SEd Maste {
511fc3c19a9SEd Maste struct passwd *pw;
512*bd393de9SDag-Erling Smørgrav u_int64_t len;
513fc3c19a9SEd Maste int r;
514fc3c19a9SEd Maste
515fc3c19a9SEd Maste /* check if size of struct passwd is as same as sender's size */
516fc3c19a9SEd Maste r = sshbuf_get_u64(buf, &len);
517fc3c19a9SEd Maste if (r != 0 || len != sizeof(*pw))
518fc3c19a9SEd Maste return NULL;
519fc3c19a9SEd Maste
520fc3c19a9SEd Maste pw = xcalloc(1, sizeof(*pw));
521fc3c19a9SEd Maste if (sshbuf_get_cstring(buf, &pw->pw_name, NULL) != 0 ||
522fc3c19a9SEd Maste sshbuf_get_cstring(buf, &pw->pw_passwd, NULL) != 0 ||
523fc3c19a9SEd Maste sshbuf_get_u32(buf, &pw->pw_uid) != 0 ||
524fc3c19a9SEd Maste sshbuf_get_u32(buf, &pw->pw_gid) != 0 ||
525*bd393de9SDag-Erling Smørgrav #ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
526*bd393de9SDag-Erling Smørgrav sshbuf_get_time(buf, &pw->pw_change) != 0 ||
527*bd393de9SDag-Erling Smørgrav #endif
528fc3c19a9SEd Maste #ifdef HAVE_STRUCT_PASSWD_PW_GECOS
529fc3c19a9SEd Maste sshbuf_get_cstring(buf, &pw->pw_gecos, NULL) != 0 ||
530fc3c19a9SEd Maste #endif
531fc3c19a9SEd Maste #ifdef HAVE_STRUCT_PASSWD_PW_CLASS
532fc3c19a9SEd Maste sshbuf_get_cstring(buf, &pw->pw_class, NULL) != 0 ||
533fc3c19a9SEd Maste #endif
534fc3c19a9SEd Maste sshbuf_get_cstring(buf, &pw->pw_dir, NULL) != 0 ||
535fc3c19a9SEd Maste sshbuf_get_cstring(buf, &pw->pw_shell, NULL) != 0 ||
536*bd393de9SDag-Erling Smørgrav #ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
537*bd393de9SDag-Erling Smørgrav sshbuf_get_time(buf, &pw->pw_expire) != 0 ||
538*bd393de9SDag-Erling Smørgrav #endif
539fc3c19a9SEd Maste sshbuf_get_u32(buf, &pw->pw_fields) != 0) {
540fc3c19a9SEd Maste sshbuf_free_passwd(pw);
541fc3c19a9SEd Maste return NULL;
542fc3c19a9SEd Maste }
543fc3c19a9SEd Maste return pw;
544fc3c19a9SEd Maste }
545fc3c19a9SEd Maste
546fc3c19a9SEd Maste /*
547fc3c19a9SEd Maste * free struct passwd obtained from sshbuf_get_passwd.
548fc3c19a9SEd Maste */
549fc3c19a9SEd Maste void
sshbuf_free_passwd(struct passwd * pwent)550fc3c19a9SEd Maste sshbuf_free_passwd(struct passwd *pwent)
551fc3c19a9SEd Maste {
552fc3c19a9SEd Maste if (pwent == NULL)
553fc3c19a9SEd Maste return;
554fc3c19a9SEd Maste free(pwent->pw_shell);
555fc3c19a9SEd Maste free(pwent->pw_dir);
556fc3c19a9SEd Maste #ifdef HAVE_STRUCT_PASSWD_PW_CLASS
557fc3c19a9SEd Maste free(pwent->pw_class);
558fc3c19a9SEd Maste #endif
559fc3c19a9SEd Maste #ifdef HAVE_STRUCT_PASSWD_PW_GECOS
560fc3c19a9SEd Maste free(pwent->pw_gecos);
561fc3c19a9SEd Maste #endif
562fc3c19a9SEd Maste free(pwent->pw_passwd);
563fc3c19a9SEd Maste free(pwent->pw_name);
564fc3c19a9SEd Maste free(pwent);
565fc3c19a9SEd Maste }
566