[BACK]Return to sshbuf-getput-basic.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/sshbuf-getput-basic.c, Revision 1.2

1.2     ! djm         1: /*     $OpenBSD: sshbuf-getput-basic.c,v 1.1 2014/04/30 05:29:56 djm Exp $     */
1.1       djm         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: #include <sys/types.h>
                     19: #include <stdlib.h>
                     20: #include <stdio.h>
                     21: #include <string.h>
                     22:
                     23: #include "ssherr.h"
                     24: #define SSHBUF_INTERNAL
                     25: #include "sshbuf.h"
                     26:
                     27: int
                     28: sshbuf_get(struct sshbuf *buf, void *v, size_t len)
                     29: {
                     30:        const u_char *p = sshbuf_ptr(buf);
                     31:        int r;
                     32:
                     33:        if ((r = sshbuf_consume(buf, len)) < 0)
                     34:                return r;
                     35:        if (v != NULL)
                     36:                memcpy(v, p, len);
                     37:        return 0;
                     38: }
                     39:
                     40: int
                     41: sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp)
                     42: {
                     43:        const u_char *p = sshbuf_ptr(buf);
                     44:        int r;
                     45:
                     46:        if ((r = sshbuf_consume(buf, 8)) < 0)
                     47:                return r;
                     48:        if (valp != NULL)
                     49:                *valp = PEEK_U64(p);
                     50:        return 0;
                     51: }
                     52:
                     53: int
                     54: sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp)
                     55: {
                     56:        const u_char *p = sshbuf_ptr(buf);
                     57:        int r;
                     58:
                     59:        if ((r = sshbuf_consume(buf, 4)) < 0)
                     60:                return r;
                     61:        if (valp != NULL)
                     62:                *valp = PEEK_U32(p);
                     63:        return 0;
                     64: }
                     65:
                     66: int
                     67: sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp)
                     68: {
                     69:        const u_char *p = sshbuf_ptr(buf);
                     70:        int r;
                     71:
                     72:        if ((r = sshbuf_consume(buf, 2)) < 0)
                     73:                return r;
                     74:        if (valp != NULL)
                     75:                *valp = PEEK_U16(p);
                     76:        return 0;
                     77: }
                     78:
                     79: int
                     80: sshbuf_get_u8(struct sshbuf *buf, u_char *valp)
                     81: {
                     82:        const u_char *p = sshbuf_ptr(buf);
                     83:        int r;
                     84:
                     85:        if ((r = sshbuf_consume(buf, 1)) < 0)
                     86:                return r;
                     87:        if (valp != NULL)
                     88:                *valp = (u_int8_t)*p;
                     89:        return 0;
                     90: }
                     91:
                     92: int
                     93: sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp)
                     94: {
                     95:        const u_char *val;
                     96:        size_t len;
                     97:        int r;
                     98:
                     99:        if (valp != NULL)
                    100:                *valp = NULL;
                    101:        if (lenp != NULL)
                    102:                *lenp = 0;
                    103:        if ((r = sshbuf_get_string_direct(buf, &val, &len)) < 0)
                    104:                return r;
                    105:        if (valp != NULL) {
                    106:                if ((*valp = malloc(len + 1)) == NULL) {
                    107:                        SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
                    108:                        return SSH_ERR_ALLOC_FAIL;
                    109:                }
                    110:                memcpy(*valp, val, len);
                    111:                (*valp)[len] = '\0';
                    112:        }
                    113:        if (lenp != NULL)
                    114:                *lenp = len;
                    115:        return 0;
                    116: }
                    117:
                    118: int
                    119: sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, size_t *lenp)
                    120: {
                    121:        size_t len;
                    122:        const u_char *p;
                    123:        int r;
                    124:
                    125:        if (valp != NULL)
                    126:                *valp = NULL;
                    127:        if (lenp != NULL)
                    128:                *lenp = 0;
                    129:        if ((r = sshbuf_peek_string_direct(buf, &p, &len)) < 0)
                    130:                return r;
                    131:        if (valp != 0)
                    132:                *valp = p;
                    133:        if (lenp != NULL)
                    134:                *lenp = len;
                    135:        if (sshbuf_consume(buf, len + 4) != 0) {
                    136:                /* Shouldn't happen */
                    137:                SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
                    138:                SSHBUF_ABORT();
                    139:                return SSH_ERR_INTERNAL_ERROR;
                    140:        }
                    141:        return 0;
                    142: }
                    143:
                    144: int
                    145: sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp,
                    146:     size_t *lenp)
                    147: {
                    148:        u_int32_t len;
                    149:        const u_char *p = sshbuf_ptr(buf);
                    150:
                    151:        if (valp != NULL)
                    152:                *valp = NULL;
                    153:        if (lenp != NULL)
                    154:                *lenp = 0;
                    155:        if (sshbuf_len(buf) < 4) {
                    156:                SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
                    157:                return SSH_ERR_MESSAGE_INCOMPLETE;
                    158:        }
                    159:        len = PEEK_U32(p);
                    160:        if (len > SSHBUF_SIZE_MAX - 4) {
                    161:                SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE"));
                    162:                return SSH_ERR_STRING_TOO_LARGE;
                    163:        }
                    164:        if (sshbuf_len(buf) - 4 < len) {
                    165:                SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
                    166:                return SSH_ERR_MESSAGE_INCOMPLETE;
                    167:        }
                    168:        if (valp != 0)
                    169:                *valp = p + 4;
                    170:        if (lenp != NULL)
                    171:                *lenp = len;
                    172:        return 0;
                    173: }
                    174:
                    175: int
                    176: sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp)
                    177: {
                    178:        size_t len;
                    179:        const u_char *p, *z;
                    180:        int r;
                    181:
                    182:        if (valp != NULL)
                    183:                *valp = NULL;
                    184:        if (lenp != NULL)
                    185:                *lenp = 0;
                    186:        if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
                    187:                return r;
                    188:        /* Allow a \0 only at the end of the string */
                    189:        if (len > 0 &&
                    190:            (z = memchr(p , '\0', len)) != NULL && z < p + len - 1) {
                    191:                SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT"));
                    192:                return SSH_ERR_INVALID_FORMAT;
                    193:        }
                    194:        if ((r = sshbuf_skip_string(buf)) != 0)
                    195:                return -1;
                    196:        if (valp != NULL) {
                    197:                if ((*valp = malloc(len + 1)) == NULL) {
                    198:                        SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
                    199:                        return SSH_ERR_ALLOC_FAIL;
                    200:                }
                    201:                memcpy(*valp, p, len);
                    202:                (*valp)[len] = '\0';
                    203:        }
                    204:        if (lenp != NULL)
                    205:                *lenp = (size_t)len;
                    206:        return 0;
                    207: }
                    208:
                    209: int
                    210: sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v)
                    211: {
                    212:        u_int32_t len;
                    213:        u_char *p;
                    214:        int r;
                    215:
                    216:        /*
                    217:         * Use sshbuf_peek_string_direct() to figure out if there is
                    218:         * a complete string in 'buf' and copy the string directly
                    219:         * into 'v'.
                    220:         */
                    221:        if ((r = sshbuf_peek_string_direct(buf, NULL, NULL)) != 0 ||
                    222:            (r = sshbuf_get_u32(buf, &len)) != 0 ||
                    223:            (r = sshbuf_reserve(v, len, &p)) != 0 ||
                    224:            (r = sshbuf_get(buf, p, len)) != 0)
                    225:                return r;
                    226:        return 0;
                    227: }
                    228:
                    229: int
                    230: sshbuf_put(struct sshbuf *buf, const void *v, size_t len)
                    231: {
                    232:        u_char *p;
                    233:        int r;
                    234:
                    235:        if ((r = sshbuf_reserve(buf, len, &p)) < 0)
                    236:                return r;
                    237:        memcpy(p, v, len);
                    238:        return 0;
                    239: }
                    240:
                    241: int
                    242: sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v)
                    243: {
                    244:        return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v));
                    245: }
                    246:
                    247: int
                    248: sshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
                    249: {
                    250:        va_list ap;
                    251:        int r;
                    252:
                    253:        va_start(ap, fmt);
                    254:        r = sshbuf_putfv(buf, fmt, ap);
                    255:        va_end(ap);
                    256:        return r;
                    257: }
                    258:
                    259: int
                    260: sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap)
                    261: {
                    262:        va_list ap2;
                    263:        int r, len;
                    264:        u_char *p;
                    265:
                    266:        va_copy(ap2, ap);
                    267:        if ((len = vsnprintf(NULL, 0, fmt, ap2)) < 0) {
                    268:                r = SSH_ERR_INVALID_ARGUMENT;
                    269:                goto out;
                    270:        }
                    271:        if (len == 0) {
                    272:                r = 0;
                    273:                goto out; /* Nothing to do */
                    274:        }
                    275:        va_end(ap2);
                    276:        va_copy(ap2, ap);
                    277:        if ((r = sshbuf_reserve(buf, (size_t)len + 1, &p)) < 0)
                    278:                goto out;
                    279:        if ((r = vsnprintf((char *)p, len + 1, fmt, ap2)) != len) {
                    280:                r = SSH_ERR_INTERNAL_ERROR;
                    281:                goto out; /* Shouldn't happen */
                    282:        }
                    283:        /* Consume terminating \0 */
                    284:        if ((r = sshbuf_consume_end(buf, 1)) != 0)
                    285:                goto out;
                    286:        r = 0;
                    287:  out:
                    288:        va_end(ap2);
                    289:        return r;
                    290: }
                    291:
                    292: int
                    293: sshbuf_put_u64(struct sshbuf *buf, u_int64_t val)
                    294: {
                    295:        u_char *p;
                    296:        int r;
                    297:
                    298:        if ((r = sshbuf_reserve(buf, 8, &p)) < 0)
                    299:                return r;
                    300:        POKE_U64(p, val);
                    301:        return 0;
                    302: }
                    303:
                    304: int
                    305: sshbuf_put_u32(struct sshbuf *buf, u_int32_t val)
                    306: {
                    307:        u_char *p;
                    308:        int r;
                    309:
                    310:        if ((r = sshbuf_reserve(buf, 4, &p)) < 0)
                    311:                return r;
                    312:        POKE_U32(p, val);
                    313:        return 0;
                    314: }
                    315:
                    316: int
                    317: sshbuf_put_u16(struct sshbuf *buf, u_int16_t val)
                    318: {
                    319:        u_char *p;
                    320:        int r;
                    321:
                    322:        if ((r = sshbuf_reserve(buf, 2, &p)) < 0)
                    323:                return r;
                    324:        POKE_U16(p, val);
                    325:        return 0;
                    326: }
                    327:
                    328: int
                    329: sshbuf_put_u8(struct sshbuf *buf, u_char val)
                    330: {
                    331:        u_char *p;
                    332:        int r;
                    333:
                    334:        if ((r = sshbuf_reserve(buf, 1, &p)) < 0)
                    335:                return r;
                    336:        p[0] = val;
                    337:        return 0;
                    338: }
                    339:
                    340: int
                    341: sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len)
                    342: {
                    343:        u_char *d;
                    344:        int r;
                    345:
                    346:        if (len > SSHBUF_SIZE_MAX - 4) {
                    347:                SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
                    348:                return SSH_ERR_NO_BUFFER_SPACE;
                    349:        }
                    350:        if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0)
                    351:                return r;
                    352:        POKE_U32(d, len);
                    353:        memcpy(d + 4, v, len);
                    354:        return 0;
                    355: }
                    356:
                    357: int
                    358: sshbuf_put_cstring(struct sshbuf *buf, const char *v)
                    359: {
1.2     ! djm       360:        return sshbuf_put_string(buf, (u_char *)v, v == NULL ? 0 : strlen(v));
1.1       djm       361: }
                    362:
                    363: int
                    364: sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v)
                    365: {
                    366:        return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v));
                    367: }
                    368:
                    369: int
                    370: sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp)
                    371: {
                    372:        const u_char *p;
                    373:        size_t len;
                    374:        struct sshbuf *ret;
                    375:        int r;
                    376:
                    377:        if (buf == NULL || bufp == NULL)
                    378:                return SSH_ERR_INVALID_ARGUMENT;
                    379:        *bufp = NULL;
                    380:        if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
                    381:                return r;
                    382:        if ((ret = sshbuf_from(p, len)) == NULL)
                    383:                return SSH_ERR_ALLOC_FAIL;
                    384:        if ((r = sshbuf_consume(buf, len + 4)) != 0 ||  /* Shouldn't happen */
                    385:            (r = sshbuf_set_parent(ret, buf)) != 0) {
                    386:                sshbuf_free(ret);
                    387:                return r;
                    388:        }
                    389:        *bufp = ret;
                    390:        return 0;
                    391: }
                    392:
                    393: int
                    394: sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len)
                    395: {
                    396:        u_char *d;
                    397:        const u_char *s = (const u_char *)v;
                    398:        int r, prepend;
                    399:
                    400:        if (len > SSHBUF_SIZE_MAX - 5) {
                    401:                SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
                    402:                return SSH_ERR_NO_BUFFER_SPACE;
                    403:        }
                    404:        /* Skip leading zero bytes */
                    405:        for (; len > 0 && *s == 0; len--, s++)
                    406:                ;
                    407:        /*
                    408:         * If most significant bit is set then prepend a zero byte to
                    409:         * avoid interpretation as a negative number.
                    410:         */
                    411:        prepend = len > 0 && (s[0] & 0x80) != 0;
                    412:        if ((r = sshbuf_reserve(buf, len + 4 + prepend, &d)) < 0)
                    413:                return r;
                    414:        POKE_U32(d, len + prepend);
                    415:        if (prepend)
                    416:                d[4] = 0;
                    417:        memcpy(d + 4 + prepend, s, len);
                    418:        return 0;
                    419: }