Coverage Report

Created: 2026-05-30 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libssh/src/string.c
Line
Count
Source
1
/*
2
 * string.c - ssh string functions
3
 *
4
 * This file is part of the SSH Library
5
 *
6
 * Copyright (c) 2003-2008 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 <errno.h>
27
#include <limits.h>
28
29
#ifndef _WIN32
30
#include <arpa/inet.h>
31
#include <netinet/in.h>
32
#endif
33
34
#include "libssh/priv.h"
35
#include "libssh/string.h"
36
37
/* String maximum size is 256M */
38
0
#define STRING_SIZE_MAX 0x10000000
39
40
/**
41
 * @defgroup libssh_string The SSH string functions
42
 * @ingroup libssh
43
 *
44
 * @brief String manipulations used in libssh.
45
 *
46
 * @{
47
 */
48
49
/**
50
 * @brief Create a new SSH String object.
51
 *
52
 * @param[in] size       The size of the string.
53
 *
54
 * @return               The newly allocated string, NULL on error.
55
 */
56
struct ssh_string_struct *ssh_string_new(size_t size)
57
0
{
58
0
    struct ssh_string_struct *str = NULL;
59
60
0
    if (size > STRING_SIZE_MAX) {
61
0
        errno = EINVAL;
62
0
        return NULL;
63
0
    }
64
65
0
    str = calloc(1, sizeof(struct ssh_string_struct) + size);
66
0
    if (str == NULL) {
67
0
        return NULL;
68
0
    }
69
70
0
    str->size = htonl((uint32_t)size);
71
72
0
    return str;
73
0
}
74
75
/**
76
 * @brief Fill a string with given data. The string should be big enough.
77
 *
78
 * @param s        An allocated string to fill with data.
79
 *
80
 * @param data     The data to fill the string with.
81
 *
82
 * @param len      Size of data.
83
 *
84
 * @return         0 on success, < 0 on error.
85
 */
86
int ssh_string_fill(struct ssh_string_struct *s, const void *data, size_t len)
87
0
{
88
0
    if ((s == NULL) || (data == NULL) || (len == 0) ||
89
0
        (len > ssh_string_len(s))) {
90
0
        return -1;
91
0
    }
92
93
0
    memcpy(s->data, data, len);
94
95
0
    return 0;
96
0
}
97
98
/**
99
 * @brief Create a ssh string using a C string
100
 *
101
 * @param[in] what      The source 0-terminated C string.
102
 *
103
 * @return              The newly allocated string, NULL on error with errno
104
 *                      set.
105
 *
106
 * @note The null byte is not copied nor counted in the output string.
107
 */
108
struct ssh_string_struct *ssh_string_from_char(const char *what)
109
0
{
110
0
    struct ssh_string_struct *ptr = NULL;
111
0
    size_t len;
112
113
0
    if (what == NULL) {
114
0
        errno = EINVAL;
115
0
        return NULL;
116
0
    }
117
118
0
    len = strlen(what);
119
120
0
    ptr = ssh_string_new(len);
121
0
    if (ptr == NULL) {
122
0
        return NULL;
123
0
    }
124
125
0
    memcpy(ptr->data, what, len);
126
127
0
    return ptr;
128
0
}
129
130
/**
131
 * @brief Create a ssh string from an arbitrary data buffer.
132
 *
133
 * Allocates a new SSH string of length `len` and copies the provided data
134
 * into it. If len is 0, returns an empty SSH string. When len > 0, data
135
 * must not be NULL.
136
 *
137
 * @param[in] data     Pointer to the data buffer to copy from. May be NULL
138
 *                     only when len == 0.
139
 * @param[in] len      Length of the data buffer to copy.
140
 *
141
 * @return             The newly allocated string, NULL on error.
142
 */
143
struct ssh_string_struct *ssh_string_from_data(const void *data, size_t len)
144
0
{
145
0
    struct ssh_string_struct *s = NULL;
146
0
    int rc;
147
148
0
    if (len > 0 && data == NULL) {
149
0
        errno = EINVAL;
150
0
        return NULL;
151
0
    }
152
153
0
    s = ssh_string_new(len);
154
0
    if (s == NULL) {
155
0
        return NULL;
156
0
    }
157
158
0
    if (len > 0) {
159
0
        rc = ssh_string_fill(s, data, len);
160
0
        if (rc != 0) {
161
0
            ssh_string_free(s);
162
0
            return NULL;
163
0
        }
164
0
    }
165
166
0
    return s;
167
0
}
168
169
/**
170
 * @brief Return the size of a SSH string.
171
 *
172
 * @param[in] s         The input SSH string.
173
 *
174
 * @return The size of the content of the string, 0 on error.
175
 */
176
size_t ssh_string_len(struct ssh_string_struct *s)
177
0
{
178
0
    size_t size;
179
180
0
    if (s == NULL) {
181
0
        return 0;
182
0
    }
183
184
0
    size = ntohl(s->size);
185
0
    if (size > 0 && size <= STRING_SIZE_MAX) {
186
0
        return size;
187
0
    }
188
189
0
    return 0;
190
0
}
191
192
/**
193
 * @brief Get the string as a C null-terminated string.
194
 *
195
 * This is only available as long as the SSH string exists.
196
 *
197
 * @param[in] s         The SSH string to get the C string from.
198
 *
199
 * @return              The char pointer, NULL on error.
200
 */
