Coverage Report

Created: 2025-11-24 06:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libssh/src/buffer.c
Line
Count
Source
1
/*
2
 * buffer.c - buffer functions
3
 *
4
 * This file is part of the SSH Library
5
 *
6
 * Copyright (c) 2003-2009 by Aris Adamantiadis
7
 *
8
 * The SSH Library is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation; either version 2.1 of the License, or (at your
11
 * option) any later version.
12
 *
13
 * The SSH Library is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16
 * License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with the SSH Library; see the file COPYING.  If not, write to
20
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21
 * MA 02111-1307, USA.
22
 */
23
24
#include "config.h"
25
26
#include <limits.h>
27
#include <stdarg.h>
28
#include <stdbool.h>
29
#include <stdio.h>
30
31
#ifndef _WIN32
32
#include <netinet/in.h>
33
#include <arpa/inet.h>
34
#endif
35
36
#include "libssh/priv.h"
37
#include "libssh/buffer.h"
38
#include "libssh/misc.h"
39
#include "libssh/bignum.h"
40
41
/*
42
 * Describes a buffer state
43
 * [XXXXXXXXXXXXDATA PAYLOAD       XXXXXXXXXXXXXXXXXXXXXXXX]
44
 * ^            ^                  ^                       ^]
45
 * \_data points\_pos points here  \_used points here |    /
46
 *   here                                          Allocated
47
 */
48
struct ssh_buffer_struct {
49
    bool secure;
50
    uint32_t used;
51
    uint32_t allocated;
52
    uint32_t pos;
53
    uint8_t *data;
54
};
55
56
/* Buffer size maximum is 256M */
57
132
#define BUFFER_SIZE_MAX 0x10000000
58
59
/**
60
 * @defgroup libssh_buffer The SSH buffer functions
61
 * @ingroup libssh
62
 *
63
 * Functions to handle SSH buffers.
64
 *
65
 * @{
66
 */
67
68
69
#ifdef DEBUG_BUFFER
70
/**
71
 * @internal
72
 *
73
 * @brief Check that preconditions and postconditions are valid.
74
 *
75
 * @param[in]  buf      The buffer to check.
76
 */
77
static void buffer_verify(ssh_buffer buf)
78
{
79
    bool do_abort = false;
80
81
    if (buf->data == NULL) {
82
        return;
83
    }
84
85
    if (buf->used > buf->allocated) {
86
        fprintf(stderr,
87
                "BUFFER ERROR: allocated %u, used %u\n",
88
                buf->allocated,
89
                buf->used);
90
        do_abort = true;
91
    }
92
    if (buf->pos > buf->used) {
93
        fprintf(stderr,
94
                "BUFFER ERROR: position %u, used %u\n",
95
                buf->pos,
96
                buf->used);
97
        do_abort = true;
98
    }
99
    if (buf->pos > buf->allocated) {
100
        fprintf(stderr,
101
                "BUFFER ERROR: position %u, allocated %u\n",
102
                buf->pos,
103
                buf->allocated);
104
        do_abort = true;
105
    }
106
    if (do_abort) {
107
        abort();
108
    }
109
}
110
111
#else
112
#define buffer_verify(x)
113
#endif
114
115
/**
116
 * @brief Create a new SSH buffer.
117
 *
118
 * @return A newly initialized SSH buffer, NULL on error.
119
 */
120
struct ssh_buffer_struct *ssh_buffer_new(void)
121
46
{
122
46
    struct ssh_buffer_struct *buf = NULL;
123
46
    int rc;
124
125
46
    buf = calloc(1, sizeof(struct ssh_buffer_struct));
126
46
    if (buf == NULL) {
127
5
        return NULL;
128
5
    }
129
130
    /*
131
     * Always preallocate 64 bytes.
132
     *
133
     * -1 for realloc_buffer magic.
134
     */
135
41
    rc = ssh_buffer_allocate_size(buf, 64 - 1);
136
41
    if (rc != 0) {
137
1
        SAFE_FREE(buf);
138
1
        return NULL;
139
1
    }
140
40
    buffer_verify(buf);
141
142
40
    return buf;
143
41
}
144
145
/**
146
 * @brief Deallocate a SSH buffer.
147
 *
148
 * \param[in]  buffer   The buffer to free.
149
 */
150
void ssh_buffer_free(struct ssh_buffer_struct *buffer)
151
40
{
152
40
    if (buffer == NULL) {
153
0
        return;
154
0
    }
155
40
    buffer_verify(buffer);
156
157
40
    if (buffer->secure && buffer->allocated > 0) {
158
        /* burn the data */
159
36
        explicit_bzero(buffer->data, buffer->allocated);
160
36
        SAFE_FREE(buffer->data);
161
162
36
        explicit_bzero(buffer, sizeof(struct ssh_buffer_struct));
163
36
    } else {
164
4
        SAFE_FREE(buffer->data);
165
4
    }
166
40
    SAFE_FREE(buffer);
167
40
}
168
169
/**
170
 * @brief Sets the buffer as secure.
171
 *
172
 * A secure buffer will never leave cleartext data in the heap
173
 * after being reallocated or freed.
174
 *
175
 * @param[in] buffer buffer to set secure.
176
 */
177
void ssh_buffer_set_secure(ssh_buffer buffer)
178
36
{
179
36
    buffer->secure = true;
180
36
}
181
182
static int realloc_buffer(struct ssh_buffer_struct *buffer, uint32_t needed)
183
132
{
184
132
    uint32_t smallest = 1;
185
132
    uint8_t *new = NULL;
186
187
132
    buffer_verify(buffer);
188
189
    /* Find the smallest power of two which is greater or equal to needed */
190
1.31k
    while(smallest <= needed) {
191
1.18k
        if (smallest == 0) {
192
0
            return -1;
193
0
        }
194
1.18k
        smallest <<= 1;
195
1.18k
    }
196
132
    needed = smallest;
197
198
132
    if (needed > BUFFER_SIZE_MAX) {
199
0
        return -1;
200
0
    }
201
202
132
    if (buffer->secure) {
203
88
        new = malloc(needed);
204
88
        if (new == NULL) {
205
0
            return -1;
206
0
        }
207
88
        memcpy(new, buffer->data, buffer->used);
208
88
        explicit_bzero(buffer->data, buffer->used);
209
88
        SAFE_FREE(buffer->data);
210
88
    } else {
211
44
        new = realloc(buffer->data, needed);
212
44
        if (new == NULL) {
213
1
            return -1;
214
1
        }
215
44
    }
216
131
    buffer->data = new;
217
131
    buffer->allocated = needed;
218
219
131
    buffer_verify(buffer);
220
131
    return 0;
221
132
}
222
223
/** @internal
224
 * @brief shifts a buffer to remove unused data in the beginning
225
 * @param buffer SSH buffer
226
 */
