Coverage Report

Created: 2023-11-19 06:39

/src/libssh/src/options.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * options.c - handle pre-connection options
3
 *
4
 * This file is part of the SSH Library
5
 *
6
 * Copyright (c) 2003-2008 by Aris Adamantiadis
7
 * Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org>
8
 *
9
 * The SSH Library is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU Lesser General Public License as published by
11
 * the Free Software Foundation; either version 2.1 of the License, or (at your
12
 * option) any later version.
13
 *
14
 * The SSH Library is distributed in the hope that it will be useful, but
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17
 * License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with the SSH Library; see the file COPYING.  If not, write to
21
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22
 * MA 02111-1307, USA.
23
 */
24
25
#include "config.h"
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#ifndef _WIN32
30
#include <pwd.h>
31
#else
32
#include <winsock2.h>
33
#endif
34
#include <sys/types.h>
35
#include "libssh/pki_priv.h"
36
#include "libssh/priv.h"
37
#include "libssh/session.h"
38
#include "libssh/misc.h"
39
#include "libssh/options.h"
40
#ifdef WITH_SERVER
41
#include "libssh/server.h"
42
#include "libssh/bind.h"
43
#include "libssh/bind_config.h"
44
#endif
45
46
/**
47
 * @addtogroup libssh_session
48
 * @{
49
 */
50
51
/**
52
 * @brief Duplicate the options of a session structure.
53
 *
54
 * If you make several sessions with the same options this is useful. You
55
 * cannot use twice the same option structure in ssh_connect.
56
 *
57
 * @param src           The session to use to copy the options.
58
 *
59
 * @param dest          A pointer to store the allocated session with duplicated
60
 *                      options. You have to free the memory using ssh_free()
61
 *
62
 * @returns             0 on success, -1 on error with errno set.
63
 *
64
 * @see ssh_connect()
65
 * @see ssh_free()
66
 */
67
int ssh_options_copy(ssh_session src, ssh_session *dest)
68
0
{
69
0
    ssh_session new;
70
0
    struct ssh_iterator *it = NULL;
71
0
    struct ssh_list *list = NULL;
72
0
    char *id = NULL;
73
0
    int i;
74
75
0
    if (src == NULL || dest == NULL) {
76
0
        return -1;
77
0
    }
78
79
0
    new = ssh_new();
80
0
    if (new == NULL) {
81
0
        return -1;
82
0
    }
83
84
0
    if (src->opts.username != NULL) {
85
0
        new->opts.username = strdup(src->opts.username);
86
0
        if (new->opts.username == NULL) {
87
0
            ssh_free(new);
88
0
            return -1;
89
0
        }
90
0
    }
91
92
0
    if (src->opts.host != NULL) {
93
0
        new->opts.host = strdup(src->opts.host);
94
0
        if (new->opts.host == NULL) {
95
0
            ssh_free(new);
96
0
            return -1;
97
0
        }
98
0
    }
99
100
0
    if (src->opts.bindaddr != NULL) {
101
0
        new->opts.bindaddr = strdup(src->opts.bindaddr);
102
0
        if (new->opts.bindaddr == NULL) {
103
0
            ssh_free(new);
104
0
            return -1;
105
0
        }
106
0
    }
107
108
    /* Remove the default identities */
109
0
    for (id = ssh_list_pop_head(char *, new->opts.identity_non_exp);
110
0
         id != NULL;
111
0
         id = ssh_list_pop_head(char *, new->opts.identity_non_exp)) {
112
0
        SAFE_FREE(id);
113
0
    }
114
    /* Copy the new identities from the source list */
115
0
    list = new->opts.identity_non_exp;
116
0
    it = ssh_list_get_iterator(src->opts.identity_non_exp);
117
0
    for (i = 0; i < 2; i++) {
118
0
        while (it) {
119
0
            int rc;
120
121
0
            id = strdup((char *) it->data);
122
0
            if (id == NULL) {
123
0
                ssh_free(new);
124
0
                return -1;
125
0
            }
126
127
0
            rc = ssh_list_append(list, id);
128
0
            if (rc < 0) {
129
0
                free(id);
130
0
                ssh_free(new);
131
0
                return -1;
132
0
            }
133
0
            it = it->next;
134
0
        }
135
136
        /* copy the identity list if there is any already */
137
0
        list = new->opts.identity;
138
0
        it = ssh_list_get_iterator(src->opts.identity);
139
0
    }
140
141
0
    if (src->opts.sshdir != NULL) {
142
0
        new->opts.sshdir = strdup(src->opts.sshdir);
143
0
        if (new->opts.sshdir == NULL) {
144
0
            ssh_free(new);
145
0
            return -1;
146
0
        }
147
0
    }
148
149
0
    if (src->opts.knownhosts != NULL) {
150
0
        new->opts.knownhosts = strdup(src->opts.knownhosts);
151
0
        if (new->opts.knownhosts == NULL) {
152
0
            ssh_free(new);
153
0
            return -1;
154
0
        }
155
0
    }
156
157
0
    if (src->opts.global_knownhosts != NULL) {
158
0
        new->opts.global_knownhosts = strdup(src->opts.global_knownhosts);
159
0
        if (new->opts.global_knownhosts == NULL) {
160
0
            ssh_free(new);
161
0
            return -1;
162
0
        }
163
0
    }
164
165
0
    for (i = 0; i < SSH_KEX_METHODS; i++) {
166
0
        if (src->opts.wanted_methods[i] != NULL) {
167
0
            new->opts.wanted_methods[i] = strdup(src->opts.wanted_methods[i]);
168
0
            if (new->opts.wanted_methods[i] == NULL) {
169
0
                ssh_free(new);
170
0
                return -1;
171
0
            }
172
0
        }
173
0
    }
174
175
0
    if (src->opts.ProxyCommand != NULL) {
176
0
        new->opts.ProxyCommand = strdup(src->opts.ProxyCommand);
177
0
        if (new->opts.ProxyCommand == NULL) {
178
0
            ssh_free(new);
179
0
            return -1;
180
0
        }
181
0
    }
182
183
0
    if (src->opts.pubkey_accepted_types != NULL) {
184
0
        new->opts.pubkey_accepted_types = strdup(src->opts.pubkey_accepted_types);
185
0
        if (new->opts.pubkey_accepted_types == NULL) {
186
0
            ssh_free(new);
187
0
            return -1;
188
0
        }
189
0
    }
190
191
0
    if (src->opts.gss_server_identity != NULL) {
192
0
        new->opts.gss_server_identity = strdup(src->opts.gss_server_identity);
193
0
        if (new->opts.gss_server_identity == NULL) {
194
0
            ssh_free(new);
195
0
            return -1;
196
0
        }
197
0
    }
198
199
0
    if (src->opts.gss_client_identity != NULL) {
200
0
        new->opts.gss_client_identity = strdup(src->opts.gss_client_identity);
201
0
        if (new->opts.gss_client_identity == NULL) {
202
0
            ssh_free(new);
203
0
            return -1;
204
0
        }
205
0
    }
206
207
0
    if (src->opts.control_path != NULL) {
208
0
        new->opts.control_path = strdup(src->opts.control_path);
209
0
        if (new->opts.control_path == NULL) {
210
0
            ssh_free(new);
211
0
            return -1;
212
0
        }
213
0
    }
214
215
0
    memcpy(new->opts.options_seen, src->opts.options_seen,
216
0
           sizeof(new->opts.options_seen));
217
218
0
    new->opts.fd                    = src->opts.fd;
219
0
    new->opts.port                  = src->opts.port;
220
0
    new->opts.timeout               = src->opts.timeout;
221
0
    new->opts.timeout_usec          = src->opts.timeout_usec;
222
0
    new->opts.compressionlevel      = src->opts.compressionlevel;
223
0
    new->opts.StrictHostKeyChecking = src->opts.StrictHostKeyChecking;
224
0
    new->opts.gss_delegate_creds    = src->opts.gss_delegate_creds;
225
0
    new->opts.flags                 = src->opts.flags;
226
0
    new->opts.nodelay               = src->opts.nodelay;
227
0
    new->opts.config_processed      = src->opts.config_processed;
228
0
    new->opts.control_master        = src->opts.control_master;
229
0
    new->common.log_verbosity       = src->common.log_verbosity;
230
0
    new->common.callbacks           = src->common.callbacks;
231
232
0
    *dest = new;
233
234
0
    return 0;
235
0
}
236
237
int ssh_options_set_algo(ssh_session session,
238
                         enum ssh_kex_types_e algo,
239
                         const char *list,
240
                         char **place)
