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