227
static void buffer_shift(ssh_buffer buffer)
228
0
{
229
0
    size_t burn_pos = buffer->pos;
230
231
0
    buffer_verify(buffer);
232
233
0
    if (buffer->pos == 0) {
234
0
        return;
235
0
    }
236
0
    memmove(buffer->data,
237
0
            buffer->data + buffer->pos,
238
0
            buffer->used - buffer->pos);
239
0
    buffer->used -= buffer->pos;
240
0
    buffer->pos = 0;
241
242
0
    if (buffer->secure) {
243
0
        void *ptr = buffer->data + buffer->used;
244
0
        explicit_bzero(ptr, burn_pos);
245
0
    }
246
247
0
    buffer_verify(buffer);
248
0
}
249
250
/**
251
 * @brief Reinitialize a SSH buffer.
252
 *
253
 * In case the buffer has exceeded 64K in size, the buffer will be reallocated
254
 * to 64K.
255
 *
256
 * @param[in]  buffer   The buffer to reinitialize.
257
 *
258
 * @return              0 on success, < 0 on error.
259
 */
260
int ssh_buffer_reinit(struct ssh_buffer_struct *buffer)
261
0
{
262
0
    if (buffer == NULL) {
263
0
        return -1;
264
0
    }
265
266
0
    buffer_verify(buffer);
267
268
0
    if (buffer->secure && buffer->allocated > 0) {
269
0
        explicit_bzero(buffer->data, buffer->allocated);
270
0
    }
271
0
    buffer->used = 0;
272
0
    buffer->pos = 0;
273
274
    /* If the buffer is bigger then 64K, reset it to 64K */
275
0
    if (buffer->allocated > 65536) {
276
0
        int rc;
277
278
        /* -1 for realloc_buffer magic */
279
0
        rc = realloc_buffer(buffer, 65536 - 1);
280
0
        if (rc != 0) {
281
0
            return -1;
282
0
        }
283
0
    }
284
285
0
    buffer_verify(buffer);
286
287
0
    return 0;
288
0
}
289
290
/**
291
 * @brief Add data at the tail of a buffer.
292
 *
293
 * @param[in]  buffer   The buffer to add the data.
294
 *
295
 * @param[in]  data     A pointer to the data to add.
296
 *
297
 * @param[in]  len      The length of the data to add.
298
 *
299
 * @return              0 on success, < 0 on error.
300
 */
301
int ssh_buffer_add_data(struct ssh_buffer_struct *buffer, const void *data, uint32_t len)
302
344k
{
303
344k
    if (buffer == NULL) {
304
0
        return -1;
305
0
    }
306
307
344k
    buffer_verify(buffer);
308
309
344k
    if (data == NULL) {
310
0
        return -1;
311
0
    }
312
313
344k
    if (buffer->used + len < len) {
314
0
        return -1;
315
0
    }
316
317
344k
    if (buffer->allocated < (buffer->used + len)) {
318
91
        if (buffer->pos > 0) {
319
0
            buffer_shift(buffer);
320
0
        }
321
91
        if (realloc_buffer(buffer, buffer->used + len) < 0) {
322
0
            return -1;
323
0
        }
324
91
    }
325
326
344k
    memcpy(buffer->data + buffer->used, data, len);
327
344k
    buffer->used += len;
328
344k
    buffer_verify(buffer);
329
344k
    return 0;
330
344k
}
331
332
/**
333
 * @brief Ensure the buffer has at least a certain preallocated size.
334
 *
335
 * @param[in]  buffer   The buffer to enlarge.
336
 *
337
 * @param[in]  len      The length to ensure as allocated.
338
 *
339
 * @return              0 on success, < 0 on error.
340
 */
341
int ssh_buffer_allocate_size(struct ssh_buffer_struct *buffer,
342
                             uint32_t len)
343
41
{
344
41
    buffer_verify(buffer);
345
346
41
    if (buffer->allocated < len) {
347
41
        if (buffer->pos > 0) {
348
0
            buffer_shift(buffer);
349
0
        }
350
41
        if (realloc_buffer(buffer, len) < 0) {
351
1
            return -1;
352
1
        }
353
41
    }
354
355
40
    buffer_verify(buffer);
356
357
40
    return 0;
358
41
}
359
360
/**
361
 * @internal
362
 *
363
 * @brief Allocate space for data at the tail of a buffer.
364
 *
365
 * @param[in]  buffer   The buffer to add the data.
366
 *
367
 * @param[in]  len      The length of the data to add.
368
 *
369
 * @return              Pointer on the allocated space
370
 *                      NULL on error.
371
 */
372
void *ssh_buffer_allocate(struct ssh_buffer_struct *buffer, uint32_t len)
373
0
{
374
0
    void *ptr = NULL;
375
376
0
    buffer_verify(buffer);
377
378
0
    if (buffer->used + len < len) {
379
0
        return NULL;
380
0
    }
381
382
0
    if (buffer->allocated < (buffer->used + len)) {
383
0
        if (buffer->pos > 0) {
384
0
            buffer_shift(buffer);
385
0
        }
386
387
0
        if (realloc_buffer(buffer, buffer->used + len) < 0) {
388
0
            return NULL;
389
0
        }
390
0
    }
391
392
0
    ptr = buffer->data + buffer->used;
393
0
    buffer->used+=len;
394
0
    buffer_verify(buffer);
395
396
0
    return ptr;
397
0
}
398
399
/**
400
 * @internal
401
 *
402
 * @brief Add a SSH string to the tail of a buffer.
403
 *
404
 * @param[in]  buffer   The buffer to add the string.
405
 *
406
 * @param[in]  string   The SSH String to add.
407
 *
408
 * @return              0 on success, < 0 on error.
409
 */
410
int
411
ssh_buffer_add_ssh_string(struct ssh_buffer_struct *buffer,
412
                          struct ssh_string_struct *string)