241
44.6k
{
242
    /* When the list start with +,-,^ the filtration of unknown algorithms
243
     * gets handled inside the helper functions, otherwise the list is taken
244
     * as it is. */
245
44.6k
    char *p = (char *)list;
246
247
44.6k
    if (algo < SSH_COMP_C_S) {
248
44.6k
        if (list[0] == '+') {
249
53
            p = ssh_add_to_default_algos(algo, list+1);
250
44.5k
        } else if (list[0] == '-') {
251
37
            p = ssh_remove_from_default_algos(algo, list+1);
252
44.5k
        } else if (list[0] == '^') {
253
65
            p = ssh_prefix_default_algos(algo, list+1);
254
65
        }
255
44.6k
    }
256
257
44.6k
    if (p == list) {
258
44.4k
        if (ssh_fips_mode()) {
259
0
            p = ssh_keep_fips_algos(algo, list);
260
44.4k
        } else {
261
44.4k
            p = ssh_keep_known_algos(algo, list);
262
44.4k
        }
263
44.4k
    }
264
265
44.6k
    if (p == NULL) {
266
4
        ssh_set_error(session, SSH_REQUEST_DENIED,
267
4
                "Setting method: no allowed algorithm for method \"%s\" (%s)",
268
4
                ssh_kex_get_description(algo), list);
269
4
        return -1;
270
4
    }
271
272
44.6k
    SAFE_FREE(*place);
273
44.6k
    *place = p;
274
275
44.6k
    return 0;
276
44.6k
}
277
278
/**
279
 * @brief This function can set all possible ssh options.
280
 *
281
 * @param  session An allocated SSH session structure.
282
 *
283
 * @param  type The option type to set. This could be one of the
284
 *              following:
285
 *
286
 *              - SSH_OPTIONS_HOST:
287
 *                The hostname or ip address to connect to (const char *).
288
 *
289
 *              - SSH_OPTIONS_PORT:
290
 *                The port to connect to (unsigned int *).
291
 *
292
 *              - SSH_OPTIONS_PORT_STR:
293
 *                The port to connect to (const char *).
294
 *
295
 *              - SSH_OPTIONS_FD:
296
 *                The file descriptor to use (socket_t).\n
297
 *                \n
298
 *                If you wish to open the socket yourself for a reason
299
 *                or another, set the file descriptor and take care of closing
300
 *                it (this is new behavior in libssh 0.10).
301
 *                Don't forget to set the hostname as the hostname is used
302
 *                as a key in the known_host mechanism.
303
 *
304
 *              - SSH_OPTIONS_BINDADDR:
305
 *                The address to bind the client to (const char *).
306
 *
307
 *              - SSH_OPTIONS_USER:
308
 *                The username for authentication (const char *).\n
309
 *                \n
310
 *                If the value is NULL, the username is set to the
311
 *                default username.
312
 *
313
 *              - SSH_OPTIONS_SSH_DIR:
314
 *                Set the ssh directory (const char *,format string).\n
315
 *                \n
316
 *                If the value is NULL, the directory is set to the
317
 *                default ssh directory.\n
318
 *                \n
319
 *                The ssh directory is used for files like known_hosts
320
 *                and identity (private and public key). It may include
321
 *                "%s" which will be replaced by the user home
322
 *                directory.
323
 *
324
 *              - SSH_OPTIONS_KNOWNHOSTS:
325
 *                Set the known hosts file name (const char *,format string).\n
326
 *                \n
327
 *                If the value is NULL, the directory is set to the
328
 *                default known hosts file, normally
329
 *                ~/.ssh/known_hosts.\n
330
 *                \n
331
 *                The known hosts file is used to certify remote hosts
332
 *                are genuine. It may include "%d" which will be
333
 *                replaced by the user home directory.
334
 *
335
 *              - SSH_OPTIONS_GLOBAL_KNOWNHOSTS:
336
 *                Set the global known hosts file name (const char *,format string).\n
337
 *                \n
338
 *                If the value is NULL, the directory is set to the
339
 *                default global known hosts file, normally
340
 *                /etc/ssh/ssh_known_hosts.\n
341
 *                \n
342
 *                The known hosts file is used to certify remote hosts
343
 *                are genuine.
344
 *
345
 *              - SSH_OPTIONS_ADD_IDENTITY (or SSH_OPTIONS_IDENTITY):
346
 *                Add a new identity file (const char *, format string) to
347
 *                the identity list.\n
348
 *                \n
349
 *                By default id_rsa, id_ecdsa and id_ed25519 files are used.\n
350
 *                \n
351
 *                The identity used to authenticate with public key will be
352
 *                prepended to the list.
353
 *                It may include "%s" which will be replaced by the
354
 *                user home directory.
355
 *
356
 *              - SSH_OPTIONS_TIMEOUT:
357
 *                Set a timeout for the connection in seconds (long).
358
 *
359
 *              - SSH_OPTIONS_TIMEOUT_USEC:
360
 *                Set a timeout for the connection in micro seconds
361
 *                        (long).
362
 *
363
 *              - SSH_OPTIONS_SSH1:
364
 *                Deprecated
365
 *
366
 *              - SSH_OPTIONS_SSH2:
367
 *                Unused
368
 *
369
 *              - SSH_OPTIONS_LOG_VERBOSITY:
370
 *                Set the session logging verbosity (int).\n
371
 *                \n
372
 *                The verbosity of the messages. Every log smaller or
373
 *                equal to verbosity will be shown.
374
 *                - SSH_LOG_NOLOG: No logging
375
 *                - SSH_LOG_WARNING: Only warnings
376
 *                - SSH_LOG_PROTOCOL: High level protocol information
377
 *                - SSH_LOG_PACKET: Lower level protocol information, packet level
378
 *                - SSH_LOG_FUNCTIONS: Every function path
379
 *                The default is SSH_LOG_NOLOG.
380
 *
381
 *              - SSH_OPTIONS_LOG_VERBOSITY_STR:
382
 *                Set the session logging verbosity via a
383
 *                string that will be converted to a numerical
384
 *                value (e.g. "3") and interpreted according
385
 *                to the values of
386
 *                SSH_OPTIONS_LOG_VERBOSITY above (const
387
 *                char *).
388
 *
389
 *              - SSH_OPTIONS_CIPHERS_C_S:
390
 *                Set the symmetric cipher client to server (const char *,
391
 *                comma-separated list). The list can be prepended by +,-,^
392
 *                which can append, remove or move to the beginning
393
 *                (prioritizing) of the default list respectively. Giving an
394
 *                empty list after + and ^ will cause error.
395
 *
396
 *              - SSH_OPTIONS_CIPHERS_S_C:
397
 *                Set the symmetric cipher server to client (const char *,
398
 *                comma-separated list). The list can be prepended by +,-,^
399
 *                which can append, remove or move to the beginning
400
 *                (prioritizing) of the default list respectively. Giving an
401
 *                empty list after + and ^ will cause error.
402
 *
403
 *              - SSH_OPTIONS_KEY_EXCHANGE:
404
 *                Set the key exchange method to be used (const char *,
405
 *                comma-separated list). ex:
406
 *                "ecdh-sha2-nistp256,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
407
 *                The list can be prepended by +,-,^ which will append,
408
 *                remove or move to the beginning (prioritizing) of the
409
 *                default list respectively. Giving an empty list
410
 *                after + and ^ will cause error.
411
 *
412
 *              - SSH_OPTIONS_HMAC_C_S:
413
 *                Set the Message Authentication Code algorithm client to server
414
 *                (const char *, comma-separated list). The list can be
415
 *                prepended by +,-,^ which will append, remove or move to
416
 *                the beginning (prioritizing) of the default list
417
 *                respectively. Giving an empty list after + and ^ will
418
 *                cause error.
419
 *
420
 *              - SSH_OPTIONS_HMAC_S_C:
421
 *                Set the Message Authentication Code algorithm server to client
422
 *                (const char *, comma-separated list). The list can be
423
 *                prepended by +,-,^ which will append, remove or move to
424
 *                the beginning (prioritizing) of the default list
425
 *                respectively. Giving an empty list after + and ^ will
426
 *                cause error.
427
 *
428
 *              - SSH_OPTIONS_HOSTKEYS:
429
 *                Set the preferred server host key types (const char *,
430
 *                comma-separated list). ex:
431
 *                "ssh-rsa,ecdh-sha2-nistp256". The list can be
432
 *                prepended by +,-,^ which will append, remove or move to
433
 *                the beginning (prioritizing) of the default list
434
 *                respectively. Giving an empty list after + and ^ will
435
 *                cause error.
436
 *
437
 *              - SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES:
438
 *                Set the preferred public key algorithms to be used for
439
 *                authentication (const char *, comma-separated list). ex:
440
 *                "ssh-rsa,rsa-sha2-256,ecdh-sha2-nistp256"
441
 *                The list can be prepended by +,-,^ which will append,
442
 *                remove or move to the beginning (prioritizing) of the
443
 *                default list respectively. Giving an empty list
444
 *                after + and ^ will cause error.
445
 *
446
 *              - SSH_OPTIONS_COMPRESSION_C_S:
447
 *                Set the compression to use for client to server
448
 *                communication (const char *, "yes", "no" or a specific
449
 *                algorithm name if needed ("zlib","zlib@openssh.com","none").
450
 *
451
 *              - SSH_OPTIONS_COMPRESSION_S_C:
452
 *                Set the compression to use for server to client
453
 *                communication (const char *, "yes", "no" or a specific
454
 *                algorithm name if needed ("zlib","zlib@openssh.com","none").
455
 *
456
 *              - SSH_OPTIONS_COMPRESSION:
457
 *                Set the compression to use for both directions
458
 *                communication (const char *, "yes", "no" or a specific
459
 *                algorithm name if needed ("zlib","zlib@openssh.com","none").
460
 *
461
 *              - SSH_OPTIONS_COMPRESSION_LEVEL:
462
 *                Set the compression level to use for zlib functions. (int,
463
 *                value from 1 to 9, 9 being the most efficient but slower).
464
 *
465
 *              - SSH_OPTIONS_STRICTHOSTKEYCHECK:
466
 *                Set the parameter StrictHostKeyChecking to avoid
467
 *                asking about a fingerprint (int, 0 = false).
468
 *
469
 *              - SSH_OPTIONS_PROXYCOMMAND:
470
 *                Set the command to be executed in order to connect to
471
 *                server (const char *).
472
 *
473
 *              - SSH_OPTIONS_GSSAPI_SERVER_IDENTITY
474
 *                Set it to specify the GSSAPI server identity that libssh
475
 *                should expect when connecting to the server (const char *).
476
 *
477
 *              - SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY
478
 *                Set it to specify the GSSAPI client identity that libssh
479
 *                should expect when connecting to the server (const char *).
480
 *
481
 *              - SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS
482
 *                Set it to specify that GSSAPI should delegate credentials
483
 *                to the server (int, 0 = false).
484
 *
485
 *              - SSH_OPTIONS_PASSWORD_AUTH
486
 *                Set it if password authentication should be used
487
 *                in ssh_userauth_auto_pubkey(). (int, 0=false).
488
 *                Currently without effect (ssh_userauth_auto_pubkey doesn't use
489
 *                password authentication).
490
 *
491
 *              - SSH_OPTIONS_PUBKEY_AUTH
492
 *                Set it if pubkey authentication should be used
493
 *                in ssh_userauth_auto_pubkey(). (int, 0=false).
494
 *
495
 *              - SSH_OPTIONS_KBDINT_AUTH
496
 *                Set it if keyboard-interactive authentication should be used
497
 *                in ssh_userauth_auto_pubkey(). (int, 0=false).
498
 *                Currently without effect (ssh_userauth_auto_pubkey doesn't use
499
 *                keyboard-interactive authentication).
500
 *
501
 *              - SSH_OPTIONS_GSSAPI_AUTH
502
 *                Set it if gssapi authentication should be used
503
 *                in ssh_userauth_auto_pubkey(). (int, 0=false).
504
 *                Currently without effect (ssh_userauth_auto_pubkey doesn't use
505
 *                gssapi authentication).
506
 *
507
 *              - SSH_OPTIONS_NODELAY
508
 *                Set it to disable Nagle's Algorithm (TCP_NODELAY) on the
509
 *                session socket. (int, 0=false)
510
 *
511
 *              - SSH_OPTIONS_PROCESS_CONFIG
512
 *                Set it to false to disable automatic processing of per-user
513
 *                and system-wide OpenSSH configuration files. LibSSH
514
 *                automatically uses these configuration files unless
515
 *                you provide it with this option or with different file (bool).
516
 *
517
 *              - SSH_OPTIONS_REKEY_DATA
518
 *                Set the data limit that can be transferred with a single
519
 *                key in bytes. RFC 4253 Section 9 recommends 1GB of data, while
520
 *                RFC 4344 provides more specific restrictions, that are applied
521
 *                automatically. When specified, the lower value will be used.
522
 *                (uint64_t, 0=default)
523
 *
524
 *              - SSH_OPTIONS_REKEY_TIME
525
 *                Set the time limit for a session before initializing a rekey
526
 *                in seconds. RFC 4253 Section 9 recommends one hour.
527
 *                (uint32_t, 0=off)
528
 *
529
 *              - SSH_OPTIONS_RSA_MIN_SIZE
530
 *                Set the minimum RSA key size in bits to be accepted by the
531
 *                client for both authentication and hostkey verification.
532
 *                The values under 768 bits are not accepted even with this
533
 *                configuration option as they are considered completely broken.
534
 *                Setting 0 will revert the value to defaults.
535
 *                Default is 1024 bits or 2048 bits in FIPS mode.
536
 *                (int *)
537
538
 *              - SSH_OPTIONS_IDENTITY_AGENT
539
 *                Set the path to the SSH agent socket. If unset, the
540
 *                SSH_AUTH_SOCK environment is consulted.
541
 *                (const char *)
542
543
 *              - SSH_OPTIONS_IDENTITIES_ONLY
544
 *                Use only keys specified in the SSH config, even if agent
545
 *                offers more.
546
 *                (bool)
547
 *
548
 *              - SSH_OPTIONS_CONTROL_MASTER
549
 *                Set the option to enable the sharing of multiple sessions over a
550
 *                single network connection using connection multiplexing.
551
 *
552
 *                The possible options are among the following:
553
 *                 - SSH_CONTROL_MASTER_AUTO: enable connection sharing if possible
554
 *                 - SSH_CONTROL_MASTER_YES: enable connection sharing unconditionally
555
 *                 - SSH_CONTROL_MASTER_ASK: ask for confirmation if connection sharing is to be enabled
556
 *                 - SSH_CONTROL_MASTER_AUTOASK: enable connection sharing if possible,
557
 *                                               but ask for confirmation
558
 *                 - SSH_CONTROL_MASTER_NO: disable connection sharing unconditionally
559
 *
560
 *                The default is SSH_CONTROL_MASTER_NO.
561
 *
562
 *              - SSH_OPTIONS_CONTROL_PATH
563
 *                Set the path to the control socket used for connection sharing.
564
 *                Set to "none" to disable connection sharing.
565
 *                (const char *)
566
 *
567
 *
568
 * @param  value The value to set. This is a generic pointer and the
569
 *               datatype which is used should be set according to the
570
 *               type set.
571
 *
572
 * @return       0 on success, < 0 on error.
573
 */
574
int ssh_options_set(ssh_session session, enum ssh_options_e type,
575
                    const void *value)