201
const char *ssh_string_get_char(struct ssh_string_struct *s)
202
0
{
203
0
    if (s == NULL) {
204
0
        return NULL;
205
0
    }
206
0
    s->data[ssh_string_len(s)] = '\0';
207
208
0
    return (const char *)s->data;
209
0
}
210
211
/**
212
 * @brief Convert a SSH string to a C null-terminated string.
213
 *
214
 * @param[in] s         The SSH input string.
215
 *
216
 * @return              An allocated string pointer, NULL on error with errno
217
 *                      set.
218
 *
219
 * @note If the input SSH string contains zeroes, some parts of the output
220
 * string may not be readable with regular libc functions.
221
 */
222
char *ssh_string_to_char(struct ssh_string_struct *s)
223
0
{
224
0
    size_t len;
225
0
    char *new = NULL;
226
227
0
    if (s == NULL) {
228
0
        return NULL;
229
0
    }
230
231
0
    len = ssh_string_len(s);
232
0
    if (len + 1 < len) {
233
0
        return NULL;
234
0
    }
235
236
0
    new = malloc(len + 1);
237
0
    if (new == NULL) {
238
0
        return NULL;
239
0
    }
240
0
    memcpy(new, s->data, len);
241
0
    new[len] = '\0';
242
243
0
    return new;
244
0
}
245
246
/**
247
 * @brief Deallocate a char string object.
248
 *
249
 * @param[in] s         The string to delete.
250
 */
251
void ssh_string_free_char(char *s)
252
0
{
253
0
    SAFE_FREE(s);
254
0
}
255
256
/**
257
 * @brief Copy a string, return a newly allocated string. The caller has to
258
 *        free the string.
259
 *
260
 * @param[in] s         String to copy.
261
 *
262
 * @return              Newly allocated copy of the string, NULL on error.
263
 */
264
struct ssh_string_struct *ssh_string_copy(struct ssh_string_struct *s)
265
0
{
266
0
    struct ssh_string_struct *new = NULL;
267
0
    size_t len;
268
269
0
    if (s == NULL) {
270
0
        return NULL;
271
0
    }
272
273
0
    len = ssh_string_len(s);
274
275
0
    new = ssh_string_new(len);
276
0
    if (new == NULL) {
277
0
        return NULL;
278
0
    }
279
280
0
    memcpy(new->data, s->data, len);
281
282
0
    return new;
283
0
}
284
285
/**
286
 * @brief Compare two SSH strings.
287
 *
288
 * @param[in] s1        The first SSH string to compare.
289
 * @param[in] s2        The second SSH string to compare.
290
 *
291
 * @return              0 if the strings are equal,
292
 *                      < 0 if s1 is less than s2,
293
 *                      > 0 if s1 is greater than s2.
294
 */
295
int ssh_string_cmp(struct ssh_string_struct *s1, struct ssh_string_struct *s2)
296
0
{
297
0
    size_t len1, len2, min_len;
298
0
    int cmp;
299
300
    /* Both are NULL */
301
0
    if (s1 == NULL && s2 == NULL) {
302
0
        return 0;
303
0
    }
304
305
    /* Only one is NULL - NULL is considered "less than" non-NULL */
306
0
    if (s1 == NULL) {
307
0
        return -1;
308
0
    } else if (s2 == NULL) {
309
0
        return 1;
310
0
    }
311
312
    /* Get lengths */
313
0
    len1 = ssh_string_len(s1);
314
0
    len2 = ssh_string_len(s2);
315
0
    min_len = MIN(len1, len2);
316
317
    /* Compare data up to the shorter length */
318
0
    if (min_len > 0) {
319
0
        cmp = memcmp(s1->data, s2->data, min_len);
320
0
        if (cmp != 0) {
321
0
            return cmp;
322
0
        }
323
0
    }
324
325
    /* If common prefix is equal, compare lengths */
326
0
    if (len1 < len2) {
327
0
        return -1;
328
0
    } else if (len1 > len2) {
329
0
        return 1;
330
0
    }
331
332
0
    return 0;
333
0
}
334
335
/**
336
 * @brief Destroy the data in a string so it couldn't appear in a core dump.
337
 *
338
 * @param[in] s         The string to burn.
339
 */
340
void ssh_string_burn(struct ssh_string_struct *s)
341
0
{
342
0
    if (s == NULL || s->size == 0) {
343
0
        return;
344
0
    }
345
346
0
    ssh_burn(s->data, ssh_string_len(s));
347
0
}
348
349
/**
350
 * @brief Get the payload of the string.
351
 *
352
 * @param s             The string to get the data from.
353
 *
354
 * @return              Return the data of the string or NULL on error.
355
 */
356
void *ssh_string_data(struct ssh_string_struct *s)
357
0
{
358
0
    if (s == NULL) {
359
0
        return NULL;
360
0
    }
361
362
0
    return s->data;
363
0
}
364
365
/**
366
 * @brief Deallocate a SSH string object.
367
 *
368
 * \param[in] s         The SSH string to delete.
369
 */
370
void ssh_string_free(struct ssh_string_struct *s)
371
0
{
372
    SAFE_FREE(s);
373
0
}
374
375
/** @} */