413
4
{
414
4
    size_t len;
415
4
    int rc;
416
417
4
    if (string == NULL) {
418
0
        return -1;
419
0
    }
420
421
4
    len = ssh_string_len(string) + sizeof(uint32_t);
422
    /* this can't overflow the uint32_t as the
423
     * STRING_SIZE_MAX is (UINT32_MAX >> 8) + 1 */
424
4
    rc = ssh_buffer_add_data(buffer, string, (uint32_t)len);
425
4
    if (rc < 0) {
426
0
        return -1;
427
0
    }
428
429
4
    return 0;
430
4
}
431
432
/**
433
 * @internal
434
 *
435
 * @brief Add a 32 bits unsigned integer to the tail of a buffer.
436
 *
437
 * @param[in]  buffer   The buffer to add the integer.
438
 *
439
 * @param[in]  data     The 32 bits integer to add.
440
 *
441
 * @return              0 on success, -1 on error.
442
 */
443
int ssh_buffer_add_u32(struct ssh_buffer_struct *buffer,uint32_t data)
444
0
{
445
0
    int rc;
446
447
0
    rc = ssh_buffer_add_data(buffer, &data, sizeof(data));
448
0
    if (rc < 0) {
449
0
        return -1;
450
0
    }
451
452
0
    return 0;
453
0
}
454
455
/**
456
 * @internal
457
 *
458
 * @brief Add a 16 bits unsigned integer to the tail of a buffer.
459
 *
460
 * @param[in]  buffer   The buffer to add the integer.
461
 *
462
 * @param[in]  data     The 16 bits integer to add.
463
 *
464
 * @return              0 on success, -1 on error.
465
 */
466
int ssh_buffer_add_u16(struct ssh_buffer_struct *buffer,uint16_t data)
467
0
{
468
0
    int rc;
469
470
0
    rc = ssh_buffer_add_data(buffer, &data, sizeof(data));
471
0
    if (rc < 0) {
472
0
        return -1;
473
0
    }
474
475
0
    return 0;
476
0
}
477
478
/**
479
 * @internal
480
 *
481
 * @brief Add a 64 bits unsigned integer to the tail of a buffer.
482
 *
483
 * @param[in]  buffer   The buffer to add the integer.
484
 *
485
 * @param[in]  data     The 64 bits integer to add.
486
 *
487
 * @return              0 on success, -1 on error.
488
 */
489
int ssh_buffer_add_u64(struct ssh_buffer_struct *buffer, uint64_t data)
490
0
{
491
0
    int rc;
492
493
0
    rc = ssh_buffer_add_data(buffer, &data, sizeof(data));
494
0
    if (rc < 0) {
495
0
        return -1;
496
0
    }
497
498
0
    return 0;
499
0
}
500
501
/**
502
 * @internal
503
 *
504
 * @brief Add a 8 bits unsigned integer to the tail of a buffer.
505
 *
506
 * @param[in]  buffer   The buffer to add the integer.
507
 *
508
 * @param[in]  data     The 8 bits integer to add.
509
 *
510
 * @return              0 on success, -1 on error.
511
 */
512
int ssh_buffer_add_u8(struct ssh_buffer_struct *buffer,uint8_t data)
513
0
{
514
0
    int rc;
515
516
0
    rc = ssh_buffer_add_data(buffer, &data, sizeof(uint8_t));
517
0
    if (rc < 0) {
518
0
        return -1;
519
0
    }
520
521
0
    return 0;
522
0
}
523
524
/**
525
 * @internal
526
 *
527
 * @brief Add data at the head of a buffer.
528
 *
529
 * @param[in]  buffer   The buffer to add the data.
530
 *
531
 * @param[in]  data     The data to prepend.
532
 *
533
 * @param[in]  len      The length of data to prepend.
534
 *
535
 * @return              0 on success, -1 on error.
536
 */
537
int ssh_buffer_prepend_data(struct ssh_buffer_struct *buffer, const void *data,
538
0
    uint32_t len) {
539
0
  buffer_verify(buffer);
540
541
0
  if(len <= buffer->pos){
542
    /* It's possible to insert data between begin and pos */
543
0
    memcpy(buffer->data + (buffer->pos - len), data, len);
544
0
    buffer->pos -= len;
545
0
    buffer_verify(buffer);
546
0
    return 0;
547
0
  }
548
  /* pos isn't high enough */
549
0
  if (buffer->used - buffer->pos + len < len) {
550
0
    return -1;
551
0
  }
552
553
0
  if (buffer->allocated < (buffer->used - buffer->pos + len)) {
554
0
    if (realloc_buffer(buffer, buffer->used - buffer->pos + len) < 0) {
555
0
      return -1;
556
0
    }
557
0
  }
558
0
  memmove(buffer->data + len, buffer->data + buffer->pos, buffer->used - buffer->pos);
559
0
  memcpy(buffer->data, data, len);
560
0
  buffer->used += len - buffer->pos;
561
0
  buffer->pos = 0;
562
0
  buffer_verify(buffer);
563
0
  return 0;
564
0
}
565
566
/**
567
 * @internal
568
 *
569
 * @brief Append data from a buffer to the tail of another buffer.
570
 *
571
 * @param[in]  buffer   The destination buffer.
572
 *
573
 * @param[in]  source   The source buffer to append. It doesn't take the
574
 *                      position of the buffer into account.
575
 *
576
 * @return              0 on success, -1 on error.
577
 */
578
int ssh_buffer_add_buffer(struct ssh_buffer_struct *buffer,
579
    struct ssh_buffer_struct *source)
580
4
{
581
4
    int rc;
582
583
4
    rc = ssh_buffer_add_data(buffer,
584
4
                             ssh_buffer_get(source),
585
4
                             ssh_buffer_get_len(source));
586
4
    if (rc < 0) {
587
0
        return -1;
588
0
    }
589
590
4
    return 0;
591
4
}
592
593
/**
594
 * @brief Get a pointer to the head of a buffer at the current position.
595
 *
596
 * @param[in]  buffer   The buffer to get the head pointer.
597
 *
598
 * @return              A pointer to the data from current position.
599
 *
600
 * @see ssh_buffer_get_len()
601
 */
602
4
void *ssh_buffer_get(struct ssh_buffer_struct *buffer){
603
4
    return buffer->data + buffer->pos;
604
4
}
605
606
/**
607
 * @brief Get the length of the buffer from the current position.
608
 *
609
 * @param[in]  buffer   The buffer to get the length from.
610
 *
611
 * @return              The length of the buffer.
612
 *
613
 * @see ssh_buffer_get()
614
 */