576
32.5k
{
577
32.5k
    const char *v;
578
32.5k
    char *p, *q;
579
32.5k
    long int i;
580
32.5k
    unsigned int u;
581
32.5k
    int rc;
582
32.5k
    char **wanted_methods = session->opts.wanted_methods;
583
584
32.5k
    if (session == NULL) {
585
0
        return -1;
586
0
    }
587
588
32.5k
    switch (type) {
589
3.25k
        case SSH_OPTIONS_HOST:
590
3.25k
            v = value;
591
3.25k
            if (v == NULL || v[0] == '\0') {
592
0
                ssh_set_error_invalid(session);
593
0
                return -1;
594
3.25k
            } else {
595
3.25k
                q = strdup(value);
596
3.25k
                if (q == NULL) {
597
0
                    ssh_set_error_oom(session);
598
0
                    return -1;
599
0
                }
600
3.25k
                p = strrchr(q, '@');
601
602
3.25k
                SAFE_FREE(session->opts.host);
603
604
3.25k
                if (p) {
605
0
                    *p = '\0';
606
0
                    session->opts.host = strdup(p + 1);
607
0
                    if (session->opts.host == NULL) {
608
0
                        SAFE_FREE(q);
609
0
                        ssh_set_error_oom(session);
610
0
                        return -1;
611
0
                    }
612
613
0
                    SAFE_FREE(session->opts.username);
614
0
                    session->opts.username = strdup(q);
615
0
                    SAFE_FREE(q);
616
0
                    if (session->opts.username == NULL) {
617
0
                        ssh_set_error_oom(session);
618
0
                        return -1;
619
0
                    }
620
3.25k
                } else {
621
3.25k
                    session->opts.host = q;
622
3.25k
                }
623
3.25k
            }
624
3.25k
            break;
625
3.25k
        case SSH_OPTIONS_PORT:
626
0
            if (value == NULL) {
627
0
                ssh_set_error_invalid(session);
628
0
                return -1;
629
0
            } else {
630
0
                int *x = (int *) value;
631
0
                if (*x <= 0) {
632
0
                    ssh_set_error_invalid(session);
633
0
                    return -1;
634
0
                }
635
636
0
                session->opts.port = *x & 0xffffU;
637
0
            }
638
0
            break;
639
0
        case SSH_OPTIONS_PORT_STR:
640
0
            v = value;
641
0
            if (v == NULL || v[0] == '\0') {
642
0
                ssh_set_error_invalid(session);
643
0
                return -1;
644
0
            } else {
645
0
                q = strdup(v);
646
0
                if (q == NULL) {
647
0
                    ssh_set_error_oom(session);
648
0
                    return -1;
649
0
                }
650
0
                i = strtol(q, &p, 10);
651
0
                if (q == p) {
652
0
                    SSH_LOG(SSH_LOG_DEBUG, "No port number was parsed");
653
0
                    SAFE_FREE(q);
654
0
                    return -1;
655
0
                }
656
0
                SAFE_FREE(q);
657
0
                if (i <= 0) {
658
0
                    ssh_set_error_invalid(session);
659
0
                    return -1;
660
0
                }
661
662
0
                session->opts.port = i & 0xffffU;
663
0
            }
664
0
            break;
665
3.25k
        case SSH_OPTIONS_FD:
666
3.25k
            if (value == NULL) {
667
0
                session->opts.fd = SSH_INVALID_SOCKET;
668
0
                ssh_set_error_invalid(session);
669
0
                return -1;
670
3.25k
            } else {
671
3.25k
                socket_t *x = (socket_t *) value;
672
3.25k
                if (*x < 0) {
673
0
                    session->opts.fd = SSH_INVALID_SOCKET;
674
0
                    ssh_set_error_invalid(session);
675
0
                    return -1;
676
0
                }
677
678
3.25k
                session->opts.fd = *x & 0xffff;
679
3.25k
            }
680
3.25k
            break;
681
3.25k
        case SSH_OPTIONS_BINDADDR:
682
0
            v = value;
683
0
            if (v == NULL || v[0] == '\0') {
684
0
                ssh_set_error_invalid(session);
685
0
                return -1;
686
0
            }
687
688
0
            q = strdup(v);
689
0
            if (q == NULL) {
690
0
                return -1;
691
0
            }
692
0
            SAFE_FREE(session->opts.bindaddr);
693
0
            session->opts.bindaddr = q;
694
0
            break;
695
3.25k
        case SSH_OPTIONS_USER:
696
3.25k
            v = value;
697
3.25k
            SAFE_FREE(session->opts.username);
698
3.25k
            if (v == NULL) {
699
0
                q = ssh_get_local_username();
700
0
                if (q == NULL) {
701
0
                    ssh_set_error_oom(session);
702
0
                    return -1;
703
0
                }
704
0
                session->opts.username = q;
705
3.25k
            } else if (v[0] == '\0') {
706
0
                ssh_set_error_invalid(session);
707
0
                return -1;
708
3.25k
            } else { /* username provided */
709
3.25k
                session->opts.username = strdup(value);
710
3.25k
                if (session->opts.username == NULL) {
711
0
                    ssh_set_error_oom(session);
712
0
                    return -1;
713
0
                }
714
3.25k
            }
715
3.25k
            break;
716
3.25k
        case SSH_OPTIONS_SSH_DIR:
717
3.25k
            v = value;
718
3.25k
            SAFE_FREE(session->opts.sshdir);
719
3.25k
            if (v == NULL) {
720
3.25k
                session->opts.sshdir = ssh_path_expand_tilde("~/.ssh");
721
3.25k
                if (session->opts.sshdir == NULL) {
722
0
                    return -1;
723
0
                }
724
3.25k
            } else if (v[0] == '\0') {
725
0
                ssh_set_error_invalid(session);
726
0
                return -1;
727
0
            } else {
728
0
                session->opts.sshdir = ssh_path_expand_tilde(v);
729
0
                if (session->opts.sshdir == NULL) {
730
0
                    ssh_set_error_oom(session);
731
0
                    return -1;
732
0
                }
733
0
            }
734
3.25k
            break;
735
3.25k
        case SSH_OPTIONS_IDENTITY:
736
0
        case SSH_OPTIONS_ADD_IDENTITY:
737
0
            v = value;
738
0
            if (v == NULL || v[0] == '\0') {
739
0
                ssh_set_error_invalid(session);
740
0
                return -1;
741
0
            }
742
0
            q = strdup(v);
743
0
            if (q == NULL) {
744
0
                return -1;
745
0
            }
746
0
            if (session->opts.exp_flags & SSH_OPT_EXP_FLAG_IDENTITY) {
747
0
                rc = ssh_list_append(session->opts.identity_non_exp, q);
748
0
            } else {
749
0
                rc = ssh_list_prepend(session->opts.identity_non_exp, q);
750
0
            }
751
0
            if (rc < 0) {
752
0
                free(q);
753
0
                return -1;
754
0
            }
755
0
            break;
756
0
        case SSH_OPTIONS_KNOWNHOSTS:
757
0
            v = value;
758
0
            SAFE_FREE(session->opts.knownhosts);
759
0
            if (v == NULL) {
760
                /* The default value will be set by the ssh_options_apply() */
761
0
            } else if (v[0] == '\0') {
762
0
                ssh_set_error_invalid(session);
763
0
                return -1;
764
0
            } else {
765
0
                session->opts.knownhosts = strdup(v);
766
0
                if (session->opts.knownhosts == NULL) {
767
0
                    ssh_set_error_oom(session);
768
0
                    return -1;
769
0
                }
770
0
                session->opts.exp_flags &= ~SSH_OPT_EXP_FLAG_KNOWNHOSTS;
771
0
            }
772
0
            break;
773
0
        case SSH_OPTIONS_GLOBAL_KNOWNHOSTS:
774
0
            v = value;
775
0
            SAFE_FREE(session->opts.global_knownhosts);
776
0
            if (v == NULL) {
777
0
                session->opts.global_knownhosts =
778
0
                    strdup("/etc/ssh/ssh_known_hosts");
779
0
                if (session->opts.global_knownhosts == NULL) {
780
0
                    ssh_set_error_oom(session);
781
0
                    return -1;
782
0
                }
783
0
            } else if (v[0] == '\0') {
784
0
                ssh_set_error_invalid(session);
785
0
                return -1;
786
0
            } else {
787
0
                session->opts.global_knownhosts = strdup(v);
788
0
                if (session->opts.global_knownhosts == NULL) {
789
0
                    ssh_set_error_oom(session);
790
0
                    return -1;
791
0
                }
792
0
                session->opts.exp_flags &= ~SSH_OPT_EXP_FLAG_GLOBAL_KNOWNHOSTS;
793
0
            }
794
0
            break;
795
3.25k
        case SSH_OPTIONS_TIMEOUT:
796
3.25k
            if (value == NULL) {
797
0
                ssh_set_error_invalid(session);
798
0
                return -1;
799
3.25k
            } else {
800
3.25k
                long *x = (long *) value;
801
3.25k
                if (*x < 0) {
802
0
                    ssh_set_error_invalid(session);
803
0
                    return -1;
804
0
                }
805
806
3.25k
                session->opts.timeout = *x & 0xffffffffU;
807
3.25k
            }
808
3.25k
            break;
809
3.25k
        case SSH_OPTIONS_TIMEOUT_USEC:
810
0
            if (value == NULL) {
811
0
                ssh_set_error_invalid(session);
812
0
                return -1;
813
0
            } else {
814
0
                long *x = (long *) value;
815
0
                if (*x < 0) {
816
0
                    ssh_set_error_invalid(session);
817
0
                    return -1;
818
0
                }
819
820
0
                session->opts.timeout_usec = *x & 0xffffffffU;
821
0
            }
822
0
            break;
823
0
        case SSH_OPTIONS_SSH1:
824
0
            break;
825
0
        case SSH_OPTIONS_SSH2:
826
0
            break;
827
0
        case SSH_OPTIONS_LOG_VERBOSITY:
828
0
            if (value == NULL) {
829
0
                ssh_set_error_invalid(session);
830
0
                return -1;
831
0
            } else {
832
0
                int *x = (int *) value;
833
0
                if (*x < 0) {
834
0
                    ssh_set_error_invalid(session);
835
0
                    return -1;
836
0
                }
837
838
0
                session->common.log_verbosity = *x & 0xffffU;
839
0
                ssh_set_log_level(*x & 0xffffU);
840
0
            }
841
0
            break;
842
0
        case SSH_OPTIONS_LOG_VERBOSITY_STR:
843
0
            v = value;
844
0
            if (v == NULL || v[0] == '\0') {
845
0
                session->common.log_verbosity = 0;
846
0
                ssh_set_error_invalid(session);
847
0
                return -1;
848
0
            } else {
849
0
                q = strdup(v);
850
0
                if (q == NULL) {
851
0
                    ssh_set_error_oom(session);
852
0
                    return -1;
853
0
                }
854
0
                i = strtol(q, &p, 10);
855
0
                if (q == p) {
856
0
                    SSH_LOG(SSH_LOG_DEBUG, "No log verbositiy was parsed");
857
0
                    SAFE_FREE(q);
858
0
                    return -1;
859
0
                }
860
0
                SAFE_FREE(q);
861
0
                if (i < 0) {
862
0
                    ssh_set_error_invalid(session);
863
0
                    return -1;
864
0
                }
865
866
0
                session->common.log_verbosity = i & 0xffffU;
867
0
                ssh_set_log_level(i & 0xffffU);
868
0
            }
869
0
            break;
870
3.25k
        case SSH_OPTIONS_CIPHERS_C_S:
871
3.25k
            v = value;
872
3.25k
            if (v == NULL || v[0] == '\0') {
873
0
                ssh_set_error_invalid(session);
874
0
                return -1;
875
3.25k
            } else {
876
3.25k
                rc = ssh_options_set_algo(session,
877
3.25k
                                          SSH_CRYPT_C_S,
878
3.25k
                                          v,
879
3.25k
                                          &wanted_methods[SSH_CRYPT_C_S]);
880
3.25k
                if (rc < 0)
881
0
                    return -1;
882
3.25k
            }
883
3.25k
            break;
884
3.25k
        case SSH_OPTIONS_CIPHERS_S_C:
885
3.25k
            v = value;
886
3.25k
            if (v == NULL || v[0] == '\0') {
887
0
                ssh_set_error_invalid(session);
888
0
                return -1;
889
3.25k
            } else {
890
3.25k
                rc = ssh_options_set_algo(session,
891
3.25k
                                          SSH_CRYPT_S_C,
892
3.25k
                                          v,
893
3.25k
                                          &wanted_methods[SSH_CRYPT_S_C]);
894
3.25k
                if (rc < 0)
895
0
                    return -1;
896
3.25k
            }
897
3.25k
            break;
898
3.25k
        case SSH_OPTIONS_KEY_EXCHANGE:
899
0
            v = value;
900
0
            if (v == NULL || v[0] == '\0') {
901
0
                ssh_set_error_invalid(session);
902
0
                return -1;
903
0
            } else {
904
0
                rc = ssh_options_set_algo(session,
905
0
                                          SSH_KEX,
906
0
                                          v,
907
0
                                          &wanted_methods[SSH_KEX]);
908
0
                if (rc < 0)
909
0
                    return -1;
910
0
            }
911
0
            break;
912
0
        case SSH_OPTIONS_HOSTKEYS:
913
0
            v = value;
914
0
            if (v == NULL || v[0] == '\0') {
915
0
                ssh_set_error_invalid(session);
916
0
                return -1;
917
0
            } else {
918
0
                rc = ssh_options_set_algo(session,
919
0
                                          SSH_HOSTKEYS,
920
0
                                          v,
921
0
                                          &wanted_methods[SSH_HOSTKEYS]);
922
0
                if (rc < 0)
923
0
                    return -1;
924
0
            }
925
0
            break;
926
0
        case SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES:
927
0
            v = value;
928
0
            if (v == NULL || v[0] == '\0') {
929
0
                ssh_set_error_invalid(session);
930
0
                return -1;
931
0
            } else {
932
0
                rc = ssh_options_set_algo(session,
933
0
                                          SSH_HOSTKEYS,
934
0
                                          v,
935
0
                                          &session->opts.pubkey_accepted_types);
936
0
                if (rc < 0)
937
0
                    return -1;
938
0
            }
939
0
            break;
940
3.25k
        case SSH_OPTIONS_HMAC_C_S:
941
3.25k
            v = value;
942
3.25k
            if (v == NULL || v[0] == '\0') {
943
0
                ssh_set_error_invalid(session);
944
0
                return -1;
945
3.25k
            } else {
946
3.25k
                rc = ssh_options_set_algo(session,
947
3.25k
                                          SSH_MAC_C_S,
948
3.25k
                                          v,
949
3.25k
                                          &wanted_methods[SSH_MAC_C_S]);
950
3.25k
                if (rc < 0)
951
0
                    return -1;
952
3.25k
            }
953
3.25k
            break;
954
3.25k
         case SSH_OPTIONS_HMAC_S_C:
955
3.25k
            v = value;
956
3.25k
            if (v == NULL || v[0] == '\0') {
957
0
                ssh_set_error_invalid(session);
958
0
                return -1;
959
3.25k
            } else {
960
3.25k
                rc = ssh_options_set_algo(session,
961
3.25k
                                          SSH_MAC_S_C,
962
3.25k
                                          v,
963
3.25k
                                          &wanted_methods[SSH_MAC_S_C]);
964
3.25k
                if (rc < 0)
965
0
                    return -1;
966
3.25k
            }
967
3.25k
            break;
968
3.25k
        case SSH_OPTIONS_COMPRESSION_C_S:
969
0
            v = value;
970
0
            if (v == NULL || v[0] == '\0') {
971
0
                ssh_set_error_invalid(session);
972
0
                return -1;
973
0
            } else {
974
0
                const char *tmp = v;
975
0
                if (strcasecmp(value, "yes") == 0){
976
0
                    tmp = "zlib@openssh.com,none";
977
0
                } else if (strcasecmp(value, "no") == 0){
978
0
                    tmp = "none,zlib@openssh.com";
979
0
                }
980
0
                rc = ssh_options_set_algo(session,
981
0
                                          SSH_COMP_C_S,
982
0
                                          tmp,
983
0
                                          &wanted_methods[SSH_COMP_C_S]);
984
0
                if (rc < 0)
985
0
                    return -1;
986
0
            }
987
0
            break;
988
0
        case SSH_OPTIONS_COMPRESSION_S_C:
989
0
            v = value;
990
0
            if (v == NULL || v[0] == '\0') {
991
0
                ssh_set_error_invalid(session);
992
0
                return -1;
993
0
            } else {
994
0
                const char *tmp = v;
995
0
                if (strcasecmp(value, "yes") == 0){
996
0
                    tmp = "zlib@openssh.com,none";
997
0
                } else if (strcasecmp(value, "no") == 0){
998
0
                    tmp = "none,zlib@openssh.com";
999
0
                }
1000
1001
0
                rc = ssh_options_set_algo(session,
1002
0
                                          SSH_COMP_S_C,
1003
0
                                          tmp,
1004
0
                                          &wanted_methods[SSH_COMP_S_C]);
1005
0
                if (rc < 0)
1006
0
                    return -1;
1007
0
            }
1008
0
            break;
1009
0
        case SSH_OPTIONS_COMPRESSION:
1010
0
            v = value;
1011
0
            if (v == NULL || v[0] == '\0') {
1012
0
                ssh_set_error_invalid(session);
1013
0
                return -1;
1014
0
            }
1015
0
            if(ssh_options_set(session,SSH_OPTIONS_COMPRESSION_C_S, v) < 0)
1016
0
                return -1;
1017
0
            if(ssh_options_set(session,SSH_OPTIONS_COMPRESSION_S_C, v) < 0)
1018
0
                return -1;
1019
0
            break;
1020
0
        case SSH_OPTIONS_COMPRESSION_LEVEL:
1021
0
            if (value == NULL) {
1022
0
                ssh_set_error_invalid(session);
1023
0
                return -1;
1024
0
            } else {
1025
0
                int *x = (int *)value;
1026
0
                if (*x < 1 || *x > 9) {
1027
0
                    ssh_set_error_invalid(session);
1028
0
                    return -1;
1029
0
                }
1030
0
                session->opts.compressionlevel = *x & 0xff;
1031
0
            }
1032
0
            break;
1033
0
        case SSH_OPTIONS_STRICTHOSTKEYCHECK:
1034
0
            if (value == NULL) {
1035
0
                ssh_set_error_invalid(session);
1036
0
                return -1;
1037
0
            } else {
1038
0
                int *x = (int *) value;
1039
1040
0
                session->opts.StrictHostKeyChecking = (*x & 0xff) > 0 ? 1 : 0;
1041
0
            }
1042
0
            break;
1043
0
        case SSH_OPTIONS_PROXYCOMMAND:
1044
0
            v = value;
1045
0
            if (v == NULL || v[0] == '\0') {
1046
0
                ssh_set_error_invalid(session);
1047
0
                return -1;
1048
0
            } else {
1049
0
                SAFE_FREE(session->opts.ProxyCommand);
1050
                /* Setting the command to 'none' disables this option. */
1051
0
                rc = strcasecmp(v, "none");
1052
0
                if (rc != 0) {
1053
0
                    q = strdup(v);
1054
0
                    if (q == NULL) {
1055
0
                        return -1;
1056
0
                    }
1057
0
                    session->opts.ProxyCommand = q;
1058
0
                    session->opts.exp_flags &= ~SSH_OPT_EXP_FLAG_PROXYCOMMAND;
1059
0
                }
1060
0
            }
1061
0
            break;
1062
0
        case SSH_OPTIONS_GSSAPI_SERVER_IDENTITY:
1063
0
            v = value;
1064
0
            if (v == NULL || v[0] == '\0') {
1065
0
                ssh_set_error_invalid(session);
1066
0
                return -1;
1067
0
            } else {
1068
0
                SAFE_FREE(session->opts.gss_server_identity);
1069
0
                session->opts.gss_server_identity = strdup(v);
1070
0
                if (session->opts.gss_server_identity == NULL) {
1071
0
                    ssh_set_error_oom(session);
1072
0
                    return -1;
1073
0
                }
1074
0
            }
1075
0
            break;
1076
0
        case SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY:
1077
0
            v = value;
1078
0
            if (v == NULL || v[0] == '\0') {
1079
0
                ssh_set_error_invalid(session);
1080
0
                return -1;
1081
0
            } else {
1082
0
                SAFE_FREE(session->opts.gss_client_identity);
1083
0
                session->opts.gss_client_identity = strdup(v);
1084
0
                if (session->opts.gss_client_identity == NULL) {
1085
0
                    ssh_set_error_oom(session);
1086
0
                    return -1;
1087
0
                }
1088
0
            }
1089
0
            break;
1090
0
        case SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS:
1091
0
            if (value == NULL) {
1092
0
                ssh_set_error_invalid(session);
1093
0
                return -1;
1094
0
            } else {
1095
0
                int x = *(int *)value;
1096
1097
0
                session->opts.gss_delegate_creds = (x & 0xff);
1098
0
            }
1099
0
            break;
1100
0
        case SSH_OPTIONS_PASSWORD_AUTH:
1101
0
        case SSH_OPTIONS_PUBKEY_AUTH:
1102
0
        case SSH_OPTIONS_KBDINT_AUTH:
1103
0
        case SSH_OPTIONS_GSSAPI_AUTH:
1104
0
            if (value == NULL) {
1105
0
                ssh_set_error_invalid(session);
1106
0
                return -1;
1107
0
            } else {
1108
0
                int x = *(int *)value;
1109
0
                u = type == SSH_OPTIONS_PASSWORD_AUTH ?
1110
0
                    SSH_OPT_FLAG_PASSWORD_AUTH:
1111
0
                    type == SSH_OPTIONS_PUBKEY_AUTH ?
1112
0
                        SSH_OPT_FLAG_PUBKEY_AUTH:
1113
0
                        type == SSH_OPTIONS_KBDINT_AUTH ?
1114
0
                            SSH_OPT_FLAG_KBDINT_AUTH:
1115
0
                            SSH_OPT_FLAG_GSSAPI_AUTH;
1116
0
                if (x != 0){
1117
0
                    session->opts.flags |= u;
1118
0
                } else {
1119
0
                    session->opts.flags &= ~u;
1120
0
                }
1121
0
            }
1122
0
            break;
1123
0
        case SSH_OPTIONS_NODELAY:
1124
0
            if (value == NULL) {
1125
0
                ssh_set_error_invalid(session);
1126
0
                return -1;
1127
0
            } else {
1128
0
                int *x = (int *) value;
1129
0
                session->opts.nodelay = (*x & 0xff) > 0 ? 1 : 0;
1130
0
            }
1131
0
            break;
1132
3.25k
        case SSH_OPTIONS_PROCESS_CONFIG:
1133
3.25k
            if (value == NULL) {
1134
0
                ssh_set_error_invalid(session);
1135
0
                return -1;
1136
3.25k
            } else {
1137
3.25k
                bool *x = (bool *)value;
1138
3.25k
                session->opts.config_processed = !(*x);
1139
3.25k
            }
1140
3.25k
            break;
1141
3.25k
        case SSH_OPTIONS_REKEY_DATA:
1142
0
            if (value == NULL) {
1143
0
                ssh_set_error_invalid(session);
1144
0
                return -1;
1145
0
            } else {
1146
0
                uint64_t *x = (uint64_t *)value;
1147
0
                session->opts.rekey_data = *x;
1148
0
            }
1149
0
            break;
1150
0
        case SSH_OPTIONS_REKEY_TIME:
1151
0
            if (value == NULL) {
1152
0
                ssh_set_error_invalid(session);
1153
0
                return -1;
1154
0
            } else {
1155
0
                uint32_t *x = (uint32_t *)value;
1156
0
                if ((*x * 1000) < *x) {
1157
0
                    ssh_set_error(session, SSH_REQUEST_DENIED,
1158
0
                                  "The provided value (%" PRIu32 ") for rekey"
1159
0
                                  " time is too large", *x);
1160
0
                    return -1;
1161
0
                }
1162
0
                session->opts.rekey_time = (*x) * 1000;
1163
0
            }
1164
0
            break;
1165
0
        case SSH_OPTIONS_RSA_MIN_SIZE:
1166
0
            if (value == NULL) {
1167
0
                ssh_set_error_invalid(session);
1168
0
                return -1;
1169
0
            } else {
1170
0
                int *x = (int *)value;
1171
0
                if (*x > 0 && *x < 768) {
1172
0
                    ssh_set_error(session, SSH_REQUEST_DENIED,
1173
0
                                  "The provided value (%u) for minimal RSA key "
1174
0
                                  "size is too small. Use at least 768 bits.", *x);
1175
0
                    return -1;
1176
0
                }
1177
0
                session->opts.rsa_min_size = *x;
1178
0
            }
1179
0
            break;
1180
0
        case SSH_OPTIONS_IDENTITY_AGENT:
1181
0
            v = value;
1182
0
            SAFE_FREE(session->opts.agent_socket);
1183
0
            if (v == NULL) {
1184
                /* The default value will be set by the ssh_options_apply() */
1185
0
            } else if (v[0] == '\0') {
1186
0
                ssh_set_error_invalid(session);
1187
0
                return -1;
1188
0
            } else {
1189
0
                session->opts.agent_socket = ssh_path_expand_tilde(v);
1190
0
                if (session->opts.agent_socket == NULL) {
1191
0
                    ssh_set_error_oom(session);
1192
0
                    return -1;
1193
0
                }
1194
0
            }
1195
0
            break;
1196
0
        case SSH_OPTIONS_IDENTITIES_ONLY:
1197
0
            if (value == NULL) {
1198
0
                ssh_set_error_invalid(session);
1199
0
                return -1;
1200
0
            } else {
1201
0
                bool *x = (bool *)value;
1202
0
                session->opts.identities_only = *x;
1203
0
            }
1204
0
            break;
1205
0
        case SSH_OPTIONS_CONTROL_MASTER:
1206
0
            if (value == NULL) {
1207
0
                ssh_set_error_invalid(session);
1208
0
                return -1;
1209
0
            } else {
1210
0
                int *x = (int *) value;
1211
0
                if (*x < SSH_CONTROL_MASTER_NO || *x > SSH_CONTROL_MASTER_AUTOASK) {
1212
0
                    ssh_set_error_invalid(session);
1213
0
                    return -1;
1214
0
                }
1215
0
                session->opts.control_master = *x;
1216
0
            }
1217
0
            break;
1218
0
        case SSH_OPTIONS_CONTROL_PATH:
1219
0
            v = value;
1220
0
            if (v == NULL || v[0] == '\0') {
1221
0
                ssh_set_error_invalid(session);
1222
0
                return -1;
1223
0
            } else {
1224
0
                SAFE_FREE(session->opts.control_path);
1225
0
                rc = strcasecmp(v, "none");
1226
0
                if (rc != 0) {
1227
0
                    session->opts.control_path = ssh_path_expand_tilde(v);
1228
0
                    if (session->opts.control_path == NULL) {
1229
0
                        ssh_set_error_oom(session);
1230
0
                        return -1;
1231
0
                    }
1232
0
                    session->opts.exp_flags &= ~SSH_OPT_EXP_FLAG_CONTROL_PATH;
1233
0
                }
1234
0
            }
1235
0
            break;
1236
0
        default:
1237
0
            ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
1238
0
            return -1;
1239
0
            break;
1240
32.5k
    }
1241
1242
32.5k
    return 0;
1243
32.5k
}
1244
1245
/**
1246
 * @brief This function can get ssh the ssh port. It must only be used on
1247
 *        a valid ssh session. This function is useful when the session
1248
 *        options have been automatically inferred from the environment
1249
 *        or configuration files and one
1250
 *
1251
 * @param  session An allocated SSH session structure.
1252
 *
1253
 * @param  port_target An unsigned integer into which the
1254
 *         port will be set from the ssh session.
1255
 *
1256
 * @return       0 on success, < 0 on error.
1257
 *
1258
 */
