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