615
23
uint32_t ssh_buffer_get_len(struct ssh_buffer_struct *buffer){
616
23
  buffer_verify(buffer);
617
23
  return buffer->used - buffer->pos;
618
23
}
619
620
/**
621
 * @internal
622
 *
623
 * @brief Duplicate an existing buffer.
624
 *
625
 * Creates a new ssh_buffer and copies all data from the source buffer.
626
 * The new buffer preserves the secure flag setting of the source.
627
 *
628
 * @param[in]  buffer   The buffer to duplicate. Can be NULL.
629
 *
630
 * @return              A new buffer containing a copy of the data on success,
631
 *                      NULL on failure or if buffer is NULL.
632
 *
633
 * @see ssh_buffer_free()
634
 */
635
ssh_buffer ssh_buffer_dup(const ssh_buffer buffer)
636
0
{
637
0
    ssh_buffer new_buffer = NULL;
638
0
    int rc;
639
640
0
    if (buffer == NULL) {
641
0
        return NULL;
642
0
    }
643
644
0
    buffer_verify(buffer);
645
646
0
    new_buffer = ssh_buffer_new();
647
0
    if (new_buffer == NULL) {
648
0
        return NULL;
649
0
    }
650
651
0
    new_buffer->secure = buffer->secure;
652
653
0
    if (ssh_buffer_get_len(buffer) > 0) {
654
0
        rc = ssh_buffer_add_data(new_buffer,
655
0
                                 ssh_buffer_get(buffer),
656
0
                                 ssh_buffer_get_len(buffer));
657
0
        if (rc != SSH_OK) {
658
0
            ssh_buffer_free(new_buffer);
659
0
            return NULL;
660
0
        }
661
0
    }
662
663
0
    buffer_verify(new_buffer);
664
0
    return new_buffer;
665
0
}
666
667
/**
668
 * @internal
669
 *
670
 * @brief Advance the position in the buffer.
671
 *
672
 * This has effect to "eat" bytes at head of the buffer.
673
 *
674
 * @param[in]  buffer   The buffer to advance the position.
675
 *
676
 * @param[in]  len      The number of bytes to eat.
677
 *
678
 * @return              The new size of the buffer.
679
 */
680
0
uint32_t ssh_buffer_pass_bytes(struct ssh_buffer_struct *buffer, uint32_t len){
681
0
    buffer_verify(buffer);
682
683
0
    if (buffer->pos + len < len || buffer->used < buffer->pos + len) {
684
0
        return 0;
685
0
    }
686
687
0
    buffer->pos+=len;
688
    /* if the buffer is empty after having passed the whole bytes into it, we can clean it */
689
0
    if(buffer->pos==buffer->used){
690
0
        buffer->pos=0;
691
0
        buffer->used=0;
692
0
    }
693
0
    buffer_verify(buffer);
694
0
    return len;
695
0
}
696
697
/**
698
 * @internal
699
 *
700
 * @brief Cut the end of the buffer.
701
 *
702
 * @param[in]  buffer   The buffer to cut.
703
 *
704
 * @param[in]  len      The number of bytes to remove from the tail.
705
 *
706
 * @return              The new size of the buffer.
707
 */
708
0
uint32_t ssh_buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t len){
709
0
  buffer_verify(buffer);
710
711
0
  if (buffer->used < len) {
712
0
      return 0;
713
0
  }
714
715
0
  buffer->used-=len;
716
0
  buffer_verify(buffer);
717
0
  return len;
718
0
}
719
720
/**
721
 * @brief Get the remaining data out of the buffer and adjust the read pointer.
722
 *
723
 * @param[in]  buffer   The buffer to read.
724
 *
725
 * @param[in]  data     The data buffer where to store the data.
726
 *
727
 * @param[in]  len      The length to read from the buffer.
728
 *
729
 * @returns             0 if there is not enough data in buffer, len otherwise.
730
 */
731
uint32_t ssh_buffer_get_data(struct ssh_buffer_struct *buffer, void *data, uint32_t len)
732
101
{
733
101
    int rc;
734
735
    /*
736
     * Check for a integer overflow first, then check if not enough data is in
737
     * the buffer.
738
     */
739
101
    rc = ssh_buffer_validate_length(buffer, len);
740
101
    if (rc != SSH_OK) {
741
3
        return 0;
742
3
    }
743
98
    memcpy(data,buffer->data+buffer->pos,len);
744
98
    buffer->pos+=len;
745
98
    return len;   /* no yet support for partial reads (is it really needed ?? ) */
746
101
}
747
748
/**
749
 * @internal
750
 *
751
 * @brief Get a 8 bits unsigned int out of the buffer and adjust the read
752
 * pointer.
753
 *
754
 * @param[in]  buffer   The buffer to read.
755
 *
756
 * @param[in]  data     A pointer to a uint8_t where to store the data.
757
 *
758
 * @returns             0 if there is not enough data in buffer, 1 otherwise.
759
 */
760
0
uint32_t ssh_buffer_get_u8(struct ssh_buffer_struct *buffer, uint8_t *data){
761
0
    return ssh_buffer_get_data(buffer,data,sizeof(uint8_t));
762
0
}
763
764
/**
765
 * @internal
766
 *
767
 * @brief gets a 32 bits unsigned int out of the buffer. Adjusts the read pointer.
768
 *
769
 * @param[in]  buffer   The buffer to read.
770
 *
771
 * @param[in]  data     A pointer to a uint32_t where to store the data.
772
 *
773
 * @returns             0 if there is not enough data in buffer, 4 otherwise.
774
 */
775
55
uint32_t ssh_buffer_get_u32(struct ssh_buffer_struct *buffer, uint32_t *data){
776
55
    return ssh_buffer_get_data(buffer,data,sizeof(uint32_t));
777
55
}
778
/**
779
 * @internal
780
 *
781
 * @brief Get a 64 bits unsigned int out of the buffer and adjusts the read
782
 * pointer.
783
 *
784
 * @param[in]  buffer   The buffer to read.
785
 *
786
 * @param[in]  data     A pointer to a uint64_t where to store the data.
787
 *
788
 * @returns             0 if there is not enough data in buffer, 8 otherwise.
789
 */
790
0
uint32_t ssh_buffer_get_u64(struct ssh_buffer_struct *buffer, uint64_t *data){
791
0
    return ssh_buffer_get_data(buffer,data,sizeof(uint64_t));
792
0
}
793
794
/**
795
 * @brief Validates that the given length can be obtained from the buffer.
796
 *
797
 * @param[in]  buffer  The buffer to read from.
798
 *
799
 * @param[in]  len     The length to be checked.
800
 *
801
 * @return             SSH_OK if the length is valid, SSH_ERROR otherwise.
802
 */