1259
0
int ssh_options_get_port(ssh_session session, unsigned int* port_target) {
1260
0
    if (session == NULL) {
1261
0
        return -1;
1262
0
    }
1263
1264
0
    if (session->opts.port == 0) {
1265
0
        *port_target = 22;
1266
0
        return 0;
1267
0
    }
1268
1269
0
    *port_target = session->opts.port;
1270
1271
0
    return 0;
1272
0
}
1273
1274
/**
1275
 * @brief This function can get ssh options, it does not support all options provided for
1276
 *        ssh options set, but mostly those which a user-space program may care about having
1277
 *        trusted the ssh driver to infer these values from underlying configuration files.
1278
 *        It operates only on those SSH_OPTIONS_* which return char*. If you wish to receive
1279
 *        the port then please use ssh_options_get_port() which returns an unsigned int.
1280
 *
1281
 * @param  session An allocated SSH session structure.
1282
 *
1283
 * @param  type The option type to get. This could be one of the
1284
 *              following:
1285
 *
1286
 *              - SSH_OPTIONS_HOST:
1287
 *                The hostname or ip address to connect to (const char *).
1288
 *
1289
 *              - SSH_OPTIONS_USER:
1290
 *                The username for authentication (const char *).\n
1291
 *                \n when not explicitly set this will be inferred from the
1292
 *                ~/.ssh/config file.
1293
 *
1294
 *              - SSH_OPTIONS_IDENTITY:
1295
 *                Get the first identity file name (const char *).\n
1296
 *                \n
1297
 *                By default id_rsa, id_ecdsa and id_ed25519 files are used.
1298
 *
1299
 *              - SSH_OPTIONS_PROXYCOMMAND:
1300
 *                Get the proxycommand necessary to log into the
1301
 *                remote host. When not explicitly set, it will be read
1302
 *                from the ~/.ssh/config file.
1303
 *
1304
 *              - SSH_OPTIONS_GLOBAL_KNOWNHOSTS:
1305
 *                Get the path to the global known_hosts file being used.
1306
 *
1307
 *              - SSH_OPTIONS_KNOWNHOSTS:
1308
 *                Get the path to the known_hosts file being used.
1309
 *
1310
 *              - SSH_OPTIONS_CONTROL_PATH:
1311
 *                Get the path to the control socket being used for connection multiplexing.
1312
 *
1313
 * @param  value The value to get into. As a char**, space will be
1314
 *               allocated by the function for the value, it is
1315
 *               your responsibility to free the memory using
1316
 *               ssh_string_free_char().
1317
 *
1318
 * @return       SSH_OK on success, SSH_ERROR on error.
1319
 */
