Coverage Report

Created: 2025-08-26 06:26

/src/libssh/src/string.c
Line
Count
Source (jump to first uncovered line)
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
2.19k
#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
1.50k
{
58
1.50k
    struct ssh_string_struct *str = NULL;
59
60
1.50k
    if (size > STRING_SIZE_MAX) {
61
0
        errno = EINVAL;
62
0
        return NULL;
63
0
    }
64
65
1.50k
    str = malloc(sizeof(struct ssh_string_struct) + size);
66
1.50k
    if (str == NULL) {
67
0
        return NULL;
68
0
    }
69
70
1.50k
    str->size = htonl((uint32_t)size);
71
1.50k
    str->data[0] = 0;
72
73
1.50k
    return str;
74
1.50k
}
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
111
{
111
111
    struct ssh_string_struct *ptr = NULL;
112
111
    size_t len;
113
114
111
    if (what == NULL) {
115
0
        errno = EINVAL;
116
0
        return NULL;
117
0
    }
118
119
111
    len = strlen(what);
120
121
111
    ptr = ssh_string_new(len);
122
111
    if (ptr == NULL) {
123
0
        return NULL;
124
0
    }
125
126
111
    memcpy(ptr->data, what, len);
127
128
111
    return ptr;
129
111
}
130
131
/**
132
 * @brief Return the size of a SSH string.
133
 *
134
 * @param[in] s         The input SSH string.
135
 *
136
 * @return The size of the content of the string, 0 on error.
137
 */
138
size_t ssh_string_len(struct ssh_string_struct *s)
139
788
{
140
788
    size_t size;
141
142
788
    if (s == NULL) {
143
6
        return 0;
144
6
    }
145
146
782
    size = ntohl(s->size);
147
782
    if (size > 0 && size <= STRING_SIZE_MAX) {
148
690
        return size;
149
690
    }
150
151
92
    return 0;
152
782
}
153
154
/**
155
 * @brief Get the string as a C null-terminated string.
156
 *
157
 * This is only available as long as the SSH string exists.
158
 *
159
 * @param[in] s         The SSH string to get the C string from.
160
 *
161
 * @return              The char pointer, NULL on error.
162
 */
163
const char *ssh_string_get_char(struct ssh_string_struct *s)
164
116
{
165
116
    if (s == NULL) {
166
0
        return NULL;
167
0
    }
168
116
    s->data[ssh_string_len(s)] = '\0';
169
170
116
    return (const char *)s->data;
171
116
}
172
173
/**
174
 * @brief Convert a SSH string to a C null-terminated string.
175
 *
176
 * @param[in] s         The SSH input string.
177
 *
178
 * @return              An allocated string pointer, NULL on error with errno
179
 *                      set.
180
 *
181
 * @note If the input SSH string contains zeroes, some parts of the output
182
 * string may not be readable with regular libc functions.
183
 */
184
char *ssh_string_to_char(struct ssh_string_struct *s)
185
0
{
186
0
    size_t len;
187
0
    char *new = NULL;
188
189
0
    if (s == NULL) {
190
0
        return NULL;
191
0
    }
192
193
0
    len = ssh_string_len(s);
194
0
    if (len + 1 < len) {
195
0
        return NULL;
196
0
    }
197
198
0
    new = malloc(len + 1);
199
0
    if (new == NULL) {
200
0
        return NULL;
201
0
    }
202
0
    memcpy(new, s->data, len);
203
0
    new[len] = '\0';
204
205
0
    return new;
206
0
}
207
208
/**
209
 * @brief Deallocate a char string object.
210
 *
211
 * @param[in] s         The string to delete.
212
 */
213
void ssh_string_free_char(char *s)
214
0
{
215
0
    SAFE_FREE(s);
216
0
}
217
218
/**
219
 * @brief Copy a string, return a newly allocated string. The caller has to
220
 *        free the string.
221
 *
222
 * @param[in] s         String to copy.
223
 *
224
 * @return              Newly allocated copy of the string, NULL on error.
225
 */
226
struct ssh_string_struct *ssh_string_copy(struct ssh_string_struct *s)
227
0
{
228
0
    struct ssh_string_struct *new = NULL;
229
0
    size_t len;
230
231
0
    if (s == NULL) {
232
0
        return NULL;
233
0
    }
234
235
0
    len = ssh_string_len(s);
236
237
0
    new = ssh_string_new(len);
238
0
    if (new == NULL) {
239
0
        return NULL;
240
0
    }
241
242
0
    memcpy(new->data, s->data, len);
243
244
0
    return new;
245
0
}
246
247
/**
248
 * @brief Compare two SSH strings.
249
 *
250
 * @param[in] s1        The first SSH string to compare.
251
 * @param[in] s2        The second SSH string to compare.
252
 *
253
 * @return              0 if the strings are equal,
254
 *                      < 0 if s1 is less than s2,
255
 *                      > 0 if s1 is greater than s2.
256
 */
257
int ssh_string_cmp(struct ssh_string_struct *s1, struct ssh_string_struct *s2)
258
0
{
259
0
    size_t len1, len2, min_len;
260
0
    int cmp;
261
262
    /* Both are NULL */
263
0
    if (s1 == NULL && s2 == NULL) {
264
0
        return 0;
265
0
    }
266
267
    /* Only one is NULL - NULL is considered "less than" non-NULL */
268
0
    if (s1 == NULL) {
269
0
        return -1;
270
0
    } else if (s2 == NULL) {
271
0
        return 1;
272
0
    }
273
274
    /* Get lengths */
275
0
    len1 = ssh_string_len(s1);
276
0
    len2 = ssh_string_len(s2);
277
0
    min_len = MIN(len1, len2);
278
279
    /* Compare data up to the shorter length */
280
0
    if (min_len > 0) {
281
0
        cmp = memcmp(s1->data, s2->data, min_len);
282
0
        if (cmp != 0) {
283
0
            return cmp;
284
0
        }
285
0
    }
286
287
    /* If common prefix is equal, compare lengths */
288
0
    if (len1 < len2) {
289
0
        return -1;
290
0
    } else if (len1 > len2) {
291
0
        return 1;
292
0
    }
293
294
0
    return 0;
295
0
}
296
297
/**
298
 * @brief Destroy the data in a string so it couldn't appear in a core dump.
299
 *
300
 * @param[in] s         The string to burn.
301
 */
302
void ssh_string_burn(struct ssh_string_struct *s)
303
595
{
304
595
    if (s == NULL || s->size == 0) {
305
351
        return;
306
351
    }
307
308
244
    explicit_bzero(s->data, ssh_string_len(s));
309
244
}
310
311
/**
312
 * @brief Get the payload of the string.
313
 *
314
 * @param s             The string to get the data from.
315
 *
316
 * @return              Return the data of the string or NULL on error.
317
 */
318
void *ssh_string_data(struct ssh_string_struct *s)
319
1.43k
{
320
1.43k
    if (s == NULL) {
321
0
        return NULL;
322
0
    }
323
324
1.43k
    return s->data;
325
1.43k
}
326
327
/**
328
 * @brief Deallocate a SSH string object.
329
 *
330
 * \param[in] s         The SSH string to delete.
331
 */
332
void ssh_string_free(struct ssh_string_struct *s)
333
1.20k
{
334
1.20k
    SAFE_FREE(s);
335
1.20k
}
336
337
/** @} */