803
int ssh_buffer_validate_length(struct ssh_buffer_struct *buffer, size_t len)
804
155
{
805
155
    if (buffer == NULL || buffer->pos + len < len ||
806
155
        buffer->pos + len > buffer->used) {
807
11
        return SSH_ERROR;
808
11
    }
809
810
144
    return SSH_OK;
811
155
}
812
813
/**
814
 * @internal
815
 *
816
 * @brief Get an SSH String out of the buffer and adjust the read pointer.
817
 *
818
 * @param[in]  buffer   The buffer to read.
819
 *
820
 * @returns             The SSH String, NULL on error.
821
 */
822
struct ssh_string_struct *
823
ssh_buffer_get_ssh_string(struct ssh_buffer_struct *buffer)
824
30
{
825
30
    uint32_t stringlen;
826
30
    uint32_t hostlen;
827
30
    struct ssh_string_struct *str = NULL;
828
30
    int rc;
829
830
30
    rc = ssh_buffer_get_u32(buffer, &stringlen);
831
30
    if (rc == 0) {
832
2
        return NULL;
833
2
    }
834
28
    hostlen = ntohl(stringlen);
835
    /* verify if there is enough space in buffer to get it */
836
28
    rc = ssh_buffer_validate_length(buffer, hostlen);
837
28
    if (rc != SSH_OK) {
838
7
      return NULL; /* it is indeed */
839
7
    }
840
21
    str = ssh_string_new(hostlen);
841
21
    if (str == NULL) {
842
0
        return NULL;
843
0
    }
844
845
21
    stringlen = ssh_buffer_get_data(buffer, ssh_string_data(str), hostlen);
846
21
    if (stringlen != hostlen) {
847
        /* should never happen */
848
0
        SAFE_FREE(str);
849
0
        return NULL;
850
0
    }
851
852
21
    return str;
853
21
}
854
855
/**
856
 * @brief Pre-calculate the size we need for packing the buffer.
857
 *
858
 * This makes sure that enough memory is allocated for packing the buffer and
859
 * we only have to do one memory allocation.
860
 *
861
 * @param[in]  buffer    The buffer to allocate
862
 *
863
 * @param[in]  format    A format string of arguments.
864
 *
865
 * @param[in]  argc      The number of arguments.
866
 *
867
 * @param[in]  ap        The va_list of arguments.
868
 *
869
 * @return SSH_OK on success, SSH_ERROR on error.
870
 */
871
static int ssh_buffer_pack_allocate_va(struct ssh_buffer_struct *buffer,
872
                                       const char *format,
873
                                       size_t argc,
874
                                       va_list ap)
875
0
{
876
0
    const char *p = NULL;
877
0
    ssh_string string = NULL;
878
0
    char *cstring = NULL;
879
0
    bignum b = NULL;
880
0
    size_t needed_size = 0;
881
0
    size_t len;
882
0
    size_t count;
883
0
    int rc = SSH_OK;
884
885
0
    for (p = format, count = 0; *p != '\0'; p++, count++) {
886
        /* Invalid number of arguments passed */
887
0
        if (count > argc) {
888
0
            return SSH_ERROR;
889
0
        }
890
891
0
        switch(*p) {
892
0
        case 'b':
893
0
            va_arg(ap, unsigned int);
894
0
            needed_size += sizeof(uint8_t);
895
0
            break;
896
0
        case 'w':
897
0
            va_arg(ap, unsigned int);
898
0
            needed_size += sizeof(uint16_t);
899
0
            break;
900
0
        case 'd':
901
0
            va_arg(ap, uint32_t);
902
0
            needed_size += sizeof(uint32_t);
903
0
            break;
904
0
        case 'q':
905
0
            va_arg(ap, uint64_t);
906
0
            needed_size += sizeof(uint64_t);
907
0
            break;
908
0
        case 'S':
909
0
            string = va_arg(ap, ssh_string);
910
0
            needed_size += sizeof(uint32_t) + ssh_string_len(string);
911
0
            string = NULL;
912
0
            break;
913
0
        case 's':
914
0
            cstring = va_arg(ap, char *);
915
0
            needed_size += sizeof(uint32_t) + strlen(cstring);
916
0
            cstring = NULL;
917
0
            break;
918
0
        case 'P':
919
0
            len = va_arg(ap, size_t);
920
0
            needed_size += len;
921
0
            va_arg(ap, void *);
922
0
            count++; /* increase argument count */
923
0
            break;
924
0
        case 'F':
925
0
        case 'B':
926
0
            b = va_arg(ap, bignum);
927
0
            if (*p == 'F') {
928
                /* For padded bignum, we know the exact length */
929
0
                len = va_arg(ap, size_t);
930
0
                count++; /* increase argument count */
931
0
                needed_size += sizeof(uint32_t) + len;
932
0
            } else {
933
                /* The bignum bytes + 1 for possible padding */
934
0
                needed_size += sizeof(uint32_t) + bignum_num_bytes(b) + 1;
935
0
            }
936
0
            break;
937
0
        case 't':
938
0
            cstring = va_arg(ap, char *);
939
0
            needed_size += strlen(cstring);
940
0
            cstring = NULL;
941
0
            break;
942
0
        default:
943
0
            SSH_LOG(SSH_LOG_TRACE, "Invalid buffer format %c", *p);
944
0
            rc = SSH_ERROR;
945
0
        }
946
0
        if (rc != SSH_OK){
947
0
            break;
948
0
        }
949
0
    }
950
951
0
    if (argc != count) {
952
0
        return SSH_ERROR;
953
0
    }
954
955
0
    if (rc != SSH_ERROR){
956
        /*
957
         * Check if our canary is intact, if not, something really bad happened.
958
         */
959
0
        uint32_t canary = va_arg(ap, uint32_t);
960
0
        if (canary != SSH_BUFFER_PACK_END) {
961
0
            abort();
962
0
        }
963
0
    }
964
965
0
    rc = ssh_buffer_allocate_size(buffer, (uint32_t)needed_size);
966
0
    if (rc != 0) {
967
0
        return SSH_ERROR;
968
0
    }
969
970
0
    return SSH_OK;
971
0
}
972
973
/** @internal
974
 * @brief Add multiple values in a buffer on a single function call
975
 * @param[in] buffer    The buffer to add to
976
 * @param[in] format    A format string of arguments.
977
 * @param[in] ap        A va_list of arguments.
978
 * @returns             SSH_OK on success
979
 *                      SSH_ERROR on error
980
 * @see ssh_buffer_add_format() for format list values.
981
 */