1320
int ssh_options_get(ssh_session session, enum ssh_options_e type, char** value)
1321
0
{
1322
0
    char* src = NULL;
1323
1324
0
    if (session == NULL) {
1325
0
        return SSH_ERROR;
1326
0
    }
1327
1328
0
    if (value == NULL) {
1329
0
        ssh_set_error_invalid(session);
1330
0
        return SSH_ERROR;
1331
0
    }
1332
1333
0
    switch(type)
1334
0
    {
1335
0
        case SSH_OPTIONS_HOST: {
1336
0
            src = session->opts.host;
1337
0
            break;
1338
0
        }
1339
0
        case SSH_OPTIONS_USER: {
1340
0
            src = session->opts.username;
1341
0
            break;
1342
0
        }
1343
0
        case SSH_OPTIONS_IDENTITY: {
1344
0
            struct ssh_iterator *it;
1345
0
            it = ssh_list_get_iterator(session->opts.identity);
1346
0
            if (it == NULL) {
1347
0
                it = ssh_list_get_iterator(session->opts.identity_non_exp);
1348
0
            }
1349
0
            if (it == NULL) {
1350
0
                return SSH_ERROR;
1351
0
            }
1352
0
            src = ssh_iterator_value(char *, it);
1353
0
            break;
1354
0
        }
1355
0
        case SSH_OPTIONS_PROXYCOMMAND: {
1356
0
            src = session->opts.ProxyCommand;
1357
0
            break;
1358
0
        }
1359
0
        case SSH_OPTIONS_KNOWNHOSTS: {
1360
0
            src = session->opts.knownhosts;
1361
0
            break;
1362
0
        }
1363
0
        case SSH_OPTIONS_GLOBAL_KNOWNHOSTS: {
1364
0
            src = session->opts.global_knownhosts;
1365
0
            break;
1366
0
        }
1367
0
        case SSH_OPTIONS_CONTROL_PATH: {
1368
0
            src = session->opts.control_path;
1369
0
            break;
1370
0
        }
1371
0
        default:
1372
0
            ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
1373
0
            return SSH_ERROR;
1374
0
        break;
1375
0
    }
1376
0
    if (src == NULL) {
1377
0
        return SSH_ERROR;
1378
0
    }
1379
0
    *value = strdup(src);
1380
0
    if (*value == NULL) {
1381
0
        ssh_set_error_oom(session);
1382
0
        return SSH_ERROR;
1383
0
    }
1384
0
    return SSH_OK;
1385
0
}
1386
1387
/**
1388
 * @brief Parse command line arguments.
1389
 *
1390
 * This is a helper for your application to generate the appropriate
1391
 * options from the command line arguments.\n
1392
 * The argv array and argc value are changed so that the parsed
1393
 * arguments won't appear anymore in them.\n
1394
 * The single arguments (without switches) are not parsed. thus,
1395
 * myssh -l user localhost\n
1396
 * The command won't set the hostname value of options to localhost.
1397
 *
1398
 * @param session       The session to configure.
1399
 *
1400
 * @param argcptr       The pointer to the argument count.
1401
 *
1402
 * @param argv          The arguments list pointer.
1403
 *
1404
 * @returns 0 on success, < 0 on error.
1405
 *
1406
 * @see ssh_session_new()
1407
 */
1408
int ssh_options_getopt(ssh_session session, int *argcptr, char **argv)
1409
0
{
1410
#ifdef _MSC_VER
1411
    (void)session;
1412
    (void)argcptr;
1413
    (void)argv;
1414
    /* Not supported with a Microsoft compiler */
1415
    return -1;
1416
#else
1417
0
    char *user = NULL;
1418
0
    char *cipher = NULL;
1419
0
    char *identity = NULL;
1420
0
    char *port = NULL;
1421
0
    char **save = NULL;
1422
0
    char **tmp = NULL;
1423
0
    size_t i = 0;
1424
0
    int argc = *argcptr;
1425
0
    int debuglevel = 0;
1426
0
    int compress = 0;
1427
0
    int cont = 1;
1428
0
    size_t current = 0;
1429
0
    int saveoptind = optind; /* need to save 'em */
1430
0
    int saveopterr = opterr;
1431
0
    int opt;
1432
1433
    /* Nothing to do here */
1434
0
    if (argc <= 1) {
1435
0
        return SSH_OK;
1436
0
    }
1437
1438
0
    opterr = 0; /* shut up getopt */
1439
0
    while((opt = getopt(argc, argv, "c:i:Cl:p:vb:r12")) != -1) {
1440
0
        switch(opt) {
1441
0
        case 'l':
1442
0
            user = optarg;
1443
0
            break;
1444
0
        case 'p':
1445
0
            port = optarg;
1446
0
            break;
1447
0
        case 'v':
1448
0
            debuglevel++;
1449
0
            break;
1450
0
        case 'r':
1451
0
            break;
1452
0
        case 'c':
1453
0
            cipher = optarg;
1454
0
            break;
1455
0
        case 'i':
1456
0
            identity = optarg;
1457
0
            break;
1458
0
        case 'C':
1459
0
            compress++;
1460
0
            break;
1461
0
        case '2':
1462
0
            break;
1463
0
        case '1':
1464
0
            break;
1465
0
        default:
1466
0
            {
1467
0
                tmp = realloc(save, (current + 1) * sizeof(char*));
1468
0
                if (tmp == NULL) {
1469
0
                    SAFE_FREE(save);
1470
0
                    ssh_set_error_oom(session);
1471
0
                    return -1;
1472
0
                }
1473
0
                save = tmp;
1474
0
                save[current] = argv[optind-1];
1475
0
                current++;
1476
                /* We can not use optarg here as getopt does not set it for
1477
                 * unknown options. We need to manually extract following
1478
                 * option and skip it manually from further processing */
1479
0
                if (optind < argc && argv[optind][0] != '-') {
1480
0
                    tmp = realloc(save, (current + 1) * sizeof(char*));
1481
0
                    if (tmp == NULL) {
1482
0
                        SAFE_FREE(save);
1483
0
                        ssh_set_error_oom(session);
1484
0
                        return -1;
1485
0
                    }
1486
0
                    save = tmp;
1487
0
                    save[current++] = argv[optind];
1488
0
                    optind++;
1489
0
                }
1490
0
            }
1491
0
        } /* switch */
1492
0
    } /* while */
1493
0
    opterr = saveopterr;
1494
0
    tmp = realloc(save, (current + (argc - optind)) * sizeof(char*));
1495
0
    if (tmp == NULL) {
1496
0
        SAFE_FREE(save);
1497
0
        ssh_set_error_oom(session);
1498
0
        return -1;
1499
0
    }
1500
0
    save = tmp;
1501
0
    while (optind < argc) {
1502
0
        tmp = realloc(save, (current + 1) * sizeof(char*));
1503
0
        if (tmp == NULL) {
1504
0
            SAFE_FREE(save);
1505
0
            ssh_set_error_oom(session);
1506
0
            return -1;
1507
0
        }
1508
0
        save = tmp;
1509
0
        save[current] = argv[optind];
1510
0
        current++;
1511
0
        optind++;
1512
0
    }
1513
1514
0
    ssh_set_log_level(debuglevel);
1515
1516
0
    optind = saveoptind;
1517
1518
0
    if(!cont) {
1519
0
        SAFE_FREE(save);
1520
0
        return -1;
1521
0
    }
1522
1523
    /* first recopy the save vector into the original's */
1524
0
    for (i = 0; i < current; i++) {
1525
        /* don't erase argv[0] */
1526
0
        argv[ i + 1] = save[i];
1527
0
    }
1528
0
    argv[current + 1] = NULL;
1529
0
    *argcptr = current + 1;
1530
0
    SAFE_FREE(save);
1531
1532
    /* set a new option struct */
1533
0
    if (compress) {
1534
0
        if (ssh_options_set(session, SSH_OPTIONS_COMPRESSION, "yes") < 0) {
1535
0
            cont = 0;
1536
0
        }
1537
0
    }
1538
1539
0
    if (cont && cipher) {
1540
0
        if (ssh_options_set(session, SSH_OPTIONS_CIPHERS_C_S, cipher) < 0) {
1541
0
            cont = 0;
1542
0
        }
1543
0
        if (cont && ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, cipher) < 0) {
1544
0
            cont = 0;
1545
0
        }
1546
0
    }
1547
1548
0
    if (cont && user) {
1549
0
        if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) {
1550
0
            cont = 0;
1551
0
        }
1552
0
    }
1553
1554
0
    if (cont && identity) {
1555
0
        if (ssh_options_set(session, SSH_OPTIONS_IDENTITY, identity) < 0) {
1556
0
            cont = 0;
1557
0
        }
1558
0
    }
1559
1560
0
    if (port != NULL) {
1561
0
        ssh_options_set(session, SSH_OPTIONS_PORT_STR, port);
1562
0
    }
1563
1564
0
    if (!cont) {
1565
0
        return SSH_ERROR;
1566
0
    }
1567
1568
0
    return SSH_OK;
