Coverage Report

Created: 2025-10-13 07:25

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