982
static int
983
ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
984
                   const char *format,
985
                   size_t argc,
986
                   va_list ap)
987
0
{
988
0
    int rc = SSH_ERROR;
989
0
    const char *p = NULL;
990
0
    union {
991
0
        uint8_t byte;
992
0
        uint16_t word;
993
0
        uint32_t dword;
994
0
        uint64_t qword;
995
0
        ssh_string string;
996
0
        void *data;
997
0
    } o;
998
0
    char *cstring = NULL;
999
0
    bignum b;
1000
0
    size_t len;
1001
0
    size_t count;
1002
1003
0
    if (argc > 256) {
1004
0
        return SSH_ERROR;
1005
0
    }
1006
1007
0
    for (p = format, count = 0; *p != '\0'; p++, count++) {
1008
        /* Invalid number of arguments passed */
1009
0
        if (count > argc) {
1010
0
            return SSH_ERROR;
1011
0
        }
1012
1013
0
        switch(*p) {
1014
0
        case 'b':
1015
0
            o.byte = (uint8_t)va_arg(ap, unsigned int);
1016
0
            rc = ssh_buffer_add_u8(buffer, o.byte);
1017
0
            break;
1018
0
        case 'w':
1019
0
            o.word = (uint16_t)va_arg(ap, unsigned int);
1020
0
            o.word = htons(o.word);
1021
0
            rc = ssh_buffer_add_u16(buffer, o.word);
1022
0
            break;
1023
0
        case 'd':
1024
0
            o.dword = va_arg(ap, uint32_t);
1025
0
            o.dword = htonl(o.dword);
1026
0
            rc = ssh_buffer_add_u32(buffer, o.dword);
1027
0
            break;
1028
0
        case 'q':
1029
0
            o.qword = va_arg(ap, uint64_t);
1030
0
            o.qword = htonll(o.qword);
1031
0
            rc = ssh_buffer_add_u64(buffer, o.qword);
1032
0
            break;
1033
0
        case 'S':
1034
0
            o.string = va_arg(ap, ssh_string);
1035
0
            rc = ssh_buffer_add_ssh_string(buffer, o.string);
1036
0
            o.string = NULL;
1037
0
            break;
1038
0
        case 's':
1039
0
            cstring = va_arg(ap, char *);
1040
0
            len = strlen(cstring);
1041
0
            if (len > UINT32_MAX) {
1042
0
                rc = SSH_ERROR;
1043
0
                break;
1044
0
            }
1045
0
            o.dword = (uint32_t)len;
1046
0
            rc = ssh_buffer_add_u32(buffer, htonl(o.dword));
1047
0
            if (rc == SSH_OK){
1048
0
                rc = ssh_buffer_add_data(buffer, cstring, o.dword);
1049
0
            }
1050
0
            cstring = NULL;
1051
0
            break;
1052
0
        case 'P':
1053
0
            len = va_arg(ap, size_t);
1054
0
            if (len > UINT32_MAX) {
1055
0
                rc = SSH_ERROR;
1056
0
                break;
1057
0
            }
1058
1059
0
            o.data = va_arg(ap, void *);
1060
0
            count++; /* increase argument count */
1061
1062
0
            rc = ssh_buffer_add_data(buffer, o.data, (uint32_t)len);
1063
0
            o.data = NULL;
1064
0
            break;
1065
0
        case 'F':
1066
0
        case 'B':
1067
0
            b = va_arg(ap, bignum);
1068
0
            if (*p == 'F') {
1069
0
                len = va_arg(ap, size_t);
1070
0
                count++; /* increase argument count */
1071
0
                o.string = ssh_make_padded_bignum_string(b, len);
1072
0
            } else {
1073
0
                o.string = ssh_make_bignum_string(b);
1074
0
            }
1075
0
            if(o.string == NULL){
1076
0
                rc = SSH_ERROR;
1077
0
                break;
1078
0
            }
1079
0
            rc = ssh_buffer_add_ssh_string(buffer, o.string);
1080
0
            SAFE_FREE(o.string);
1081
0
            break;
1082
0
        case 't':
1083
0
            cstring = va_arg(ap, char *);
1084
0
            len = strlen(cstring);
1085
0
            if (len > UINT32_MAX) {
1086
0
                rc = SSH_ERROR;
1087
0
                break;
1088
0
            }
1089
0
            rc = ssh_buffer_add_data(buffer, cstring, (uint32_t)len);
1090
0
            cstring = NULL;
1091
0
            break;
1092
0
        default:
1093
0
            SSH_LOG(SSH_LOG_TRACE, "Invalid buffer format %c", *p);
1094
0
            rc = SSH_ERROR;
1095
0
        }
1096
0
        if (rc != SSH_OK){
1097
0
            break;
1098
0
        }
1099
0
    }
1100
1101
0
    if (argc != count) {
1102
0
        return SSH_ERROR;
1103
0
    }
1104
1105
0
    if (rc != SSH_ERROR){
1106
        /* Check if our canary is intact, if not something really bad happened */
1107
0
        uint32_t canary = va_arg(ap, uint32_t);
1108
0
        if (canary != SSH_BUFFER_PACK_END) {
1109
0
            abort();
1110
0
        }
1111
0
    }
1112
0
    return rc;
1113
0
}
1114
1115
/** @internal
1116
 * @brief Add multiple values in a buffer on a single function call
1117
 * @param[in] buffer    The buffer to add to
1118
 * @param[in] format    A format string of arguments. This string contains single
1119
 *                      letters describing the order and type of arguments:
1120
 *                         'b': uint8_t  (pushed in network byte order)
1121
 *                         'w': uint16_t (pushed in network byte order)
1122
 *                         'd': uint32_t (pushed in network byte order)
1123
 *                         'q': uint64_t (pushed in network byte order)
1124
 *                         'S': ssh_string
1125
 *                         's': char * (C string, pushed as SSH string)
1126
 *                         't': char * (C string, pushed as free text)
1127
 *                         'P': size_t, void * (len of data, pointer to data)
1128
 *                              only pushes data.
1129
 *                         'B': bignum (pushed as SSH string)
1130
 *                         'F': bignum, size_t (bignum, padded to fixed length,
1131
 *                              pushed as SSH string)
1132
 * @returns             SSH_OK on success
1133
 *                      SSH_ERROR on error
1134
 * @warning             when using 'P' with a constant size (e.g. 8), do not
1135
 *                      forget to cast to (size_t).
1136
 */