1569
0
#endif
1570
0
}
1571
1572
/**
1573
 * @brief Parse the ssh config file.
1574
 *
1575
 * This should be the last call of all options, it may overwrite options which
1576
 * are already set. It requires that the host name is already set with
1577
 * ssh_options_set(SSH_OPTIONS_HOST).
1578
 *
1579
 * @param  session      SSH session handle
1580
 *
1581
 * @param  filename     The options file to use, if NULL the default
1582
 *                      ~/.ssh/config and /etc/ssh/ssh_config will be used.
1583
 *
1584
 * @return 0 on success, < 0 on error.
1585
 *
1586
 * @see ssh_options_set()
1587
 */
1588
int ssh_options_parse_config(ssh_session session, const char *filename)
1589
0
{
1590
0
  char *expanded_filename;
1591
0
  int r;
1592
1593
0
  if (session == NULL) {
1594
0
    return -1;
1595
0
  }
1596
0
  if (session->opts.host == NULL) {
1597
0
    ssh_set_error_invalid(session);
1598
0
    return -1;
1599
0
  }
1600
1601
0
  if (session->opts.sshdir == NULL) {
1602
0
      r = ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL);
1603
0
      if (r < 0) {
1604
0
          ssh_set_error_oom(session);
1605
0
          return -1;
1606
0
      }
1607
0
  }
1608
1609
  /* set default filename */
1610
0
  if (filename == NULL) {
1611
0
    expanded_filename = ssh_path_expand_escape(session, "%d/config");
1612
0
  } else {
1613
0
    expanded_filename = ssh_path_expand_escape(session, filename);
1614
0
  }
1615
0
  if (expanded_filename == NULL) {
1616
0
    return -1;
1617
0
  }
1618
1619
0
  r = ssh_config_parse_file(session, expanded_filename);
1620
0
  if (r < 0) {
1621
0
      goto out;
1622
0
  }
1623
0
  if (filename == NULL) {
1624
0
      r = ssh_config_parse_file(session, GLOBAL_CLIENT_CONFIG);
1625
0
  }
1626
1627
  /* Do not process the default configuration as part of connection again */
1628
0
  session->opts.config_processed = true;
1629
0
out:
1630
0
  free(expanded_filename);
1631
0
  return r;
1632
0
}
1633
1634
int ssh_options_apply(ssh_session session)
1635
3.25k
{
1636
3.25k
    char *tmp;
1637
3.25k
    int rc;
1638
1639
3.25k
    if (session->opts.sshdir == NULL) {
1640
3.25k
        rc = ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL);
1641
3.25k
        if (rc < 0) {
1642
0
            return -1;
1643
0
        }
1644
3.25k
    }
1645
1646
3.25k
    if (session->opts.username == NULL) {
1647
0
        rc = ssh_options_set(session, SSH_OPTIONS_USER, NULL);
1648
0
        if (rc < 0) {
1649
0
            return -1;
1650
0
        }
1651
0
    }
1652
1653
3.25k
    if ((session->opts.exp_flags & SSH_OPT_EXP_FLAG_KNOWNHOSTS) == 0) {
1654
3.25k
        if (session->opts.knownhosts == NULL) {
1655
3.25k
            tmp = ssh_path_expand_escape(session, "%d/known_hosts");
1656
3.25k
        } else {
1657
0
            tmp = ssh_path_expand_escape(session, session->opts.knownhosts);
1658
0
        }
1659
3.25k
        if (tmp == NULL) {
1660
0
            return -1;
1661
0
        }
1662
3.25k
        free(session->opts.knownhosts);
1663
3.25k
        session->opts.knownhosts = tmp;
1664
3.25k
        session->opts.exp_flags |= SSH_OPT_EXP_FLAG_KNOWNHOSTS;
1665
3.25k
    }
1666
1667
3.25k
    if ((session->opts.exp_flags & SSH_OPT_EXP_FLAG_GLOBAL_KNOWNHOSTS) == 0) {
1668
3.25k
        if (session->opts.global_knownhosts == NULL) {
1669
3.25k
            tmp = strdup("/etc/ssh/ssh_known_hosts");
1670
3.25k
        } else {
1671
0
            tmp = ssh_path_expand_escape(session,
1672
0
                                         session->opts.global_knownhosts);
1673
0
        }
1674
3.25k
        if (tmp == NULL) {
1675
0
            return -1;
1676
0
        }
1677
3.25k
        free(session->opts.global_knownhosts);
1678
3.25k
        session->opts.global_knownhosts = tmp;
1679
3.25k
        session->opts.exp_flags |= SSH_OPT_EXP_FLAG_GLOBAL_KNOWNHOSTS;
1680
3.25k
    }
1681
1682
1683
3.25k
    if ((session->opts.exp_flags & SSH_OPT_EXP_FLAG_PROXYCOMMAND) == 0) {
1684
3.25k
        if (session->opts.ProxyCommand != NULL) {
1685
0
            char *p = NULL;
1686
0
            size_t plen = strlen(session->opts.ProxyCommand) +
1687
0
                          5 /* strlen("exec ") */;
1688
1689
0
            if (strncmp(session->opts.ProxyCommand, "exec ", 5) != 0) {
1690
0
                p = malloc(plen + 1 /* \0 */);
1691
0
                if (p == NULL) {
1692
0
                    return -1;
1693
0
                }
1694
1695
0
                rc = snprintf(p, plen + 1, "exec %s", session->opts.ProxyCommand);
1696
0
                if ((size_t)rc != plen) {
1697
0
                    free(p);
1698
0
                    return -1;
1699
0
                }
1700
0
                tmp = ssh_path_expand_escape(session, p);
1701
0
                free(p);
1702
0
            } else {
1703
0
                tmp = ssh_path_expand_escape(session,
1704
0
                                             session->opts.ProxyCommand);
1705
0
            }
1706
1707
0
            if (tmp == NULL) {
1708
0
                return -1;
1709
0
            }
1710
0
            free(session->opts.ProxyCommand);
1711
0
            session->opts.ProxyCommand = tmp;
1712
0
            session->opts.exp_flags |= SSH_OPT_EXP_FLAG_PROXYCOMMAND;
1713
0
        }
1714
3.25k
    }
1715
1716
3.25k
    if ((session->opts.exp_flags & SSH_OPT_EXP_FLAG_CONTROL_PATH) == 0) {
1717
3.25k
        if (session->opts.control_path != NULL) {
1718
0
            tmp = ssh_path_expand_escape(session, session->opts.control_path);
1719
0
            if (tmp == NULL) {
1720
0
                return -1;
1721
0
            }
1722
0
            free(session->opts.control_path);
1723
0
            session->opts.control_path = tmp;
1724
0
            session->opts.exp_flags |= SSH_OPT_EXP_FLAG_CONTROL_PATH;
1725
0
        }
1726
3.25k
    }
1727
1728
3.25k
    for (tmp = ssh_list_pop_head(char *, session->opts.identity_non_exp);
1729
13.0k
         tmp != NULL;
1730
9.76k
         tmp = ssh_list_pop_head(char *, session->opts.identity_non_exp)) {
1731
9.76k
        char *id = tmp;
1732
9.76k
        if (strncmp(id, "pkcs11:", 6) != 0) {
1733
            /* PKCS#11 URIs are using percent-encoding so we can not mix
1734
             * it with ssh expansion of ssh escape characters.
1735
             */
1736
9.76k
            tmp = ssh_path_expand_escape(session, id);
1737
9.76k
            if (tmp == NULL) {
1738
0
                return -1;
1739
0
            }
1740
9.76k
            free(id);
1741
9.76k
        }
1742
1743
        /* use append to keep the order at first call and use prepend
1744
         * to put anything that comes on the nth calls to the beginning */
1745
9.76k
        if (session->opts.exp_flags & SSH_OPT_EXP_FLAG_IDENTITY) {
1746
0
            rc = ssh_list_prepend(session->opts.identity, tmp);
1747
9.76k
        } else {
1748
9.76k
            rc = ssh_list_append(session->opts.identity, tmp);
1749
9.76k
        }
1750
9.76k
        if (rc != SSH_OK) {
1751
0
            return -1;
1752
0
        }
1753
9.76k
    }
1754
3.25k
    session->opts.exp_flags |= SSH_OPT_EXP_FLAG_IDENTITY;
1755
1756
3.25k
    return 0;
1757
3.25k
}
1758
1759
/** @} */
1760
1761
#ifdef WITH_SERVER
1762
static bool ssh_bind_key_size_allowed(ssh_bind sshbind, ssh_key key)
1763
5.65k
{
1764
5.65k
    int min_size = 0;
1765
1766
5.65k
    switch (ssh_key_type(key)) {
1767
5.65k
    case SSH_KEYTYPE_RSA:
1768
5.65k
    case SSH_KEYTYPE_RSA_CERT01:
1769
5.65k
        min_size = sshbind->rsa_min_size;
1770
5.65k
        return ssh_key_size_allowed_rsa(min_size, key);
1771
0
    default:
1772
0
        return true;
1773
5.65k
    }
1774
5.65k
}
1775
1776
/**
1777
 * @addtogroup libssh_server
1778
 * @{
1779
 */
1780
static int
1781
ssh_bind_set_key(ssh_bind sshbind, char **key_loc, const void *value)
1782
5.65k
{
1783
5.65k
    if (value == NULL) {
1784
0
        ssh_set_error_invalid(sshbind);
1785
0
        return -1;
1786
5.65k
    } else {
1787
5.65k
        SAFE_FREE(*key_loc);
1788
5.65k
        *key_loc = strdup(value);
1789
5.65k
        if (*key_loc == NULL) {
1790
0
            ssh_set_error_oom(sshbind);
1791
0
            return -1;
1792
0
        }
1793
5.65k
    }
1794
5.65k
    return 0;
1795
5.65k
}
1796
1797
static int ssh_bind_set_algo(ssh_bind sshbind,
1798
                             enum ssh_kex_types_e algo,
1799
                             const char *list,
1800
                             char **place)
1801
22.7k
{
1802
    /* sshbind is needed only for ssh_set_error which takes void*
1803
     * the typecast is only to satisfy function parameter type */
1804
22.7k
    return ssh_options_set_algo((ssh_session)sshbind, algo, list, place);
1805
22.7k
}
1806
1807
/**
1808
 * @brief Set options for an SSH server bind.
1809
 *
1810
 * @param  sshbind      The ssh server bind to configure.
1811
 *
1812
 * @param  type         The option type to set. This should be one of the
1813
 *                      following:
1814
 *
1815
 *                      - SSH_BIND_OPTIONS_HOSTKEY:
1816
 *                        Set the path to an ssh host key, regardless
1817
 *                        of type.  Only one key from per key type
1818
 *                        (RSA, ED25519 and ECDSA) is allowed in an ssh_bind
1819
 *                        at a time, and later calls to this function
1820
 *                        with this option for the same key type will
1821
 *                        override prior calls (const char *).
1822
 *
1823
 *                      - SSH_BIND_OPTIONS_BINDADDR:
1824
 *                        Set the IP address to bind (const char *).
1825
 *
1826
 *                      - SSH_BIND_OPTIONS_BINDPORT:
1827
 *                        Set the port to bind (unsigned int *).
1828
 *
1829
 *                      - SSH_BIND_OPTIONS_BINDPORT_STR:
1830
 *                        Set the port to bind (const char *).
1831
 *
1832
 *                      - SSH_BIND_OPTIONS_LOG_VERBOSITY:
1833
 *                        Set the session logging verbosity (int *).
1834
 *                        The logging verbosity should have one of the
1835
 *                        following values, which are listed in order
1836
 *                        of increasing verbosity.  Every log message
1837
 *                        with verbosity less than or equal to the
1838
 *                        logging verbosity will be shown.
1839
 *                        - SSH_LOG_NOLOG: No logging
1840
 *                        - SSH_LOG_WARNING: Only warnings
1841
 *                        - SSH_LOG_PROTOCOL: High level protocol information
1842
 *                        - SSH_LOG_PACKET: Lower level protocol information, packet level
1843
 *                        - SSH_LOG_FUNCTIONS: Every function path
1844
 *                        The default is SSH_LOG_NOLOG.
1845
 *
1846
 *                      - SSH_BIND_OPTIONS_LOG_VERBOSITY_STR:
1847
 *                        Set the session logging verbosity via a
1848
 *                        string that will be converted to a numerical
1849
 *                        value (e.g. "3") and interpreted according
1850
 *                        to the values of
1851
 *                        SSH_BIND_OPTIONS_LOG_VERBOSITY above (const
1852
 *                        char *).
1853
 *
1854
 *                      - SSH_BIND_OPTIONS_RSAKEY:
1855
 *                        Deprecated alias to SSH_BIND_OPTIONS_HOSTKEY
1856
 *                        (const char *).
1857
 *
1858
 *                      - SSH_BIND_OPTIONS_ECDSAKEY:
1859
 *                        Deprecated alias to SSH_BIND_OPTIONS_HOSTKEY
1860
 *                        (const char *).
1861
 *
1862
 *                      - SSH_BIND_OPTIONS_BANNER:
1863
 *                        Set the server banner sent to clients (const char *).
1864
 *
1865
 *                      - SSH_BIND_OPTIONS_DSAKEY:
1866
 *                        This is DEPRECATED, please do not use.
1867
 *
1868
 *                      - SSH_BIND_OPTIONS_IMPORT_KEY:
1869
 *                        Set the Private Key for the server directly (ssh_key)
1870
 *
1871
 *                      - SSH_BIND_OPTIONS_CIPHERS_C_S:
1872
 *                        Set the symmetric cipher client to server (const char *,
1873
 *                        comma-separated list).
1874
 *
1875
 *                      - SSH_BIND_OPTIONS_CIPHERS_S_C:
1876
 *                        Set the symmetric cipher server to client (const char *,
1877
 *                        comma-separated list).
1878
 *
1879
 *                      - SSH_BIND_OPTIONS_KEY_EXCHANGE:
1880
 *                        Set the key exchange method to be used (const char *,
1881
 *                        comma-separated list). ex:
1882
 *                        "ecdh-sha2-nistp256,diffie-hellman-group14-sha1"
1883
 *
1884
 *                      - SSH_BIND_OPTIONS_HMAC_C_S:
1885
 *                        Set the Message Authentication Code algorithm client
1886
 *                        to server (const char *, comma-separated list).
1887
 *
1888
 *                      - SSH_BIND_OPTIONS_HMAC_S_C:
1889
 *                        Set the Message Authentication Code algorithm server
1890
 *                        to client (const char *, comma-separated list).
1891
 *
1892
 *                      - SSH_BIND_OPTIONS_CONFIG_DIR:
1893
 *                        Set the directory (const char *, format string)
1894
 *                        to be used when the "%d" scape is used when providing
1895
 *                        paths of configuration files to
1896
 *                        ssh_bind_options_parse_config().
1897
 *
1898
 *                      - SSH_BIND_OPTIONS_PROCESS_CONFIG
1899
 *                        Set it to false to disable automatic processing of
1900
 *                        system-wide configuration files. LibSSH automatically
1901
 *                        uses these configuration files otherwise. This
1902
 *                        option will only have effect if set before any call
1903
 *                        to ssh_bind_options_parse_config() (bool).
1904
 *
1905
 *                      - SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES:
1906
 *                        Set the public key algorithm accepted by the server
1907
 *                        (const char *, comma-separated list).
1908
 *
1909
 *                      - SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS:
1910
 *                        Set the list of allowed hostkey signatures algorithms
1911
 *                        to offer to the client, ordered by preference. This
1912
 *                        list is used as a filter when creating the list of
1913
 *                        algorithms to offer to the client: first the list of
1914
 *                        possible algorithms is created from the list of keys
1915
 *                        set and then filtered against this list.
1916
 *                        (const char *, comma-separated list).
1917
 *
1918
 *                      - SSH_BIND_OPTIONS_MODULI
1919
 *                        Set the path to the moduli file. Defaults to
1920
 *                        /etc/ssh/moduli if not specified (const char *).
1921
 *
1922
 *                      - SSH_BIND_OPTIONS_RSA_MIN_SIZE
1923
 *                        Set the minimum RSA key size in bits to be accepted by
1924
 *                        the server for both authentication and hostkey
1925
 *                        operations. The values under 768 bits are not accepted
1926
 *                        even with this configuration option as they are
1927
 *                        considered completely broken. Setting 0 will revert
1928
 *                        the value to defaults.
1929
 *                        Default is 1024 bits or 2048 bits in FIPS mode.
1930
 *                        (int)
1931
 *
1932
 *
1933
 * @param  value        The value to set. This is a generic pointer and the
1934
 *                      datatype which should be used is described at the
1935
 *                      corresponding value of type above.
1936
 *
1937
 * @return              0 on success, < 0 on error, invalid option, or parameter.
1938
 */
1939
int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
1940
    const void *value)