1137
int _ssh_buffer_pack(struct ssh_buffer_struct *buffer,
1138
                     const char *format,
1139
                     size_t argc,
1140
                     ...)
1141
0
{
1142
0
    va_list ap;
1143
0
    int rc;
1144
1145
0
    if (argc > 256) {
1146
0
        return SSH_ERROR;
1147
0
    }
1148
1149
0
    va_start(ap, argc);
1150
0
    rc = ssh_buffer_pack_allocate_va(buffer, format, argc, ap);
1151
0
    va_end(ap);
1152
1153
0
    if (rc != SSH_OK) {
1154
0
        return rc;
1155
0
    }
1156
1157
0
    va_start(ap, argc);
1158
0
    rc = ssh_buffer_pack_va(buffer, format, argc, ap);
1159
0
    va_end(ap);
1160
1161
0
    return rc;
1162
0
}
1163
1164
/** @internal
1165
 * @brief Get multiple values from a buffer on a single function call
1166
 * @param[in] buffer    The buffer to get from
1167
 * @param[in] format    A format string of arguments.
1168
 * @param[in] ap        A va_list of arguments.
1169
 * @returns             SSH_OK on success
1170
 *                      SSH_ERROR on error
1171
 * @see ssh_buffer_get_format() for format list values.
1172
 */
1173
int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
1174
                         const char *format,
1175
                         size_t argc,
1176
                         va_list ap)