1941
34.1k
{
1942
34.1k
  bool allowed;
1943
34.1k
  char *p, *q;
1944
34.1k
  const char *v;
1945
34.1k
  int i, rc;
1946
34.1k
  char **wanted_methods = sshbind->wanted_methods;
1947
1948
34.1k
  if (sshbind == NULL) {
1949
0
    return -1;
1950
0
  }
1951
1952
34.1k
  switch (type) {
1953
0
    case SSH_BIND_OPTIONS_RSAKEY:
1954
0
    case SSH_BIND_OPTIONS_ECDSAKEY:
1955
        /* deprecated */
1956
5.65k
    case SSH_BIND_OPTIONS_HOSTKEY:
1957
5.65k
      if (value == NULL) {
1958
0
        ssh_set_error_invalid(sshbind);
1959
0
        return -1;
1960
5.65k
      } else {
1961
5.65k
          int key_type;
1962
5.65k
          ssh_key key;
1963
5.65k
          ssh_key *bind_key_loc = NULL;
1964
5.65k
          char **bind_key_path_loc;
1965
1966
5.65k
          rc = ssh_pki_import_privkey_file(value, NULL, NULL, NULL, &key);
1967
5.65k
          if (rc != SSH_OK) {
1968
2
              return -1;
1969
2
          }
1970
5.65k
          allowed = ssh_bind_key_size_allowed(sshbind, key);
1971
5.65k
          if (!allowed) {
1972
0
              ssh_set_error(sshbind,
1973
0
                            SSH_FATAL,
1974
0
                            "The host key size %d is too small.",
1975
0
                            ssh_key_size(key));
1976
0
              ssh_key_free(key);
1977
0
              return -1;
1978
0
          }
1979
1980
5.65k
          key_type = ssh_key_type(key);
1981
5.65k
          switch (key_type) {
1982
0
          case SSH_KEYTYPE_ECDSA_P256:
1983
0
          case SSH_KEYTYPE_ECDSA_P384:
1984
0
          case SSH_KEYTYPE_ECDSA_P521:
1985
0
#ifdef HAVE_ECC
1986
0
              bind_key_loc = &sshbind->ecdsa;
1987
0
              bind_key_path_loc = &sshbind->ecdsakey;
1988
#else
1989
              ssh_set_error(sshbind,
1990
                            SSH_FATAL,
1991
                            "ECDSA key used and libssh compiled "
1992
                            "without ECDSA support");
1993
#endif
1994
0
              break;
1995
5.65k
          case SSH_KEYTYPE_RSA:
1996
5.65k
              bind_key_loc = &sshbind->rsa;
1997
5.65k
              bind_key_path_loc = &sshbind->rsakey;
1998
5.65k
              break;
1999
0
          case SSH_KEYTYPE_ED25519:
2000
0
              bind_key_loc = &sshbind->ed25519;
2001
0
              bind_key_path_loc = &sshbind->ed25519key;
2002
0
              break;
2003
0
          default:
2004
0
              ssh_set_error(sshbind,
2005
5.65k
                            SSH_FATAL,
2006
5.65k
                            "Unsupported key type %d", key_type);
2007
5.65k
          }
2008
2009
5.65k
          if (bind_key_loc == NULL) {
2010
0
              ssh_key_free(key);
2011
0
              return -1;
2012
0
          }
2013
2014
          /* Set the location of the key on disk even though we don't
2015
             need it in case some other function wants it */
2016
5.65k
          rc = ssh_bind_set_key(sshbind, bind_key_path_loc, value);
2017
5.65k
          if (rc < 0) {
2018
0
              ssh_key_free(key);
2019
0
              return -1;
2020
0
          }
2021
5.65k
          ssh_key_free(*bind_key_loc);
2022
5.65k
          *bind_key_loc = key;
2023
5.65k
      }
2024
5.65k
      break;
2025
5.65k
    case SSH_BIND_OPTIONS_IMPORT_KEY:
2026
0
        if (value == NULL) {
2027
0
            ssh_set_error_invalid(sshbind);
2028
0
            return -1;
2029
0
        } else {
2030
0
            int key_type;
2031
0
            ssh_key *bind_key_loc = NULL;
2032
0
            ssh_key key = (ssh_key)value;
2033
2034
0
            allowed = ssh_bind_key_size_allowed(sshbind, key);
2035
0
            if (!allowed) {
2036
0
                ssh_set_error(sshbind,
2037
0
                              SSH_FATAL,
2038
0
                              "The host key size %d is too small.",
2039
0
                              ssh_key_size(key));
2040
0
                return -1;
2041
0
            }
2042
2043
0
            key_type = ssh_key_type(key);
2044
0
            switch (key_type) {
2045
0
                case SSH_KEYTYPE_ECDSA_P256:
2046
0
                case SSH_KEYTYPE_ECDSA_P384:
2047
0
                case SSH_KEYTYPE_ECDSA_P521:
2048
0
#ifdef HAVE_ECC
2049
0
                    bind_key_loc = &sshbind->ecdsa;
2050
#else
2051
                    ssh_set_error(sshbind,
2052
                                  SSH_FATAL,
2053
                                  "ECDSA key used and libssh compiled "
2054
                                  "without ECDSA support");
2055
#endif
2056
0
                    break;
2057
0
                case SSH_KEYTYPE_RSA:
2058
0
                    bind_key_loc = &sshbind->rsa;
2059
0
                    break;
2060
0
                case SSH_KEYTYPE_ED25519:
2061
0
                    bind_key_loc = &sshbind->ed25519;
2062
0
                    break;
2063
0
                default:
2064
0
                    ssh_set_error(sshbind,
2065
0
                                  SSH_FATAL,
2066
0
                                  "Unsupported key type %d", key_type);
2067
0
            }
2068
0
            if (bind_key_loc == NULL)
2069
0
                return -1;
2070
0
            ssh_key_free(*bind_key_loc);
2071
0
            *bind_key_loc = key;
2072
0
        }
2073
0
        break;
2074
0
    case SSH_BIND_OPTIONS_BINDADDR:
2075
0
      if (value == NULL) {
2076
0
        ssh_set_error_invalid(sshbind);
2077
0
        return -1;
2078
0
      } else {
2079
0
        SAFE_FREE(sshbind->bindaddr);
2080
0
        sshbind->bindaddr = strdup(value);
2081
0
        if (sshbind->bindaddr == NULL) {
2082
0
          ssh_set_error_oom(sshbind);
2083
0
          return -1;
2084
0
        }
2085
0
      }
2086
0
      break;
2087
0
    case SSH_BIND_OPTIONS_BINDPORT:
2088
0
      if (value == NULL) {
2089
0
        ssh_set_error_invalid(sshbind);
2090
0
        return -1;
2091
0
      } else {
2092
0
        int *x = (int *) value;
2093
0
        sshbind->bindport = *x & 0xffffU;
2094
0
      }
2095
0
      break;
2096
0
    case SSH_BIND_OPTIONS_BINDPORT_STR:
2097
0
      if (value == NULL) {
2098
0
        sshbind->bindport = 22 & 0xffffU;
2099
0
      } else {
2100
0
        q = strdup(value);
2101
0
        if (q == NULL) {
2102
0
          ssh_set_error_oom(sshbind);
2103
0
          return -1;
2104
0
        }
2105
0
        i = strtol(q, &p, 10);
2106
0
        if (q == p) {
2107
0
            SSH_LOG(SSH_LOG_DEBUG, "No bind port was parsed");
2108
0
            SAFE_FREE(q);
2109
0
            return -1;
2110
0
        }
2111
0
        SAFE_FREE(q);
2112
2113
0
        sshbind->bindport = i & 0xffffU;
2114
0
      }
2115
0
      break;
2116
10
    case SSH_BIND_OPTIONS_LOG_VERBOSITY:
2117
10
      if (value == NULL) {
2118
0
        ssh_set_error_invalid(sshbind);
2119
0
        return -1;
2120
10
      } else {
2121
10
        int *x = (int *) value;
2122
10
        ssh_set_log_level(*x & 0xffffU);
2123
10
      }
2124
10
      break;
2125
10
    case SSH_BIND_OPTIONS_LOG_VERBOSITY_STR:
2126
0
      if (value == NULL) {
2127
0
        ssh_set_log_level(0);
2128
0
      } else {
2129
0
        q = strdup(value);
2130
0
        if (q == NULL) {
2131
0
          ssh_set_error_oom(sshbind);
2132
0
          return -1;
2133
0
        }
2134
0
        i = strtol(q, &p, 10);
2135
0
        if (q == p) {
2136
0
            SSH_LOG(SSH_LOG_DEBUG, "No log verbositiy was parsed");
2137
0
            SAFE_FREE(q);
2138
0
            return -1;
2139
0
        }
2140
0
        SAFE_FREE(q);
2141
2142
0
        ssh_set_log_level(i & 0xffffU);
2143
0
      }
2144
0
      break;
2145
0
    case SSH_BIND_OPTIONS_BANNER:
2146
0
      if (value == NULL) {
2147
0
        ssh_set_error_invalid(sshbind);
2148
0
        return -1;
2149
0
      } else {
2150
0
        SAFE_FREE(sshbind->banner);
2151
0
        sshbind->banner = strdup(value);
2152
0
        if (sshbind->banner == NULL) {
2153
0
          ssh_set_error_oom(sshbind);
2154
0
          return -1;
2155
0
        }
2156
0
      }
2157
0
      break;
2158
5.66k
    case SSH_BIND_OPTIONS_CIPHERS_C_S:
2159
5.66k
        v = value;
2160
5.66k
        if (v == NULL || v[0] == '\0') {
2161
0
            ssh_set_error_invalid(sshbind);
2162
0
            return -1;
2163
5.66k
        } else {
2164
5.66k
            rc = ssh_bind_set_algo(sshbind,
2165
5.66k
                                   SSH_CRYPT_C_S,
2166
5.66k
                                   v,
2167
5.66k
                                   &wanted_methods[SSH_CRYPT_C_S]);
2168
5.66k
            if (rc < 0) {
2169
0
                return -1;
2170
0
            }
2171
5.66k
        }
2172
5.66k
        break;
2173
5.66k
    case SSH_BIND_OPTIONS_CIPHERS_S_C:
2174
5.66k
        v = value;
2175
5.66k
        if (v == NULL || v[0] == '\0') {
2176
0
            ssh_set_error_invalid(sshbind);
2177
0
            return -1;
2178
5.66k
        } else {
2179
5.66k
            rc = ssh_bind_set_algo(sshbind,
2180
5.66k
                                   SSH_CRYPT_S_C,
2181
5.66k
                                   v,
2182
5.66k
                                   &wanted_methods[SSH_CRYPT_S_C]);
2183
5.66k
            if (rc < 0) {
2184
0
                return -1;
2185
0
            }
2186
5.66k
        }
2187
5.66k
        break;
2188
5.66k
    case SSH_BIND_OPTIONS_KEY_EXCHANGE:
2189
18
        v = value;
2190
18
        if (v == NULL || v[0] == '\0') {
2191
0
            ssh_set_error_invalid(sshbind);
2192
0
            return -1;
2193
18
        } else {
2194
18
            rc = ssh_bind_set_algo(sshbind,
2195
18
                                   SSH_KEX,
2196
18
                                   v,
2197
18
                                   &wanted_methods[SSH_KEX]);
2198
18
            if (rc < 0) {
2199
0
                return -1;
2200
0
            }
2201
18
        }
2202
18
        break;
2203
5.70k
    case SSH_BIND_OPTIONS_HMAC_C_S:
2204
5.70k
        v = value;
2205
5.70k
        if (v == NULL || v[0] == '\0') {
2206
0
            ssh_set_error_invalid(sshbind);
2207
0
            return -1;
2208
5.70k
        } else {
2209
5.70k
            rc = ssh_bind_set_algo(sshbind,
2210
5.70k
                                   SSH_MAC_C_S,
2211
5.70k
                                   v,
2212
5.70k
                                   &wanted_methods[SSH_MAC_C_S]);
2213
5.70k
            if (rc < 0) {
2214
3
                return -1;
2215
3
            }
2216
5.70k
        }
2217
5.70k
        break;
2218
5.70k
     case SSH_BIND_OPTIONS_HMAC_S_C:
2219
5.70k
        v = value;
2220
5.70k
        if (v == NULL || v[0] == '\0') {
2221
0
            ssh_set_error_invalid(sshbind);
2222
0
            return -1;
2223
5.70k
        } else {
2224
5.70k
            rc = ssh_bind_set_algo(sshbind,
2225
5.70k
                                   SSH_MAC_S_C,
2226
5.70k
                                   v,
2227
5.70k
                                   &wanted_methods[SSH_MAC_S_C]);
2228
5.70k
            if (rc < 0) {
2229
0
                return -1;
2230
0
            }
2231
5.70k
        }
2232
5.70k
        break;
2233
5.70k
    case SSH_BIND_OPTIONS_CONFIG_DIR:
2234
0
        v = value;
2235
0
        SAFE_FREE(sshbind->config_dir);
2236
0
        if (v == NULL) {
2237
0
            break;
2238
0
        } else if (v[0] == '\0') {
2239
0
            ssh_set_error_invalid(sshbind);
2240
0
            return -1;
2241
0
        } else {
2242
0
            sshbind->config_dir = ssh_path_expand_tilde(v);
2243
0
            if (sshbind->config_dir == NULL) {
2244
0
                ssh_set_error_oom(sshbind);
2245
0
                return -1;
2246
0
            }
2247
0
        }
2248
0
        break;
2249
7
    case SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES:
2250
7
        v = value;
2251
7
        if (v == NULL || v[0] == '\0') {
2252
0
            ssh_set_error_invalid(sshbind);
2253
0
            return -1;
2254
7
        } else {
2255
7
            rc = ssh_bind_set_algo(sshbind,
2256
7
                                   SSH_HOSTKEYS,
2257
7
                                   v,
2258
7
                                   &sshbind->pubkey_accepted_key_types);
2259
7
            if (rc < 0) {
2260
0
                return -1;
2261
0
            }
2262
7
        }
2263
7
        break;
2264
18
    case SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS:
2265
18
        v = value;
2266
18
        if (v == NULL || v[0] == '\0') {
2267
0
            ssh_set_error_invalid(sshbind);
2268
0
            return -1;
2269
18
        } else {
2270
18
            rc = ssh_bind_set_algo(sshbind,
2271
18
                                   SSH_HOSTKEYS,
2272
18
                                   v,
2273
18
                                   &wanted_methods[SSH_HOSTKEYS]);
2274
18
            if (rc < 0) {
2275
1
                return -1;
2276
1
            }
2277
18
        }
2278
17
        break;
2279
5.65k
    case SSH_BIND_OPTIONS_PROCESS_CONFIG:
2280
5.65k
        if (value == NULL) {
2281
0
            ssh_set_error_invalid(sshbind);
2282
0
            return -1;
2283
5.65k
        } else {
2284
5.65k
            bool *x = (bool *)value;
2285
5.65k
            sshbind->config_processed = !(*x);
2286
5.65k
        }
2287
5.65k
        break;
2288
5.65k
    case SSH_BIND_OPTIONS_MODULI:
2289
0
        if (value == NULL) {
2290
0
            ssh_set_error_invalid(sshbind);
2291
0
            return -1;
2292
0
        } else {
2293
0
            SAFE_FREE(sshbind->moduli_file);
2294
0
            sshbind->moduli_file = strdup(value);
2295
0
            if (sshbind->moduli_file == NULL) {
2296
0
                ssh_set_error_oom(sshbind);
2297
0
                return -1;
2298
0
            }
2299
0
        }
2300
0
        break;
2301
0
    case SSH_BIND_OPTIONS_RSA_MIN_SIZE:
2302
0
        if (value == NULL) {
2303
0
            ssh_set_error_invalid(sshbind);
2304
0
            return -1;
2305
0
        } else {
2306
0
            int *x = (int *)value;
2307
0
            if (*x > 0 && *x < 768) {
2308
0
                ssh_set_error(sshbind, SSH_REQUEST_DENIED,
2309
0
                              "The provided value (%u) for minimal RSA key "
2310
0
                              "size is too small. Use at least 768 bits.", *x);
2311
0
                return -1;
2312
0
            }
2313
0
            sshbind->rsa_min_size = *x;
2314
0
        }
2315
0
        break;
2316
0
    default:
2317
0
      ssh_set_error(sshbind, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
2318
0
      return -1;
2319
0
    break;
2320
34.1k
  }
2321
2322
34.0k
  return 0;
2323
34.1k
}
2324
2325
static char *ssh_bind_options_expand_escape(ssh_bind sshbind, const char *s)
2326
0
{
2327
0
    char *buf = NULL;
2328
0
    char *r = NULL;
2329
0
    char *x = NULL;
2330
0
    const char *p;
2331
0
    size_t i, l;
2332
2333
0
    r = ssh_path_expand_tilde(s);
2334
0
    if (r == NULL) {
2335
0
        ssh_set_error_oom(sshbind);
2336
0
        return NULL;
2337
0
    }
2338
2339
0
    if (strlen(r) > MAX_BUF_SIZE) {
2340
0
        ssh_set_error(sshbind, SSH_FATAL, "string to expand too long");
2341
0
        free(r);
2342
0
        return NULL;
2343
0
    }
2344
2345
0
    buf = malloc(MAX_BUF_SIZE);
2346
0
    if (buf == NULL) {
2347
0
        ssh_set_error_oom(sshbind);
2348
0
        free(r);
2349
0
        return NULL;
2350
0
    }
2351
2352
0
    p = r;
2353
0
    buf[0] = '\0';
2354
2355
0
    for (i = 0; *p != '\0'; p++) {
2356
0
        if (*p != '%') {
2357
0
            buf[i] = *p;
2358
0
            i++;
2359
0
            if (i >= MAX_BUF_SIZE) {
2360
0
                free(buf);
2361
0
                free(r);
2362
0
                return NULL;
2363
0
            }
2364
0
            buf[i] = '\0';
2365
0
            continue;
2366
0
        }
2367
2368
0
        p++;
2369
0
        if (*p == '\0') {
2370
0
            break;
2371
0
        }
2372
2373
0
        switch (*p) {
2374
0
            case 'd':
2375
0
                x = strdup(sshbind->config_dir);
2376
0
                break;
2377
0
            default:
2378
0
                ssh_set_error(sshbind, SSH_FATAL,
2379
0
                        "Wrong escape sequence detected");
2380
0
                free(buf);
2381
0
                free(r);
2382
0
                return NULL;
2383
0
        }
2384
2385
0
        if (x == NULL) {
2386
0
            ssh_set_error_oom(sshbind);
2387
0
            free(buf);
2388
0
            free(r);
2389
0
            return NULL;
2390
0
        }
2391
2392
0
        i += strlen(x);
2393
0
        if (i >= MAX_BUF_SIZE) {
2394
0
            ssh_set_error(sshbind, SSH_FATAL,
2395
0
                    "String too long");
2396
0
            free(buf);
2397
0
            free(x);
2398
0
            free(r);
2399
0
            return NULL;
2400
0
        }
2401
0
        l = strlen(buf);
2402
0
        strncpy(buf + l, x, MAX_BUF_SIZE - l - 1);
2403
0
        buf[i] = '\0';
2404
0
        SAFE_FREE(x);
2405
0
    }
2406
2407
0
    free(r);
2408
2409
    /* strip the unused space by realloc */
2410
0
    x = realloc(buf, strlen(buf) + 1);
2411
0
    if (x == NULL) {
2412
0
        ssh_set_error_oom(sshbind);
2413
0
        free(buf);
2414
0
    }
2415
0
    return x;
2416
0
}
2417
2418
/**
2419
 * @brief Parse a ssh bind options configuration file.
2420
 *
2421
 * This parses the options file and set them to the ssh_bind handle provided. If
2422
 * an option was previously set, it is overridden. If the global configuration
2423
 * hasn't been processed yet, it is processed prior to the provided file.
2424
 *
2425
 * @param  sshbind      SSH bind handle
2426
 *
2427
 * @param  filename     The options file to use; if NULL only the global
2428
 *                      configuration is parsed and applied (if it hasn't been
2429
 *                      processed before).
2430
 *
2431
 * @return 0 on success, < 0 on error.
2432
 */
2433
int ssh_bind_options_parse_config(ssh_bind sshbind, const char *filename)
2434
5.65k
{
2435
5.65k
    int rc = 0;
2436
5.65k
    char *expanded_filename;
2437
2438
5.65k
    if (sshbind == NULL) {
2439
0
        return -1;
2440
0
    }
2441
2442
    /* If the global default configuration hasn't been processed yet, process it
2443
     * before the provided configuration. */
2444
5.65k
    if (!(sshbind->config_processed)) {
2445
0
        rc = ssh_bind_config_parse_file(sshbind, GLOBAL_BIND_CONFIG);
2446
0
        if (rc != 0) {
2447
0
            return rc;
2448
0
        }
2449
0
        sshbind->config_processed = true;
2450
0
    }
2451
2452
5.65k
    if (filename != NULL) {
2453
0
        expanded_filename = ssh_bind_options_expand_escape(sshbind, filename);
2454
0
        if (expanded_filename == NULL) {
2455
0
            return -1;
2456
0
        }
2457
2458
        /* Apply the user provided configuration */
2459
0
        rc = ssh_bind_config_parse_file(sshbind, expanded_filename);
2460
0
        free(expanded_filename);
2461
0
    }
2462
2463
5.65k
    return rc;
2464
5.65k
}
2465
2466
#endif
2467
2468
/** @} */