1177
19
{
1178
19
    int rc = SSH_ERROR;
1179
19
    const char *p = format, *last = NULL;
1180
19
    union {
1181
19
        uint8_t *byte;
1182
19
        uint16_t *word;
1183
19
        uint32_t *dword;
1184
19
        uint64_t *qword;
1185
19
        ssh_string *string;
1186
19
        char **cstring;
1187
19
        bignum *bignum;
1188
19
        void **data;
1189
19
    } o;
1190
19
    size_t len;
1191
19
    uint32_t rlen, max_len;
1192
19
    ssh_string tmp_string = NULL;
1193
19
    va_list ap_copy;
1194
19
    size_t count;
1195
1196
19
    max_len = ssh_buffer_get_len(buffer);
1197
1198
    /* copy the argument list in case a rollback is needed */
1199
19
    va_copy(ap_copy, ap);
1200
1201
19
    if (argc > 256) {
1202
0
        rc = SSH_ERROR;
1203
0
        goto cleanup;
1204
0
    }
1205
1206
58
    for (count = 0; *p != '\0'; p++, count++) {
1207
        /* Invalid number of arguments passed */
1208
55
        if (count > argc) {
1209
0
            rc = SSH_ERROR;
1210
0
            goto cleanup;
1211
0
        }
1212
1213
55
        rc = SSH_ERROR;
1214
55
        switch (*p) {
1215
0
        case 'b':
1216
0
            o.byte = va_arg(ap, uint8_t *);
1217
0
            rlen = ssh_buffer_get_u8(buffer, o.byte);
1218
0
            rc = rlen==1 ? SSH_OK : SSH_ERROR;
1219
0
            break;
1220
0
        case 'w':
1221
0
            o.word = va_arg(ap,  uint16_t *);
1222
0
            rlen = ssh_buffer_get_data(buffer, o.word, sizeof(uint16_t));
1223
0
            if (rlen == 2) {
1224
0
                *o.word = ntohs(*o.word);
1225
0
                rc = SSH_OK;
1226
0
            }
1227
0
            break;
1228
3
        case 'd':
1229
3
            o.dword = va_arg(ap, uint32_t *);
1230
3
            rlen = ssh_buffer_get_u32(buffer, o.dword);
1231
3
            if (rlen == 4) {
1232
3
                *o.dword = ntohl(*o.dword);
1233
3
                rc = SSH_OK;
1234
3
            }
1235
3
            break;
1236
0
        case 'q':
1237
0
            o.qword = va_arg(ap, uint64_t*);
1238
0
            rlen = ssh_buffer_get_u64(buffer, o.qword);
1239
0
            if (rlen == 8) {
1240
0
                *o.qword = ntohll(*o.qword);
1241
0
                rc = SSH_OK;
1242
0
            }
1243
0
            break;
1244
0
        case 'B':
1245
0
            o.bignum = va_arg(ap, bignum *);
1246
0
            *o.bignum = NULL;
1247
0
            tmp_string = ssh_buffer_get_ssh_string(buffer);
1248
0
            if (tmp_string == NULL) {
1249
0
                break;
1250
0
            }
1251
0
            *o.bignum = ssh_make_string_bn(tmp_string);
1252
0
            ssh_string_burn(tmp_string);
1253
0
            SSH_STRING_FREE(tmp_string);
1254
0
            rc = (*o.bignum != NULL) ? SSH_OK : SSH_ERROR;
1255
0
            break;
1256
16
        case 'S':
1257
16
            o.string = va_arg(ap, ssh_string *);
1258
16
            *o.string = ssh_buffer_get_ssh_string(buffer);
1259
16
            rc = *o.string != NULL ? SSH_OK : SSH_ERROR;
1260
16
            o.string = NULL;
1261
16
            break;
1262
22
        case 's': {
1263
22
            uint32_t u32len = 0;
1264
1265
22
            o.cstring = va_arg(ap, char **);
1266
22
            *o.cstring = NULL;
1267
22
            rlen = ssh_buffer_get_u32(buffer, &u32len);
1268
22
            if (rlen != 4){
1269
1
                break;
1270
1
            }
1271
21
            u32len = ntohl(u32len);
1272
21
            if (u32len > max_len - 1) {
1273
9
                break;
1274
9
            }
1275
1276
12
            rc = ssh_buffer_validate_length(buffer, u32len);
1277
12
            if (rc != SSH_OK) {
1278
1
                break;
1279
1
            }
1280
1281
11
            *o.cstring = malloc(u32len + 1);
1282
11
            if (*o.cstring == NULL){
1283
0
                rc = SSH_ERROR;
1284
0
                break;
1285
0
            }
1286
11
            rlen = ssh_buffer_get_data(buffer, *o.cstring, u32len);
1287
11
            if (rlen != u32len) {
1288
0
                SAFE_FREE(*o.cstring);
1289
0
                rc = SSH_ERROR;
1290
0
                break;
1291
0
            }
1292
11
            (*o.cstring)[u32len] = '\0';
1293
11
            o.cstring = NULL;
1294
11
            rc = SSH_OK;
1295
11
            break;
1296
11
        }
1297
14
        case 'P':
1298
14
            len = va_arg(ap, size_t);
1299
14
            if (len > max_len - 1) {
1300
0
                rc = SSH_ERROR;
1301
0
                break;
1302
0
            }
1303
1304
14
            rc = ssh_buffer_validate_length(buffer, len);
1305
14
            if (rc != SSH_OK) {
1306
0
                break;
1307
0
            }
1308
1309
14
            o.data = va_arg(ap, void **);
1310
14
            count++;
1311
1312
14
            *o.data = malloc(len);
1313
14
            if(*o.data == NULL){
1314
0
                rc = SSH_ERROR;
1315
0
                break;
1316
0
            }
1317
14
            rlen = ssh_buffer_get_data(buffer, *o.data, (uint32_t)len);
1318
14
            if (rlen != len){
1319
0
                SAFE_FREE(*o.data);
1320
0
                rc = SSH_ERROR;
1321
0
                break;
1322
0
            }
1323
14
            o.data = NULL;
1324
14
            rc = SSH_OK;
1325
14
            break;
1326
0
        default:
1327
0
            SSH_LOG(SSH_LOG_TRACE, "Invalid buffer format %c", *p);
1328
55
        }
1329
55
        if (rc != SSH_OK) {
1330
16
            break;
1331
16
        }
1332
55
    }
1333
1334
19
    if (argc != count) {
1335
16
        rc = SSH_ERROR;
1336
16
    }
1337
1338
19
cleanup:
1339
19
    if (rc != SSH_ERROR){
1340
        /* Check if our canary is intact, if not something really bad happened */
1341
3
        uint32_t canary = va_arg(ap, uint32_t);
1342
3
        if (canary != SSH_BUFFER_PACK_END){
1343
0
            abort();
1344
0
        }
1345
3
    }
1346
1347
19
    if (rc != SSH_OK){
1348
        /* Reset the format string and erase everything that was allocated */
1349
16
        last = p;
1350
44
        for(p=format;p<last;++p){
1351
28
            switch(*p){
1352
0
            case 'b':
1353
0
                o.byte = va_arg(ap_copy, uint8_t *);
1354
0
                if (buffer->secure) {
1355
0
                    explicit_bzero(o.byte, sizeof(uint8_t));
1356
0
                    break;
1357
0
                }
1358
0
                break;
1359
0
            case 'w':
1360
0
                o.word = va_arg(ap_copy, uint16_t *);
1361
0
                if (buffer->secure) {
1362
0
                    explicit_bzero(o.word, sizeof(uint16_t));
1363
0
                    break;
1364
0
                }
1365
0
                break;
1366
2
            case 'd':
1367
2
                o.dword = va_arg(ap_copy, uint32_t *);
1368
2
                if (buffer->secure) {
1369
2
                    explicit_bzero(o.dword, sizeof(uint32_t));
1370
2
                    break;
1371
2
                }
1372
0
                break;
1373
0
            case 'q':
1374
0
                o.qword = va_arg(ap_copy, uint64_t *);
1375
0
                if (buffer->secure) {
1376
0
                    explicit_bzero(o.qword, sizeof(uint64_t));
1377
0
                    break;
1378
0
                }
1379
0
                break;
1380
0
            case 'B':
1381
0
                o.bignum = va_arg(ap_copy, bignum *);
1382
0
                bignum_safe_free(*o.bignum);
1383
0
                break;
1384
4
            case 'S':
1385
4
                o.string = va_arg(ap_copy, ssh_string *);
1386
4
                if (buffer->secure) {
1387
4
                    ssh_string_burn(*o.string);
1388
4
                }
1389
4
                SAFE_FREE(*o.string);
1390
4
                break;
1391
9
            case 's':
1392
9
                o.cstring = va_arg(ap_copy, char **);
1393
9
                if (buffer->secure) {
1394
9
                    explicit_bzero(*o.cstring, strlen(*o.cstring));
1395
9
                }
1396
9
                SAFE_FREE(*o.cstring);
1397
9
                break;
1398
13
            case 'P':
1399
13
                len = va_arg(ap_copy, size_t);
1400
13
                o.data = va_arg(ap_copy, void **);
1401
13
                if (buffer->secure) {
1402
13
                    explicit_bzero(*o.data, len);
1403
13
                }
1404
13
                SAFE_FREE(*o.data);
1405
13
                break;
1406
0
            default:
1407
0
                (void)va_arg(ap_copy, void *);
1408
0
                break;
1409
28
            }
1410
28
        }
1411
16
    }
1412
19
    va_end(ap_copy);
1413
1414
19
    return rc;
1415
19
}
1416
1417
/** @internal
1418
 * @brief Get multiple values from a buffer on a single function call
1419
 * @param[in] buffer    The buffer to get from
1420
 * @param[in] format    A format string of arguments. This string contains single
1421
 *                      letters describing the order and type of arguments:
1422
 *                         'b': uint8_t *  (pulled in network byte order)
1423
 *                         'w': uint16_t * (pulled in network byte order)
1424
 *                         'd': uint32_t * (pulled in network byte order)
1425
 *                         'q': uint64_t * (pulled in network byte order)
1426
 *                         'S': ssh_string *
1427
 *                         's': char ** (C string, pulled as SSH string)
1428
 *                         'P': size_t, void ** (len of data, pointer to data)
1429
 *                              only pulls data.
1430
 *                         'B': bignum * (pulled as SSH string)
1431
 * @returns             SSH_OK on success
1432
 *                      SSH_ERROR on error
1433
 * @warning             when using 'P' with a constant size (e.g. 8), do not
1434
 *                      forget to cast to (size_t).
1435
 */
1436
int _ssh_buffer_unpack(struct ssh_buffer_struct *buffer,
1437
                       const char *format,
1438
                       size_t argc,
1439
                       ...)
1440
19
{
1441
19
    va_list ap;
1442
19
    int rc;
1443
1444
19
    va_start(ap, argc);
1445
19
    rc = ssh_buffer_unpack_va(buffer, format, argc, ap);
1446
    va_end(ap);
1447
19
    return rc;
1448
19
}
1449
1450
/** @} */