Coverage Report

Created: 2026-07-05 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libssh/src/options.c
Line
Count
Source
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 <ctype.h>
27
#include <stdio.h>
28
#include <stdlib.h>
29
#include <string.h>
30
#ifndef _WIN32
31
#include <pwd.h>
32
#else
33
#include <winsock2.h>
34
#endif
35
#include "libssh/config.h"
36
#include "libssh/config_parser.h"
37
#include "libssh/misc.h"
38
#include "libssh/options.h"
39
#include "libssh/pki.h"
40
#include "libssh/pki_context.h"
41
#include "libssh/pki_priv.h"
42
#include "libssh/priv.h"
43
#include "libssh/session.h"
44
#include <sys/types.h>
45
#include "libssh/misc.h"
46
#include "libssh/options.h"
47
#include "libssh/config_parser.h"
48
#include "libssh/gssapi.h"
49
#include "libssh/getopt.h"
50
#include "libssh/token.h"
51
#ifdef WITH_SERVER
52
#include "libssh/server.h"
53
#include "libssh/bind.h"
54
#include "libssh/bind_config.h"
55
#endif
56
57
/**
58
 * @addtogroup libssh_session
59
 * @{
60
 */
61
62
/**
63
 * @brief Duplicate the options of a session structure.
64
 *
65
 * If you make several sessions with the same options this is useful. You
66
 * cannot use twice the same option structure in ssh_connect.
67
 *
68
 * @param src           The session to use to copy the options.
69
 *
70
 * @param dest          A pointer to store the allocated session with duplicated
71
 *                      options. You have to free the memory using ssh_free()
72
 *
73
 * @returns             0 on success, -1 on error with errno set.
74
 *
75
 * @see ssh_connect()
76
 * @see ssh_free()
77
 */
78
int ssh_options_copy(ssh_session src, ssh_session *dest)
79
0
{
80
0
    ssh_session new = NULL;
81
0
    struct ssh_iterator *it = NULL;
82
0
    struct ssh_list *list = NULL;
83
0
    char *id = NULL;
84
0
    int i;
85
86
0
    if (src == NULL || dest == NULL) {
87
0
        return -1;
88
0
    }
89
90
0
    new = ssh_new();
91
0
    if (new == NULL) {
92
0
        return -1;
93
0
    }
94
95
0
    if (src->opts.username != NULL) {
96
0
        new->opts.username = strdup(src->opts.username);
97
0
        if (new->opts.username == NULL) {
98
0
            ssh_free(new);
99
0
            return -1;
100
0
        }
101
0
    }
102
103
0
    if (src->opts.host != NULL) {
104
0
        new->opts.host = strdup(src->opts.host);
105
0
        if (new->opts.host == NULL) {
106
0
            ssh_free(new);
107
0
            return -1;
108
0
        }
109
0
    }
110
111
0
    if (src->opts.originalhost != NULL) {
112
0
        new->opts.originalhost = strdup(src->opts.originalhost);
113
0
        if (new->opts.originalhost == NULL) {
114
0
            ssh_free(new);
115
0
            return -1;
116
0
        }
117
0
    }
118
119
0
    if (src->opts.tag != NULL) {
120
0
        new->opts.tag = strdup(src->opts.tag);
121
0
        if (new->opts.tag == NULL) {
122
0
            ssh_free(new);
123
0
            return -1;
124
0
        }
125
0
    }
126
127
0
    if (src->opts.config_hostname != NULL) {
128
0
        new->opts.config_hostname = strdup(src->opts.config_hostname);
129
0
        if (new->opts.config_hostname == NULL) {
130
0
            ssh_free(new);
131
0
            return -1;
132
0
        }
133
0
    }
134
135
0
    if (src->opts.bindaddr != NULL) {
136
0
        new->opts.bindaddr = strdup(src->opts.bindaddr);
137
0
        if (new->opts.bindaddr == NULL) {
138
0
            ssh_free(new);
139
0
            return -1;
140
0
        }
141
0
    }
142
143
    /* Remove the default identities */
144
0
    for (id = ssh_list_pop_head(char *, new->opts.identity_non_exp);
145
0
         id != NULL;
146
0
         id = ssh_list_pop_head(char *, new->opts.identity_non_exp)) {
147
0
        SAFE_FREE(id);
148
0
    }
149
    /* Copy the new identities from the source list */
150
0
    list = new->opts.identity_non_exp;
151
0
    it = ssh_list_get_iterator(src->opts.identity_non_exp);
152
0
    for (i = 0; i < 2; i++) {
153
0
        while (it) {
154
0
            int rc;
155
156
0
            id = strdup((char *)it->data);
157
0
            if (id == NULL) {
158
0
                ssh_free(new);
159
0
                return -1;
160
0
            }
161
162
0
            rc = ssh_list_append(list, id);
163
0
            if (rc < 0) {
164
0
                free(id);
165
0
                ssh_free(new);
166
0
                return -1;
167
0
            }
168
0
            it = it->next;
169
0
        }
170
171
        /* copy the identity list if there is any already */
172
0
        list = new->opts.identity;
173
0
        it = ssh_list_get_iterator(src->opts.identity);
174
0
    }
175
176
0
    list = new->opts.certificate_non_exp;
177
0
    it = ssh_list_get_iterator(src->opts.certificate_non_exp);
178
0
    for (i = 0; i < 2; i++) {
179
0
        while (it) {
180
0
            int rc;
181
182
0
            id = strdup((char *)it->data);
183
0
            if (id == NULL) {
184
0
                ssh_free(new);
185
0
                return -1;
186
0
            }
187
188
0
            rc = ssh_list_append(list, id);
189
0
            if (rc < 0) {
190
0
                free(id);
191
0
                ssh_free(new);
192
0
                return -1;
193
0
            }
194
0
            it = it->next;
195
0
        }
196
197
        /* copy the certificate list if there is any already */
198
0
        list = new->opts.certificate;
199
0
        it = ssh_list_get_iterator(src->opts.certificate);
200
0
    }
201
202
0
    it = ssh_list_get_iterator(src->opts.local_forward);
203
0
    while (it) {
204
0
        int rc = 0;
205
0
        char *pattern = strdup(ssh_iterator_value(char *, it));
206
207
0
        if (pattern == NULL) {
208
0
            ssh_free(new);
209
0
            return -1;
210
0
        }
211
0
        rc = ssh_list_append(new->opts.local_forward, pattern);
212
0
        if (rc < 0) {
213
0
            free(pattern);
214
0
            ssh_free(new);
215
0
            return -1;
216
0
        }
217
0
        it = it->next;
218
0
    }
219
220
0
    if (src->opts.sshdir != NULL) {
221
0
        new->opts.sshdir = strdup(src->opts.sshdir);
222
0
        if (new->opts.sshdir == NULL) {
223
0
            ssh_free(new);
224
0
            return -1;
225
0
        }
226
0
    }
227
228
0
    if (src->opts.knownhosts != NULL) {
229
0
        new->opts.knownhosts = strdup(src->opts.knownhosts);
230
0
        if (new->opts.knownhosts == NULL) {
231
0
            ssh_free(new);
232
0
            return -1;
233
0
        }
234
0
    }
235
236
0
    if (src->opts.global_knownhosts != NULL) {
237
0
        new->opts.global_knownhosts = strdup(src->opts.global_knownhosts);
238
0
        if (new->opts.global_knownhosts == NULL) {
239
0
            ssh_free(new);
240
0
            return -1;
241
0
        }
242
0
    }
243
244
0
    for (i = 0; i < SSH_KEX_METHODS; i++) {
245
0
        if (src->opts.wanted_methods[i] != NULL) {
246
0
            new->opts.wanted_methods[i] = strdup(src->opts.wanted_methods[i]);
247
0
            if (new->opts.wanted_methods[i] == NULL) {
248
0
                ssh_free(new);
249
0
                return -1;
250
0
            }
251
0
        }
252
0
    }
253
254
0
    if (src->opts.ProxyCommand != NULL) {
255
0
        new->opts.ProxyCommand = strdup(src->opts.ProxyCommand);
256
0
        if (new->opts.ProxyCommand == NULL) {
257
0
            ssh_free(new);
258
0
            return -1;
259
0
        }
260
0
    }
261
262
0
    if (src->opts.pubkey_accepted_types != NULL) {
263
0
        new->opts.pubkey_accepted_types = strdup(src->opts.pubkey_accepted_types);
264
0
        if (new->opts.pubkey_accepted_types == NULL) {
265
0
            ssh_free(new);
266
0
            return -1;
267
0
        }
268
0
    }
269
270
0
    if (src->opts.gss_server_identity != NULL) {
271
0
        new->opts.gss_server_identity = strdup(src->opts.gss_server_identity);
272
0
        if (new->opts.gss_server_identity == NULL) {
273
0
            ssh_free(new);
274
0
            return -1;
275
0
        }
276
0
    }
277
278
0
    if (src->opts.gss_client_identity != NULL) {
279
0
        new->opts.gss_client_identity = strdup(src->opts.gss_client_identity);
280
0
        if (new->opts.gss_client_identity == NULL) {
281
0
            ssh_free(new);
282
0
            return -1;
283
0
        }
284
0
    }
285
286
0
    if (src->opts.control_path != NULL) {
287
0
        new->opts.control_path = strdup(src->opts.control_path);
288
0
        if (new->opts.control_path == NULL) {
289
0
            ssh_free(new);
290
0
            return -1;
291
0
        }
292
0
    }
293
294
0
    if (src->opts.preferred_authentications != NULL) {
295
0
        new->opts.preferred_authentications = strdup(src->opts.preferred_authentications);
296
0
        if (new->opts.preferred_authentications == NULL) {
297
0
            ssh_free(new);
298
0
            return -1;
299
0
        }
300
0
    }
301
302
0
    it = ssh_list_get_iterator(src->opts.send_env);
303
0
    while (it) {
304
0
        int rc = 0;
305
0
        char *pattern = strdup((char *)it->data);
306
307
0
        if (pattern == NULL) {
308
0
            ssh_free(new);
309
0
            return -1;
310
0
        }
311
0
        rc = ssh_list_append(new->opts.send_env, pattern);
312
0
        if (rc < 0) {
313
0
            free(pattern);
314
0
            ssh_free(new);
315
0
            return -1;
316
0
        }
317
0
        it = it->next;
318
0
    }
319
320
0
    memcpy(new->opts.options_seen, src->opts.options_seen,
321
0
           sizeof(new->opts.options_seen));
322
323
0
    new->opts.fd                    = src->opts.fd;
324
0
    new->opts.port                  = src->opts.port;
325
0
    new->opts.timeout               = src->opts.timeout;
326
0
    new->opts.timeout_usec          = src->opts.timeout_usec;
327
0
    new->opts.compressionlevel      = src->opts.compressionlevel;
328
0
    new->opts.StrictHostKeyChecking = src->opts.StrictHostKeyChecking;
329
0
    new->opts.gss_delegate_creds    = src->opts.gss_delegate_creds;
330
0
    new->opts.flags                 = src->opts.flags;
331
0
    new->opts.pubkey_auth = src->opts.pubkey_auth;
332
0
    new->opts.nodelay               = src->opts.nodelay;
333
0
    new->opts.config_processed      = src->opts.config_processed;
334
0
    new->opts.control_master        = src->opts.control_master;
335
0
    new->opts.number_of_password_prompts = src->opts.number_of_password_prompts;
336
0
    new->opts.request_tty           = src->opts.request_tty;
337
0
    new->opts.escape_char           = src->opts.escape_char;
338
0
    new->opts.address_family        = src->opts.address_family;
339
0
    new->common.log_verbosity       = src->common.log_verbosity;
340
0
    new->common.callbacks           = src->common.callbacks;
341
342
0
    SSH_PKI_CTX_FREE(new->pki_context);
343
0
    if (src->pki_context != NULL) {
344
0
        new->pki_context = ssh_pki_ctx_dup(src->pki_context);
345
0
        if (new->pki_context == NULL) {
346
0
            ssh_free(new);
347
0
            return -1;
348
0
        }
349
0
    }
350
351
0
    *dest = new;
352
353
0
    return 0;
354
0
}
355
356
/** @internal
357
 * @brief Set a key exchange algorithm list option on the session.
358
 *
359
 * Supports prefix modifiers: '+' to append, '-' to remove, '^' to prepend
360
 * to the default algorithm list.
361
 *
362
 * @param[in]  session  The SSH session.
363
 * @param[in]  algo     The algorithm type to configure.
364
 * @param[in]  list     The algorithm list string.
365
 * @param[out] place    Pointer to the string to store
366
 *                      the resulting algorithm list.
367
 *
368
 * @return  `SSH_OK` on success, `SSH_ERROR` on error.
369
 */
370
int ssh_options_set_algo(ssh_session session,
371
                         enum ssh_kex_types_e algo,
372
                         const char *list,
373
                         char **place)
374
71.5k
{
375
    /* When the list start with +,-,^ the filtration of unknown algorithms
376
     * gets handled inside the helper functions, otherwise the list is taken
377
     * as it is. */
378
71.5k
    char *p = (char *)list;
379
380
71.5k
    if (algo < SSH_COMP_C_S) {
381
71.5k
        if (list[0] == '+') {
382
567
            p = ssh_add_to_default_algos(algo, list+1);
383
70.9k
        } else if (list[0] == '-') {
384
291
            p = ssh_remove_from_default_algos(algo, list+1);
385
70.6k
        } else if (list[0] == '^') {
386
200
            p = ssh_prefix_default_algos(algo, list+1);
387
200
        }
388
71.5k
    }
389
390
71.5k
    if (p == list) {
391
70.4k
        if (ssh_fips_mode()) {
392
0
            p = ssh_keep_fips_algos(algo, list);
393
70.4k
        } else {
394
70.4k
            p = ssh_keep_known_algos(algo, list);
395
70.4k
        }
396
70.4k
    }
397
398
71.5k
    if (p == NULL) {
399
274
        ssh_set_error(session, SSH_REQUEST_DENIED,
400
274
                "Setting method: no allowed algorithm for method \"%s\" (%s)",
401
274
                ssh_kex_get_description(algo), list);
402
274
        return -1;
403
274
    }
404
405
71.2k
    SAFE_FREE(*place);
406
71.2k
    *place = p;
407
408
71.2k
    return 0;
409
71.5k
}
410
411
/**
412
 * @brief This function can set all possible ssh options.
413
 *
414
 * @param  session An allocated SSH session structure.
415
 *
416
 * @param  type The option type to set. This could be one of the
417
 *              following:
418
 *
419
 *              - SSH_OPTIONS_HOST:
420
 *                The hostname or ip address to connect to. It can be also in
421
 *                the format of URI, containing also username, such as
422
 *                [username@]hostname. The IPv6 addresses can be enclosed
423
 *                within square braces, for example [::1]. The IPv4 address
424
 *                supports any format supported by OS. The hostname needs to be
425
 *                encoded to match RFC1035, so for IDN it needs to be encoded
426
 *                in punycode.
427
 *                (const char *).
428
 *
429
 *              - SSH_OPTIONS_PORT:
430
 *                The port to connect to (unsigned int).
431
 *
432
 *              - SSH_OPTIONS_PORT_STR:
433
 *                The port to connect to (const char *).
434
 *
435
 *              - SSH_OPTIONS_FD:
436
 *                The file descriptor to use (socket_t).\n
437
 *                \n
438
 *                If you wish to open the socket yourself for a reason
439
 *                or another, set the file descriptor and take care of closing
440
 *                it (this is new behavior in libssh 0.10).
441
 *                Don't forget to set the hostname as the hostname is used
442
 *                as a key in the known_host mechanism.
443
 *
444
 *              - SSH_OPTIONS_BINDADDR:
445
 *                The address to bind the client to (const char *).
446
 *
447
 *              - SSH_OPTIONS_USER:
448
 *                The username for authentication (const char *).\n
449
 *                \n
450
 *                If the value is NULL, the username is set to the
451
 *                default username.
452
 *
453
 *              - SSH_OPTIONS_SSH_DIR:
454
 *                Set the ssh directory (const char *,format string).\n
455
 *                \n
456
 *                If the value is NULL, the directory is set to the
457
 *                default ssh directory.\n
458
 *                \n
459
 *                The ssh directory is used for files like known_hosts
460
 *                and identity (private and public key). It may start
461
 *                with ~ which will be replaced by the user home
462
 *                directory.
463
 *
464
 *              - SSH_OPTIONS_KNOWNHOSTS:
465
 *                Set the known hosts file name (const char *,format string).\n
466
 *                \n
467
 *                If the value is NULL, the directory is set to the
468
 *                default known hosts file, normally
469
 *                ~/.ssh/known_hosts.\n
470
 *                \n
471
 *                The known hosts file is used to certify remote hosts
472
 *                are genuine. It may include "%d" which will be
473
 *                replaced by the user home directory.
474
 *
475
 *              - SSH_OPTIONS_GLOBAL_KNOWNHOSTS:
476
 *                Set the global known hosts file name (const char *,format string).\n
477
 *                \n
478
 *                If the value is NULL, the directory is set to the
479
 *                default global known hosts file, normally
480
 *                /etc/ssh/ssh_known_hosts.\n
481
 *                \n
482
 *                The known hosts file is used to certify remote hosts
483
 *                are genuine.
484
 *
485
 *              - SSH_OPTIONS_ADD_IDENTITY (or SSH_OPTIONS_IDENTITY):
486
 *                Add a new identity file (const char *, format string) to
487
 *                the identity list.\n
488
 *                \n
489
 *                By default id_rsa, id_ecdsa and id_ed25519 files are used.\n
490
 *                If libssh is built with FIDO2/U2F support, id_ecdsa_sk and\n
491
 *                id_ed25519_sk files are also used by default.\n
492
 *                \n
493
 *                The identity used to authenticate with public key will be
494
 *                prepended to the list.
495
 *                It may include "%s" which will be replaced by the
496
 *                user home directory.
497
 *
498
 *              - SSH_OPTIONS_CERTIFICATE:
499
 *                Add a new certificate file (const char *, format string) to
500
 *                the certificate list.\n
501
 *                \n
502
 *                By default id_rsa-cert.pub, id_ecdsa-cert.pub and
503
 *                id_ed25519-cert.pub files are used, when the underlying
504
 *                private key is present.\n
505
 *                \n
506
 *                The certificate itself can not be used to authenticate to
507
 *                remote server so it needs to be paired with private key
508
 *                (aka identity file) provided with separate option, from agent
509
 *                or from PKCS#11 token.
510
 *                It may include "%s" which will be replaced by the
511
 *                user home directory.
512
 *
513
 *              - SSH_OPTIONS_TIMEOUT:
514
 *                Set a timeout for the connection in seconds (long).
515
 *
516
 *              - SSH_OPTIONS_TIMEOUT_USEC:
517
 *                Set a timeout for the connection in micro seconds
518
 *                        (long).
519
 *
520
 *              - SSH_OPTIONS_SSH1:
521
 *                Deprecated
522
 *
523
 *              - SSH_OPTIONS_SSH2:
524
 *                Unused
525
 *
526
 *              - SSH_OPTIONS_LOG_VERBOSITY:
527
 *                Set the session logging verbosity (int).\n
528
 *                \n
529
 *                The verbosity of the messages. Every log smaller or
530
 *                equal to verbosity will be shown.
531
 *                - SSH_LOG_NOLOG: No logging
532
 *                - SSH_LOG_WARNING: Only warnings
533
 *                - SSH_LOG_PROTOCOL: High level protocol information
534
 *                - SSH_LOG_PACKET: Lower level protocol information, packet level
535
 *                - SSH_LOG_FUNCTIONS: Every function path
536
 *                The default is SSH_LOG_NOLOG.
537
 *
538
 *              - SSH_OPTIONS_LOG_VERBOSITY_STR:
539
 *                Set the session logging verbosity via a
540
 *                string that will be converted to a numerical
541
 *                value (e.g. "3") and interpreted according
542
 *                to the values of
543
 *                SSH_OPTIONS_LOG_VERBOSITY above (const
544
 *                char *).
545
 *
546
 *              - SSH_OPTIONS_CIPHERS_C_S:
547
 *                Set the symmetric cipher client to server (const char *,
548
 *                comma-separated list). The list can be prepended by +,-,^
549
 *                which can append, remove or move to the beginning
550
 *                (prioritizing) of the default list respectively. Giving an
551
 *                empty list after + and ^ will cause error.
552
 *
553
 *              - SSH_OPTIONS_CIPHERS_S_C:
554
 *                Set the symmetric cipher server to client (const char *,
555
 *                comma-separated list). The list can be prepended by +,-,^
556
 *                which can append, remove or move to the beginning
557
 *                (prioritizing) of the default list respectively. Giving an
558
 *                empty list after + and ^ will cause error.
559
 *
560
 *              - SSH_OPTIONS_KEY_EXCHANGE:
561
 *                Set the key exchange method to be used (const char *,
562
 *                comma-separated list). ex:
563
 *                "ecdh-sha2-nistp256,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
564
 *                The list can be prepended by +,-,^ which will append,
565
 *                remove or move to the beginning (prioritizing) of the
566
 *                default list respectively. Giving an empty list
567
 *                after + and ^ will cause error.
568
 *
569
 *              - SSH_OPTIONS_HMAC_C_S:
570
 *                Set the Message Authentication Code algorithm client to server
571
 *                (const char *, comma-separated list). The list can be
572
 *                prepended by +,-,^ which will append, remove or move to
573
 *                the beginning (prioritizing) of the default list
574
 *                respectively. Giving an empty list after + and ^ will
575
 *                cause error.
576
 *
577
 *              - SSH_OPTIONS_HMAC_S_C:
578
 *                Set the Message Authentication Code algorithm server to client
579
 *                (const char *, comma-separated list). The list can be
580
 *                prepended by +,-,^ which will append, remove or move to
581
 *                the beginning (prioritizing) of the default list
582
 *                respectively. Giving an empty list after + and ^ will
583
 *                cause error.
584
 *
585
 *              - SSH_OPTIONS_HOSTKEYS:
586
 *                Set the preferred server host key types (const char *,
587
 *                comma-separated list). ex:
588
 *                "ssh-rsa,ecdh-sha2-nistp256". The list can be
589
 *                prepended by +,-,^ which will append, remove or move to
590
 *                the beginning (prioritizing) of the default list
591
 *                respectively. Giving an empty list after + and ^ will
592
 *                cause error.
593
 *
594
 *              - SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES:
595
 *                Set the preferred public key algorithms to be used for
596
 *                authentication (const char *, comma-separated list). ex:
597
 *                "ssh-rsa,rsa-sha2-256,ecdh-sha2-nistp256"
598
 *                The list can be prepended by +,-,^ which will append,
599
 *                remove or move to the beginning (prioritizing) of the
600
 *                default list respectively. Giving an empty list
601
 *                after + and ^ will cause error.
602
 *
603
 *              - SSH_OPTIONS_COMPRESSION_C_S:
604
 *                Set the compression to use for client to server
605
 *                communication (const char *, "yes", "no" or a specific
606
 *                algorithm name if needed ("zlib","zlib@openssh.com","none").
607
 *
608
 *              - SSH_OPTIONS_COMPRESSION_S_C:
609
 *                Set the compression to use for server to client
610
 *                communication (const char *, "yes", "no" or a specific
611
 *                algorithm name if needed ("zlib","zlib@openssh.com","none").
612
 *
613
 *              - SSH_OPTIONS_COMPRESSION:
614
 *                Set the compression to use for both directions
615
 *                communication (const char *, "yes", "no" or a specific
616
 *                algorithm name if needed ("zlib","zlib@openssh.com","none").
617
 *
618
 *              - SSH_OPTIONS_COMPRESSION_LEVEL:
619
 *                Set the compression level to use for zlib functions. (int,
620
 *                value from 1 to 9, 9 being the most efficient but slower).
621
 *
622
 *              - SSH_OPTIONS_STRICTHOSTKEYCHECK:
623
 *                Set the parameter StrictHostKeyChecking to control how
624
 *                unknown host keys are handled (int, SSH_STRICT_HOSTKEY_OFF,
625
 *                SSH_STRICT_HOSTKEY_YES, SSH_STRICT_HOSTKEY_ASK or
626
 *                SSH_STRICT_HOSTKEY_ACCEPT_NEW).
627
 *                Default: SSH_STRICT_HOSTKEY_ASK.
628
 *
629
 *              - SSH_OPTIONS_PROXYCOMMAND:
630
 *                Set the command to be executed in order to connect to
631
 *                server (const char *).
632
 *
633
 *              - SSH_OPTIONS_PROXYJUMP:
634
 *                Set the comma separated jump hosts in order to connect to
635
 *                server (const char *). Set to "none" to disable.
636
 *                Example:
637
 *                  "alice@127.0.0.1:5555,bob@127.0.0.2"
638
 *
639
 *                If environment variable OPENSSH_PROXYJUMP is set to 1 then proxyjump will be
640
 *                handled by the OpenSSH binary.
641
 *
642
 *              - SSH_OPTIONS_PROXYJUMP_CB_LIST_APPEND:
643
 *                Append the callbacks struct for a jump in order of
644
 *                SSH_OPTIONS_PROXYJUMP. Append as many times
645
 *                as the number of jumps (struct ssh_jump_callbacks_struct *).
646
 *
647
 *              - SSH_OPTIONS_GSSAPI_SERVER_IDENTITY
648
 *                Set it to specify the GSSAPI server identity that libssh
649
 *                should expect when connecting to the server (const char *).
650
 *
651
 *              - SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY
652
 *                Set it to specify the GSSAPI client identity that libssh
653
 *                should expect when connecting to the server (const char *).
654
 *
655
 *              - SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS
656
 *                Set it to specify that GSSAPI should delegate credentials
657
 *                to the server (int, 0 = false).
658
 *
659
 *              - SSH_OPTIONS_GSSAPI_KEY_EXCHANGE
660
 *                Set to true to allow GSSAPI key exchange (bool).
661
 *
662
 *              - SSH_OPTIONS_GSSAPI_KEY_EXCHANGE_ALGS
663
 *                Set the GSSAPI key exchange method to be used (const char *,
664
 *                comma-separated list). ex:
665
 *                "gss-curve25519-sha256-,gss-nistp256-sha256-"
666
 *                These will prefix the default algorithms if
667
 *                SSH_OPTIONS_GSSAPI_KEY_EXCHANGE is true.
668
 *
669
 *              - SSH_OPTIONS_PASSWORD_AUTH
670
 *                Set it if password authentication should be used
671
 *                in ssh_userauth_password(). (int, 0=false).
672
 *
673
 *              - SSH_OPTIONS_PUBKEY_AUTH
674
 *                Set the PubkeyAuthentication mode used by
675
 *                ssh_userauth_publickey_auto(),
676
 *                ssh_userauth_try_publickey(),
677
 *                ssh_userauth_publickey(), and ssh_userauth_agent().
678
 *                The default is SSH_PUBKEY_AUTH_ALL.
679
 *                (int, SSH_PUBKEY_AUTH_NO, SSH_PUBKEY_AUTH_ALL,
680
 *                SSH_PUBKEY_AUTH_UNBOUND or SSH_PUBKEY_AUTH_HOST_BOUND).
681
 *
682
 *              - SSH_OPTIONS_KBDINT_AUTH
683
 *                Set it if keyboard-interactive authentication should
684
 *                be used in ssh_userauth_kbdint(). (int, 0=false).
685
 *
686
 *              - SSH_OPTIONS_GSSAPI_AUTH
687
 *                Set it if gssapi authentication should be used
688
 *                in ssh_userauth_gssapi(). (int, 0=false).
689
 *
690
 *              - SSH_OPTIONS_NODELAY
691
 *                Set it to disable Nagle's Algorithm (TCP_NODELAY) on the
692
 *                session socket. (int, 0=false)
693
 *
694
 *              - SSH_OPTIONS_PROCESS_CONFIG
695
 *                Set it to false to disable automatic processing of per-user
696
 *                and system-wide OpenSSH configuration files. LibSSH
697
 *                automatically uses these configuration files unless
698
 *                you provide it with this option or with different file (bool).
699
 *
700
 *              - SSH_OPTIONS_REKEY_DATA
701
 *                Set the data limit that can be transferred with a single
702
 *                key in bytes. RFC 4253 Section 9 recommends 1GB of data, while
703
 *                RFC 4344 provides more specific restrictions, that are applied
704
 *                automatically. When specified, the lower value will be used.
705
 *                (uint64_t, 0=default)
706
 *
707
 *              - SSH_OPTIONS_REKEY_TIME
708
 *                Set the time limit for a session before initializing a rekey
709
 *                in seconds. RFC 4253 Section 9 recommends one hour.
710
 *                (uint32_t, 0=off)
711
 *
712
 *              - SSH_OPTIONS_RSA_MIN_SIZE
713
 *                Set the minimum RSA key size in bits to be accepted by the
714
 *                client for both authentication and hostkey verification.
715
 *                The values under 1024 bits are not accepted even with this
716
 *                configuration option as they are considered completely broken.
717
 *                Setting 0 will revert the value to defaults.
718
 *                Default is 3072 bits or 2048 bits in FIPS mode.
719
 *                (int)
720
 *
721
 *              - SSH_OPTIONS_IDENTITY_AGENT
722
 *                Set the path to the SSH agent socket. If unset, the
723
 *                SSH_AUTH_SOCK environment is consulted.
724
 *                (const char *)
725
 *
726
 *              - SSH_OPTIONS_IDENTITIES_ONLY
727
 *                Use only keys specified in the SSH config, even if agent
728
 *                offers more.
729
 *                (bool)
730
 *
731
 *              - SSH_OPTIONS_CONTROL_MASTER
732
 *                Set the option to enable the sharing of multiple sessions over a
733
 *                single network connection using connection multiplexing (int).
734
 *
735
 *                The possible options are among the following:
736
 *                 - SSH_CONTROL_MASTER_AUTO: enable connection sharing if possible
737
 *                 - SSH_CONTROL_MASTER_YES: enable connection sharing unconditionally
738
 *                 - SSH_CONTROL_MASTER_ASK: ask for confirmation if connection sharing is to be enabled
739
 *                 - SSH_CONTROL_MASTER_AUTOASK: enable connection sharing if possible,
740
 *                                               but ask for confirmation
741
 *                 - SSH_CONTROL_MASTER_NO: disable connection sharing unconditionally
742
 *
743
 *                The default is SSH_CONTROL_MASTER_NO.
744
 *
745
 *              - SSH_OPTIONS_CONTROL_PATH
746
 *                Set the path to the control socket used for connection sharing.
747
 *                Set to "none" to disable connection sharing.
748
 *                (const char *)
749
 *
750
 *              - SSH_OPTIONS_PKI_CONTEXT
751
 *                Attach a previously created generic PKI context to the
752
 *                session. This allows supplying per-session PKI
753
 *                configuration options for PKI operations.
754
 *                All fields from the user's context are copied to the session's
755
 *                own context. The user retains ownership of the original
756
 *                context and can free it after this call.
757
 *                (ssh_pki_ctx)
758
 *
759
 *              - SSH_OPTIONS_ADDRESS_FAMILY
760
 *                Specify which address family to use when connecting.
761
 *
762
 *                Possible options:
763
 *                 - SSH_ADDRESS_FAMILY_ANY: use any address family
764
 *                 - SSH_ADDRESS_FAMILY_INET: IPv4 only
765
 *                 - SSH_ADDRESS_FAMILY_INET6: IPv6 only
766
 *
767
 *              - SSH_OPTIONS_PREFERRED_AUTHENTICATIONS
768
 *                Set the preferred authentication method(s) to use.
769
 *                This value is parsed from the configuration file and stored
770
 *                for the calling application to read; libssh does not
771
 *                automatically reorder authentication methods based on this
772
 *                setting.
773
 *                (string)
774
 *
775
 *              - SSH_OPTIONS_BATCH_MODE
776
 *                If set to true, indicates that the application is running
777
 *                non-interactively and must not prompt the user. The
778
 *                application is responsible for skipping password
779
 *                authentication and keyboard-interactive authentication,
780
 *                and for returning failure from passphrase callbacks instead
781
 *                of prompting the user. Use ssh_options_get_int() with
782
 *                SSH_OPTIONS_BATCH_MODE to read back this value after
783
 *                parsing a configuration file.
784
 *                Note that this value is parsed from the configuration file
785
 *                and stored for the calling application to read; libssh does
786
 *                not automatically change its behavior based on this setting.
787
 *                (bool)
788
 *
789
 *              - SSH_OPTIONS_NUMBER_OF_PASSWORD_PROMPTS
790
 *                Set the maximum number of password prompts before giving up.
791
 *                OpenSSH default is 3. The value must be a positive integer
792
 *                (>= 1). Passing NULL or a value <= 0 is rejected.
793
 *                When read via ssh_options_get_int(), 0 means "not configured"
794
 *                and the CLI will use the default of 3.
795
 *                Note that this value is parsed from the configuration file
796
 *                and stored for the calling application to read; libssh does
797
 *                not automatically limit password prompts based on this setting.
798
 *                (int)
799
 *
800
 *              - SSH_OPTIONS_REQUEST_TTY
801
 *                Set whether to request a pseudo-terminal for the session.
802
 *                Accepted values are SSH_REQUEST_TTY_NO (never),
803
 *                SSH_REQUEST_TTY_YES (always),
804
 *                SSH_REQUEST_TTY_AUTO (request on login),
805
 *                and SSH_REQUEST_TTY_FORCE (always, even when a command is
806
 *                specified). Note that this value is parsed from the
807
 *                configuration file and stored for the calling application to
808
 *                read; libssh does not automatically request a PTY based on
809
 *                this setting.
810
 *                (int)
811
 *
812
 *              - SSH_OPTIONS_ESCAPE_CHAR
813
 *                Set the escape character for the session.
814
 *                OpenSSH default is '~'. Accepted values are -1 (none,
815
 *                escape sequences disabled) or a single byte value
816
 *                in the range 1-255 for a custom escape character.
817
 *                In the configuration file, the value may be specified
818
 *                as a single character ("~"), as "^X" notation for
819
 *                control characters ("^C" for Ctrl-C), or as "none"
820
 *                to disable escape sequences.
821
 *                Passing NULL, 0, or a value less than -1 or greater
822
 *                than 255 is rejected.
823
 *                When read via ssh_options_get_int(), 0 means "not
824
 *                configured" and the CLI will use the default of '~'.
825
 *                Note that this value is parsed from the configuration
826
 *                file and stored for the calling application to read;
827
 *                libssh does not automatically change the escape
828
 *                character based on this setting.
829
 *                (int)
830
 *              - SSH_OPTIONS_SEND_ENV
831
 *                Append one environment variable name pattern to the list of
832
 *                patterns to send to the server. Multiple calls accumulate
833
 *                patterns. If the value has a leading '-' (for example
834
 *                "-LANG"), the matching pattern is removed from the list
835
 *                instead of added. Removing a pattern that does not exist
836
 *                in the list is not an error and the existing patterns are
837
 *                not affected. To iterate the list, use SSH_OPTIONS_SEND_ENV
838
 *                followed by SSH_OPTIONS_NEXT_SEND_ENV in ssh_options_get().
839
 *                Note that this value is parsed from the configuration file
840
 *                and stored for the calling application to read; libssh does
841
 *                not automatically send environment variables based on this
842
 *                setting.
843
 *                (const char *)
844
 *
845
 *              - SSH_OPTIONS_LOCAL_FORWARD
846
 *                Append one local forwarding specification to the list.
847
 *                The format is "<bind_spec> <remote_spec>", for example,
848
 *                "8080 web:80" or "0.0.0.0:9090 db:3306". Multiple calls
849
 *                accumulate entries. To iterate the list, use
850
 *                SSH_OPTIONS_LOCAL_FORWARD followed by
851
 *                SSH_OPTIONS_NEXT_LOCAL_FORWARD in ssh_options_get().
852
 *                Note that this value is parsed from the configuration
853
 *                file and stored for the calling application to read;
854
 *                libssh does not automatically set up local forwarding
855
 *                based on this setting.
856
 *                (const char *)
857
 *
858
 * @param  value The value to set. This is a generic pointer and the
859
 *               datatype which is used should be set according to the
860
 *               type set.
861
 *
862
 * @return       0 on success, < 0 on error.
863
 *
864
 * @warning      When the option value to set is represented via a pointer
865
 *               (e.g const char * in case of strings, ssh_key in case of a
866
 *               libssh key), the value parameter should be that pointer.
867
 *               Do NOT pass a pointer to a pointer (const char **, ssh_key *)
868
 *
869
 * @warning      When the option value to set is not a pointer (e.g int,
870
 *               unsigned int, bool, long), the value parameter should be
871
 *               a pointer to the location storing the value to set (int *,
872
 *               unsigned int *, bool *, long *)
873
 *
874
 * @warning      If the value parameter has an invalid type (e.g if its not a
875
 *               pointer when it should have been a pointer, or if its a pointer
876
 *               to a pointer when it should have just been a pointer), then the
877
 *               behaviour is undefined.
878
 */
879
int ssh_options_set(ssh_session session,
880
                    enum ssh_options_e type,
881
                    const void *value)
882
70.6k
{
883
70.6k
    const char *v = NULL;
884
70.6k
    char *p = NULL, *q = NULL;
885
70.6k
    long int i;
886
70.6k
    unsigned int u;
887
70.6k
    int rc;
888
70.6k
    char **wanted_methods = session->opts.wanted_methods;
889
70.6k
    struct ssh_jump_callbacks_struct *j = NULL;
890
891
70.6k
    if (session == NULL) {
892
0
        return -1;
893
0
    }
894
895
70.6k
    switch (type) {
896
6.96k
        case SSH_OPTIONS_HOST:
897
6.96k
            v = value;
898
6.96k
            if (v == NULL || v[0] == '\0') {
899
0
                ssh_set_error_invalid(session);
900
0
                return -1;
901
6.96k
            } else {
902
6.96k
                char *username = NULL, *hostname = NULL;
903
6.96k
                char *strict_hostname = NULL;
904
6.96k
                char *normalized = NULL;
905
906
                /* Non-strict parse: reject shell metacharacters */
907
6.96k
                rc = ssh_config_parse_uri(value,
908
6.96k
                                          &username,
909
6.96k
                                          &hostname,
910
6.96k
                                          NULL,
911
6.96k
                                          true,
912
6.96k
                                          false);
913
6.96k
                if (rc != SSH_OK || hostname == NULL) {
914
83
                    SAFE_FREE(username);
915
83
                    SAFE_FREE(hostname);
916
83
                    ssh_set_error_invalid(session);
917
83
                    return -1;
918
83
                }
919
920
                /* Non-strict passed: set username and originalhost */
921
6.88k
                if (username != NULL) {
922
18
                    SAFE_FREE(session->opts.username);
923
18
                    session->opts.username = username;
924
18
                }
925
6.88k
                if (!session->opts.config_hostname_only) {
926
6.76k
                    SAFE_FREE(session->opts.config_hostname);
927
6.76k
                    SAFE_FREE(session->opts.originalhost);
928
6.76k
                    session->opts.originalhost = hostname;
929
6.76k
                } else {
930
120
                    SAFE_FREE(hostname);
931
120
                }
932
933
                /* Strict parse: set host only if valid hostname or IP */
934
6.88k
                rc = ssh_normalize_loose_ip(value, &normalized);
935
6.88k
                if (rc == -1) {
936
                    /* Error */
937
0
                    SAFE_FREE(username);
938
0
                    ssh_set_error_oom(session);
939
0
                    return -1;
940
0
                }
941
6.88k
                rc = ssh_config_parse_uri(
942
6.88k
                    (normalized != NULL) ? normalized : value,
943
6.88k
                    NULL,
944
6.88k
                    &strict_hostname,
945
6.88k
                    NULL,
946
6.88k
                    true,
947
6.88k
                    true);
948
6.88k
                SAFE_FREE(normalized);
949
950
6.88k
                if (rc != SSH_OK || strict_hostname == NULL) {
951
81
                    SAFE_FREE(session->opts.host);
952
81
                    SAFE_FREE(strict_hostname);
953
81
                    if (session->opts.config_hostname_only) {
954
                        /* Config path: Hostname must be valid */
955
81
                        ssh_set_error_invalid(session);
956
81
                        return -1;
957
81
                    }
958
6.80k
                } else {
959
6.80k
                    SAFE_FREE(session->opts.host);
960
6.80k
                    session->opts.host = strict_hostname;
961
6.80k
                }
962
6.88k
            }
963
6.80k
            break;
964
6.80k
        case SSH_OPTIONS_PORT:
965
4
            if (value == NULL) {
966
0
                ssh_set_error_invalid(session);
967
0
                return -1;
968
4
            } else {
969
4
                int *x = (int *) value;
970
4
                if (*x <= 0 || *x > 65535) {
971
0
                    ssh_set_error_invalid(session);
972
0
                    return -1;
973
0
                }
974
975
4
                session->opts.port = *x;
976
4
            }
977
4
            break;
978
4
        case SSH_OPTIONS_PORT_STR:
979
0
            v = value;
980
0
            if (v == NULL || v[0] == '\0') {
981
0
                ssh_set_error_invalid(session);
982
0
                return -1;
983
0
            } else {
984
0
                q = strdup(v);
985
0
                if (q == NULL) {
986
0
                    ssh_set_error_oom(session);
987
0
                    return -1;
988
0
                }
989
0
                i = strtol(q, &p, 10);
990
0
                if (q == p || *p != '\0') {
991
0
                    SSH_LOG(SSH_LOG_DEBUG, "No port number was parsed");
992
0
                    SAFE_FREE(q);
993
0
                    return -1;
994
0
                }
995
0
                SAFE_FREE(q);
996
0
                if (i <= 0 || i > 65535) {
997
0
                    ssh_set_error_invalid(session);
998
0
                    return -1;
999
0
                }
1000
1001
0
                session->opts.port = i;
1002
0
            }
1003
0
            break;
1004
5.47k
        case SSH_OPTIONS_FD:
1005
5.47k
            if (value == NULL) {
1006
0
                session->opts.fd = SSH_INVALID_SOCKET;
1007
0
                ssh_set_error_invalid(session);
1008
0
                return -1;
1009
5.47k
            } else {
1010
5.47k
                socket_t *x = (socket_t *) value;
1011
5.47k
                if (*x < 0) {
1012
0
                    session->opts.fd = SSH_INVALID_SOCKET;
1013
0
                    ssh_set_error_invalid(session);
1014
0
                    return -1;
1015
0
                }
1016
1017
5.47k
                session->opts.fd = *x & 0xffff;
1018
5.47k
            }
1019
5.47k
            break;
1020
5.47k
        case SSH_OPTIONS_BINDADDR:
1021
12
            v = value;
1022
12
            if (v == NULL || v[0] == '\0') {
1023
0
                ssh_set_error_invalid(session);
1024
0
                return -1;
1025
0
            }
1026
1027
12
            q = strdup(v);
1028
12
            if (q == NULL) {
1029
0
                return -1;
1030
0
            }
1031
12
            SAFE_FREE(session->opts.bindaddr);
1032
12
            session->opts.bindaddr = q;
1033
12
            break;
1034
5.55k
        case SSH_OPTIONS_USER:
1035
5.55k
            v = value;
1036
5.55k
            SAFE_FREE(session->opts.username);
1037
5.55k
            if (v == NULL) {
1038
0
                q = ssh_get_local_username();
1039
0
                if (q == NULL) {
1040
0
                    ssh_set_error_oom(session);
1041
0
                    return -1;
1042
0
                }
1043
0
                session->opts.username = q;
1044
5.55k
            } else if (v[0] == '\0') {
1045
0
                ssh_set_error_invalid(session);
1046
0
                return -1;
1047
5.55k
            } else { /* username provided */
1048
5.55k
                session->opts.username = strdup(value);
1049
5.55k
                if (session->opts.username == NULL) {
1050
0
                    ssh_set_error_oom(session);
1051
0
                    return -1;
1052
0
                }
1053
5.55k
                rc = ssh_check_username_syntax(session->opts.username);
1054
5.55k
                if (rc != SSH_OK) {
1055
37
                    ssh_set_error_invalid(session);
1056
37
                    return -1;
1057
37
                }
1058
5.55k
            }
1059
5.51k
            break;
1060
6.76k
        case SSH_OPTIONS_SSH_DIR:
1061
6.76k
            v = value;
1062
6.76k
            SAFE_FREE(session->opts.sshdir);
1063
6.76k
            if (v == NULL) {
1064
6.76k
                session->opts.sshdir = ssh_path_expand_tilde("~/.ssh");
1065
6.76k
                if (session->opts.sshdir == NULL) {
1066
0
                    return -1;
1067
0
                }
1068
6.76k
            } else if (v[0] == '\0') {
1069
0
                ssh_set_error_invalid(session);
1070
0
                return -1;
1071
0
            } else {
1072
0
                session->opts.sshdir = ssh_path_expand_tilde(v);
1073
0
                if (session->opts.sshdir == NULL) {
1074
0
                    ssh_set_error_oom(session);
1075
0
                    return -1;
1076
0
                }
1077
0
            }
1078
6.76k
            break;
1079
6.76k
        case SSH_OPTIONS_IDENTITY:
1080
933
        case SSH_OPTIONS_ADD_IDENTITY:
1081
933
            v = value;
1082
933
            if (v == NULL || v[0] == '\0') {
1083
0
                ssh_set_error_invalid(session);
1084
0
                return -1;
1085
0
            }
1086
933
            q = strdup(v);
1087
933
            if (q == NULL) {
1088
0
                return -1;
1089
0
            }
1090
933
            if (session->opts.exp_flags & SSH_OPT_EXP_FLAG_IDENTITY) {
1091
0
                rc = ssh_list_append(session->opts.identity_non_exp, q);
1092
933
            } else {
1093
933
                rc = ssh_list_prepend(session->opts.identity_non_exp, q);
1094
933
            }
1095
933
            if (rc < 0) {
1096
0
                free(q);
1097
0
                return -1;
1098
0
            }
1099
933
            break;
1100
1.39k
        case SSH_OPTIONS_CERTIFICATE:
1101
1.39k
            v = value;
1102
1.39k
            if (v == NULL || v[0] == '\0') {
1103
0
                ssh_set_error_invalid(session);
1104
0
                return -1;
1105
0
            }
1106
1.39k
            q = strdup(v);
1107
1.39k
            if (q == NULL) {
1108
0
                return -1;
1109
0
            }
1110
1.39k
            rc = ssh_list_append(session->opts.certificate_non_exp, q);
1111
1.39k
            if (rc < 0) {
1112
0
                free(q);
1113
0
                return -1;
1114
0
            }
1115
1.39k
            break;
1116
1.39k
        case SSH_OPTIONS_KNOWNHOSTS:
1117
4
            v = value;
1118
4
            SAFE_FREE(session->opts.knownhosts);
1119
4
            if (v == NULL) {
1120
                /* The default value will be set by the ssh_options_apply() */
1121
4
            } else if (v[0] == '\0') {
1122
0
                ssh_set_error_invalid(session);
1123
0
                return -1;
1124
4
            } else {
1125
4
                session->opts.knownhosts = strdup(v);
1126
4
                if (session->opts.knownhosts == NULL) {
1127
0
                    ssh_set_error_oom(session);
1128
0
                    return -1;
1129
0
                }
1130
4
                session->opts.exp_flags &= ~SSH_OPT_EXP_FLAG_KNOWNHOSTS;
1131
4
            }
1132
4
            break;
1133
6
        case SSH_OPTIONS_GLOBAL_KNOWNHOSTS:
1134
6
            v = value;
1135
6
            SAFE_FREE(session->opts.global_knownhosts);
1136
6
            if (v == NULL) {
1137
0
                session->opts.global_knownhosts =
1138
0
                    strdup(GLOBAL_CONF_DIR "/ssh_known_hosts");
1139
0
                if (session->opts.global_knownhosts == NULL) {
1140
0
                    ssh_set_error_oom(session);
1141
0
                    return -1;
1142
0
                }
1143
6
            } else if (v[0] == '\0') {
1144
0
                ssh_set_error_invalid(session);
1145
0
                return -1;
1146
6
            } else {
1147
6
                session->opts.global_knownhosts = strdup(v);
1148
6
                if (session->opts.global_knownhosts == NULL) {
1149
0
                    ssh_set_error_oom(session);
1150
0
                    return -1;
1151
0
                }
1152
6
                session->opts.exp_flags &= ~SSH_OPT_EXP_FLAG_GLOBAL_KNOWNHOSTS;
1153
6
            }
1154
6
            break;
1155
5.75k
        case SSH_OPTIONS_TIMEOUT:
1156
5.75k
            if (value == NULL) {
1157
0
                ssh_set_error_invalid(session);
1158
0
                return -1;
1159
5.75k
            } else {
1160
5.75k
                long *x = (long *) value;
1161
5.75k
                if (*x < 0) {
1162
0
                    ssh_set_error_invalid(session);
1163
0
                    return -1;
1164
0
                }
1165
1166
5.75k
                session->opts.timeout = *x & 0xffffffffU;
1167
5.75k
            }
1168
5.75k
            break;
1169
5.75k
        case SSH_OPTIONS_TIMEOUT_USEC:
1170
0
            if (value == NULL) {
1171
0
                ssh_set_error_invalid(session);
1172
0
                return -1;
1173
0
            } else {
1174
0
                long *x = (long *) value;
1175
0
                if (*x < 0) {
1176
0
                    ssh_set_error_invalid(session);
1177
0
                    return -1;
1178
0
                }
1179
1180
0
                session->opts.timeout_usec = *x & 0xffffffffU;
1181
0
            }
1182
0
            break;
1183
0
        case SSH_OPTIONS_SSH1:
1184
0
            break;
1185
0
        case SSH_OPTIONS_SSH2:
1186
0
            break;
1187
4
        case SSH_OPTIONS_LOG_VERBOSITY:
1188
4
            if (value == NULL) {
1189
0
                ssh_set_error_invalid(session);
1190
0
                return -1;
1191
4
            } else {
1192
4
                int *x = (int *) value;
1193
4
                if (*x < 0) {
1194
0
                    ssh_set_error_invalid(session);
1195
0
                    return -1;
1196
0
                }
1197
1198
4
                session->common.log_verbosity = *x & 0xffffU;
1199
4
                ssh_set_log_level(*x & 0xffffU);
1200
4
            }
1201
4
            break;
1202
4
        case SSH_OPTIONS_LOG_VERBOSITY_STR:
1203
0
            v = value;
1204
0
            if (v == NULL || v[0] == '\0') {
1205
0
                session->common.log_verbosity = 0;
1206
0
                ssh_set_error_invalid(session);
1207
0
                return -1;
1208
0
            } else {
1209
0
                q = strdup(v);
1210
0
                if (q == NULL) {
1211
0
                    ssh_set_error_oom(session);
1212
0
                    return -1;
1213
0
                }
1214
0
                i = strtol(q, &p, 10);
1215
0
                if (q == p) {
1216
0
                    SSH_LOG(SSH_LOG_DEBUG, "No log verbositiy was parsed");
1217
0
                    SAFE_FREE(q);
1218
0
                    return -1;
1219
0
                }
1220
0
                SAFE_FREE(q);
1221
0
                if (i < 0) {
1222
0
                    ssh_set_error_invalid(session);
1223
0
                    return -1;
1224
0
                }
1225
1226
0
                session->common.log_verbosity = i & 0xffffU;
1227
0
                ssh_set_log_level(i & 0xffffU);
1228
0
            }
1229
0
            break;
1230
5.52k
        case SSH_OPTIONS_CIPHERS_C_S:
1231
5.52k
            v = value;
1232
5.52k
            if (v == NULL || v[0] == '\0') {
1233
0
                ssh_set_error_invalid(session);
1234
0
                return -1;
1235
5.52k
            } else {
1236
5.52k
                rc = ssh_options_set_algo(session,
1237
5.52k
                                          SSH_CRYPT_C_S,
1238
5.52k
                                          v,
1239
5.52k
                                          &wanted_methods[SSH_CRYPT_C_S]);
1240
5.52k
                if (rc < 0)
1241
9
                    return -1;
1242
5.52k
            }
1243
5.51k
            break;
1244
5.52k
        case SSH_OPTIONS_CIPHERS_S_C:
1245
5.52k
            v = value;
1246
5.52k
            if (v == NULL || v[0] == '\0') {
1247
0
                ssh_set_error_invalid(session);
1248
0
                return -1;
1249
5.52k
            } else {
1250
5.52k
                rc = ssh_options_set_algo(session,
1251
5.52k
                                          SSH_CRYPT_S_C,
1252
5.52k
                                          v,
1253
5.52k
                                          &wanted_methods[SSH_CRYPT_S_C]);
1254
5.52k
                if (rc < 0)
1255
9
                    return -1;
1256
5.52k
            }
1257
5.51k
            break;
1258
5.51k
        case SSH_OPTIONS_KEY_EXCHANGE:
1259
93
            v = value;
1260
93
            if (v == NULL || v[0] == '\0') {
1261
0
                ssh_set_error_invalid(session);
1262
0
                return -1;
1263
93
            } else {
1264
93
                rc = ssh_options_set_algo(session,
1265
93
                                          SSH_KEX,
1266
93
                                          v,
1267
93
                                          &wanted_methods[SSH_KEX]);
1268
93
                if (rc < 0)
1269
19
                    return -1;
1270
93
            }
1271
74
            break;
1272
74
        case SSH_OPTIONS_HOSTKEYS:
1273
29
            v = value;
1274
29
            if (v == NULL || v[0] == '\0') {
1275
0
                ssh_set_error_invalid(session);
1276
0
                return -1;
1277
29
            } else {
1278
29
                rc = ssh_options_set_algo(session,
1279
29
                                          SSH_HOSTKEYS,
1280
29
                                          v,
1281
29
                                          &wanted_methods[SSH_HOSTKEYS]);
1282
29
                if (rc < 0)
1283
17
                    return -1;
1284
29
            }
1285
12
            break;
1286
75
        case SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES:
1287
75
            v = value;
1288
75
            if (v == NULL || v[0] == '\0') {
1289
0
                ssh_set_error_invalid(session);
1290
0
                return -1;
1291
75
            } else {
1292
75
                rc = ssh_options_set_algo(session,
1293
75
                                          SSH_HOSTKEYS,
1294
75
                                          v,
1295
75
                                          &session->opts.pubkey_accepted_types);
1296
75
                if (rc < 0)
1297
17
                    return -1;
1298
75
            }
1299
58
            break;
1300
5.78k
        case SSH_OPTIONS_HMAC_C_S:
1301
5.78k
            v = value;
1302
5.78k
            if (v == NULL || v[0] == '\0') {
1303
0
                ssh_set_error_invalid(session);
1304
0
                return -1;
1305
5.78k
            } else {
1306
5.78k
                rc = ssh_options_set_algo(session,
1307
5.78k
                                          SSH_MAC_C_S,
1308
5.78k
                                          v,
1309
5.78k
                                          &wanted_methods[SSH_MAC_C_S]);
1310
5.78k
                if (rc < 0)
1311
52
                    return -1;
1312
5.78k
            }
1313
5.73k
            break;
1314
5.78k
         case SSH_OPTIONS_HMAC_S_C:
1315
5.78k
            v = value;
1316
5.78k
            if (v == NULL || v[0] == '\0') {
1317
0
                ssh_set_error_invalid(session);
1318
0
                return -1;
1319
5.78k
            } else {
1320
5.78k
                rc = ssh_options_set_algo(session,
1321
5.78k
                                          SSH_MAC_S_C,
1322
5.78k
                                          v,
1323
5.78k
                                          &wanted_methods[SSH_MAC_S_C]);
1324
5.78k
                if (rc < 0)
1325
52
                    return -1;
1326
5.78k
            }
1327
5.73k
            break;
1328
5.73k
        case SSH_OPTIONS_COMPRESSION_C_S:
1329
5
            v = value;
1330
5
            if (v == NULL || v[0] == '\0') {
1331
0
                ssh_set_error_invalid(session);
1332
0
                return -1;
1333
5
            } else {
1334
5
                const char *tmp = v;
1335
5
                if (strcasecmp(value, "yes") == 0){
1336
0
                    tmp = "zlib@openssh.com,none";
1337
5
                } else if (strcasecmp(value, "no") == 0){
1338
5
                    tmp = "none,zlib@openssh.com";
1339
5
                }
1340
5
                rc = ssh_options_set_algo(session,
1341
5
                                          SSH_COMP_C_S,
1342
5
                                          tmp,
1343
5
                                          &wanted_methods[SSH_COMP_C_S]);
1344
5
                if (rc < 0)
1345
0
                    return -1;
1346
5
            }
1347
5
            break;
1348
5
        case SSH_OPTIONS_COMPRESSION_S_C:
1349
5
            v = value;
1350
5
            if (v == NULL || v[0] == '\0') {
1351
0
                ssh_set_error_invalid(session);
1352
0
                return -1;
1353
5
            } else {
1354
5
                const char *tmp = v;
1355
5
                if (strcasecmp(value, "yes") == 0){
1356
0
                    tmp = "zlib@openssh.com,none";
1357
5
                } else if (strcasecmp(value, "no") == 0){
1358
5
                    tmp = "none,zlib@openssh.com";
1359
5
                }
1360
1361
5
                rc = ssh_options_set_algo(session,
1362
5
                                          SSH_COMP_S_C,
1363
5
                                          tmp,
1364
5
                                          &wanted_methods[SSH_COMP_S_C]);
1365
5
                if (rc < 0)
1366
0
                    return -1;
1367
5
            }
1368
5
            break;
1369
5
        case SSH_OPTIONS_COMPRESSION:
1370
5
            v = value;
1371
5
            if (v == NULL || v[0] == '\0') {
1372
0
                ssh_set_error_invalid(session);
1373
0
                return -1;
1374
0
            }
1375
5
            if(ssh_options_set(session,SSH_OPTIONS_COMPRESSION_C_S, v) < 0)
1376
0
                return -1;
1377
5
            if(ssh_options_set(session,SSH_OPTIONS_COMPRESSION_S_C, v) < 0)
1378
0
                return -1;
1379
5
            break;
1380
5
        case SSH_OPTIONS_COMPRESSION_LEVEL:
1381
0
            if (value == NULL) {
1382
0
                ssh_set_error_invalid(session);
1383
0
                return -1;
1384
0
            } else {
1385
0
                int *x = (int *)value;
1386
0
                if (*x < 1 || *x > 9) {
1387
0
                    ssh_set_error_invalid(session);
1388
0
                    return -1;
1389
0
                }
1390
0
                session->opts.compressionlevel = *x & 0xff;
1391
0
            }
1392
0
            break;
1393
0
        case SSH_OPTIONS_STRICTHOSTKEYCHECK:
1394
0
            if (value == NULL) {
1395
0
                ssh_set_error_invalid(session);
1396
0
                return -1;
1397
0
            } else {
1398
0
                int *x = (int *) value;
1399
0
                int mode = *x;
1400
1401
0
                switch (mode) {
1402
0
                case SSH_STRICT_HOSTKEY_OFF:
1403
0
                case SSH_STRICT_HOSTKEY_YES:
1404
0
                case SSH_STRICT_HOSTKEY_ASK:
1405
0
                case SSH_STRICT_HOSTKEY_ACCEPT_NEW:
1406
0
                    session->opts.StrictHostKeyChecking = mode;
1407
0
                    break;
1408
0
                default:
1409
                    /* Preserve the legacy low-byte "non-zero means yes"
1410
                     * normalization.
1411
                     */
1412
0
                    session->opts.StrictHostKeyChecking =
1413
0
                        (mode & 0xff) > 0 ? SSH_STRICT_HOSTKEY_YES
1414
0
                                          : SSH_STRICT_HOSTKEY_OFF;
1415
0
                    break;
1416
0
                }
1417
0
            }
1418
0
            break;
1419
27
        case SSH_OPTIONS_PROXYCOMMAND:
1420
27
            v = value;
1421
27
            if (v == NULL || v[0] == '\0') {
1422
10
                ssh_set_error_invalid(session);
1423
10
                return -1;
1424
17
            } else {
1425
17
                SAFE_FREE(session->opts.ProxyCommand);
1426
                /* Setting the command to 'none' disables this option. */
1427
17
                rc = strcasecmp(v, "none");
1428
17
                if (rc != 0) {
1429
17
                    q = strdup(v);
1430
17
                    if (q == NULL) {
1431
0
                        return -1;
1432
0
                    }
1433
17
                    session->opts.ProxyCommand = q;
1434
17
                    session->opts.exp_flags &= ~SSH_OPT_EXP_FLAG_PROXYCOMMAND;
1435
17
                }
1436
17
            }
1437
17
            break;
1438
17
        case SSH_OPTIONS_PROXYJUMP:
1439
0
            v = value;
1440
0
            if (v == NULL || v[0] == '\0') {
1441
0
                ssh_set_error_invalid(session);
1442
0
                return -1;
1443
0
            } else {
1444
0
                rc = ssh_config_parse_proxy_jump(session, v, true);
1445
0
                if (rc != SSH_OK) {
1446
0
                    return SSH_ERROR;
1447
0
                }
1448
0
            }
1449
0
            break;
1450
0
        case SSH_OPTIONS_PROXYJUMP_CB_LIST_APPEND:
1451
0
            j = (struct ssh_jump_callbacks_struct *)value;
1452
0
            if (j == NULL) {
1453
0
                ssh_set_error_invalid(session);
1454
0
                return -1;
1455
0
            } else {
1456
0
                rc = ssh_list_prepend(session->opts.proxy_jumps_user_cb, j);
1457
0
                if (rc != SSH_OK) {
1458
0
                    ssh_set_error_oom(session);
1459
0
                    return SSH_ERROR;
1460
0
                }
1461
0
            }
1462
0
            break;
1463
6
        case SSH_OPTIONS_GSSAPI_SERVER_IDENTITY:
1464
6
            v = value;
1465
6
            if (v == NULL || v[0] == '\0') {
1466
0
                ssh_set_error_invalid(session);
1467
0
                return -1;
1468
6
            } else {
1469
6
                SAFE_FREE(session->opts.gss_server_identity);
1470
6
                session->opts.gss_server_identity = strdup(v);
1471
6
                if (session->opts.gss_server_identity == NULL) {
1472
0
                    ssh_set_error_oom(session);
1473
0
                    return -1;
1474
0
                }
1475
6
            }
1476
6
            break;
1477
13
        case SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY:
1478
13
            v = value;
1479
13
            if (v == NULL || v[0] == '\0') {
1480
0
                ssh_set_error_invalid(session);
1481
0
                return -1;
1482
13
            } else {
1483
13
                SAFE_FREE(session->opts.gss_client_identity);
1484
13
                session->opts.gss_client_identity = strdup(v);
1485
13
                if (session->opts.gss_client_identity == NULL) {
1486
0
                    ssh_set_error_oom(session);
1487
0
                    return -1;
1488
0
                }
1489
13
            }
1490
13
            break;
1491
13
        case SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS:
1492
0
            if (value == NULL) {
1493
0
                ssh_set_error_invalid(session);
1494
0
                return -1;
1495
0
            } else {
1496
0
                int x = *(int *)value;
1497
1498
0
                session->opts.gss_delegate_creds = (x & 0xff);
1499
0
            }
1500
0
            break;
1501
#ifdef WITH_GSSAPI
1502
        case SSH_OPTIONS_GSSAPI_KEY_EXCHANGE:
1503
            if (value == NULL) {
1504
                ssh_set_error_invalid(session);
1505
                return -1;
1506
            } else {
1507
                bool *x = (bool *)value;
1508
                session->opts.gssapi_key_exchange = *x;
1509
            }
1510
            break;
1511
        case SSH_OPTIONS_GSSAPI_KEY_EXCHANGE_ALGS:
1512
            v = value;
1513
            if (v == NULL || v[0] == '\0') {
1514
                ssh_set_error_invalid(session);
1515
                return -1;
1516
            } else {
1517
                /* Check if algorithms are supported */
1518
                char *ret =
1519
                    ssh_find_all_matching(GSSAPI_KEY_EXCHANGE_SUPPORTED, v);
1520
                if (ret == NULL) {
1521
                    ssh_set_error(session,
1522
                                  SSH_FATAL,
1523
                                  "GSSAPI key exchange algorithms not "
1524
                                  "supported or invalid");
1525
                    return -1;
1526
                }
1527
                SAFE_FREE(session->opts.gssapi_key_exchange_algs);
1528
                session->opts.gssapi_key_exchange_algs = ret;
1529
            }
1530
            break;
1531
#endif
1532
0
        case SSH_OPTIONS_PASSWORD_AUTH:
1533
0
        case SSH_OPTIONS_PUBKEY_AUTH:
1534
0
        case SSH_OPTIONS_KBDINT_AUTH:
1535
0
        case SSH_OPTIONS_GSSAPI_AUTH:
1536
0
            if (value == NULL) {
1537
0
                ssh_set_error_invalid(session);
1538
0
                return -1;
1539
0
            } else {
1540
0
                int x = *(int *)value;
1541
0
                u = type == SSH_OPTIONS_PASSWORD_AUTH ?
1542
0
                    SSH_OPT_FLAG_PASSWORD_AUTH:
1543
0
                    type == SSH_OPTIONS_PUBKEY_AUTH ?
1544
0
                        SSH_OPT_FLAG_PUBKEY_AUTH:
1545
0
                        type == SSH_OPTIONS_KBDINT_AUTH ?
1546
0
                            SSH_OPT_FLAG_KBDINT_AUTH:
1547
0
                            SSH_OPT_FLAG_GSSAPI_AUTH;
1548
0
                if (x != 0) {
1549
0
                    session->opts.flags |= u;
1550
0
                } else {
1551
0
                    session->opts.flags &= ~u;
1552
0
                }
1553
0
                if (type == SSH_OPTIONS_PUBKEY_AUTH) {
1554
                    /*
1555
                     * Keep the legacy enabled/disabled auth flag semantics in
1556
                     * sync above while also storing the selected
1557
                     * PubkeyAuthentication mode here.
1558
                     */
1559
0
                    switch (x) {
1560
0
                    case SSH_PUBKEY_AUTH_NO:
1561
0
                    case SSH_PUBKEY_AUTH_ALL:
1562
0
                    case SSH_PUBKEY_AUTH_UNBOUND:
1563
0
                    case SSH_PUBKEY_AUTH_HOST_BOUND:
1564
0
                        session->opts.pubkey_auth = x;
1565
0
                        break;
1566
0
                    default:
1567
                        /* Preserve the legacy non-zero "yes" normalization
1568
                         * here so callers passing -1 still land on
1569
                         * SSH_PUBKEY_AUTH_ALL.
1570
                         */
1571
0
                        session->opts.pubkey_auth = SSH_PUBKEY_AUTH_ALL;
1572
0
                        break;
1573
0
                    }
1574
0
                }
1575
0
            }
1576
0
            break;
1577
0
        case SSH_OPTIONS_NODELAY:
1578
0
            if (value == NULL) {
1579
0
                ssh_set_error_invalid(session);
1580
0
                return -1;
1581
0
            } else {
1582
0
                int *x = (int *) value;
1583
0
                session->opts.nodelay = (*x & 0xff) > 0 ? 1 : 0;
1584
0
            }
1585
0
            break;
1586
5.47k
        case SSH_OPTIONS_PROCESS_CONFIG:
1587
5.47k
            if (value == NULL) {
1588
0
                ssh_set_error_invalid(session);
1589
0
                return -1;
1590
5.47k
            } else {
1591
5.47k
                bool *x = (bool *)value;
1592
5.47k
                session->opts.config_processed = !(*x);
1593
5.47k
            }
1594
5.47k
            break;
1595
5.47k
        case SSH_OPTIONS_REKEY_DATA:
1596
220
            if (value == NULL) {
1597
0
                ssh_set_error_invalid(session);
1598
0
                return -1;
1599
220
            } else {
1600
220
                uint64_t *x = (uint64_t *)value;
1601
220
                session->opts.rekey_data = *x;
1602
220
            }
1603
220
            break;
1604
220
        case SSH_OPTIONS_REKEY_TIME:
1605
100
            if (value == NULL) {
1606
0
                ssh_set_error_invalid(session);
1607
0
                return -1;
1608
100
            } else {
1609
100
                uint32_t *x = (uint32_t *)value;
1610
100
                if ((*x * 1000) < *x) {
1611
24
                    ssh_set_error(session, SSH_REQUEST_DENIED,
1612
24
                                  "The provided value (%" PRIu32 ") for rekey"
1613
24
                                  " time is too large", *x);
1614
24
                    return -1;
1615
24
                }
1616
76
                session->opts.rekey_time = (*x) * 1000;
1617
76
            }
1618
76
            break;
1619
76
        case SSH_OPTIONS_RSA_MIN_SIZE:
1620
8
            if (value == NULL) {
1621
0
                ssh_set_error_invalid(session);
1622
0
                return -1;
1623
8
            } else {
1624
8
                int *x = (int *)value;
1625
1626
8
                if (*x < 0) {
1627
0
                    ssh_set_error_invalid(session);
1628
0
                    return -1;
1629
0
                }
1630
1631
                /* (*x == 0) is allowed as it is used to revert to default */
1632
1633
8
                if (*x > 0 && *x < RSA_MIN_KEY_SIZE) {
1634
2
                    ssh_set_error(session,
1635
2
                                  SSH_REQUEST_DENIED,
1636
2
                                  "The provided value (%d) for minimal RSA key "
1637
2
                                  "size is too small. Use at least %d bits.",
1638
2
                                  *x,
1639
2
                                  RSA_MIN_KEY_SIZE);
1640
2
                    return -1;
1641
2
                }
1642
6
                session->opts.rsa_min_size = *x;
1643
6
            }
1644
6
            break;
1645
14
        case SSH_OPTIONS_IDENTITY_AGENT:
1646
14
            v = value;
1647
14
            SAFE_FREE(session->opts.agent_socket);
1648
14
            if (v == NULL) {
1649
                /* The default value will be set by the ssh_options_apply() */
1650
14
            } else if (v[0] == '\0') {
1651
0
                ssh_set_error_invalid(session);
1652
0
                return -1;
1653
14
            } else {
1654
14
                session->opts.agent_socket = ssh_path_expand_tilde(v);
1655
14
                if (session->opts.agent_socket == NULL) {
1656
0
                    ssh_set_error_oom(session);
1657
0
                    return -1;
1658
0
                }
1659
14
            }
1660
14
            break;
1661
14
        case SSH_OPTIONS_IDENTITIES_ONLY:
1662
1
            if (value == NULL) {
1663
0
                ssh_set_error_invalid(session);
1664
0
                return -1;
1665
1
            } else {
1666
1
                bool *x = (bool *)value;
1667
1
                session->opts.identities_only = *x;
1668
1
            }
1669
1
            break;
1670
1
        case SSH_OPTIONS_CONTROL_MASTER:
1671
0
            if (value == NULL) {
1672
0
                ssh_set_error_invalid(session);
1673
0
                return -1;
1674
0
            } else {
1675
0
                int *x = (int *) value;
1676
0
                if (*x < SSH_CONTROL_MASTER_NO || *x > SSH_CONTROL_MASTER_AUTOASK) {
1677
0
                    ssh_set_error_invalid(session);
1678
0
                    return -1;
1679
0
                }
1680
0
                session->opts.control_master = *x;
1681
0
            }
1682
0
            break;
1683
0
        case SSH_OPTIONS_CONTROL_PATH:
1684
0
            v = value;
1685
0
            if (v == NULL || v[0] == '\0') {
1686
0
                ssh_set_error_invalid(session);
1687
0
                return -1;
1688
0
            } else {
1689
0
                SAFE_FREE(session->opts.control_path);
1690
0
                rc = strcasecmp(v, "none");
1691
0
                if (rc != 0) {
1692
0
                    session->opts.control_path = ssh_path_expand_tilde(v);
1693
0
                    if (session->opts.control_path == NULL) {
1694
0
                        ssh_set_error_oom(session);
1695
0
                        return -1;
1696
0
                    }
1697
0
                    session->opts.exp_flags &= ~SSH_OPT_EXP_FLAG_CONTROL_PATH;
1698
0
                }
1699
0
            }
1700
0
            break;
1701
0
        case SSH_OPTIONS_PKI_CONTEXT:
1702
0
            if (value == NULL) {
1703
0
                ssh_set_error_invalid(session);
1704
0
                return -1;
1705
0
            }
1706
1707
0
            SSH_PKI_CTX_FREE(session->pki_context);
1708
1709
0
            session->pki_context = ssh_pki_ctx_dup((const ssh_pki_ctx)value);
1710
0
            if (session->pki_context == NULL) {
1711
0
                ssh_set_error_oom(session);
1712
0
                return -1;
1713
0
            }
1714
0
            break;
1715
1
        case SSH_OPTIONS_ADDRESS_FAMILY:
1716
1
            if (value == NULL) {
1717
0
                ssh_set_error_invalid(session);
1718
0
                return -1;
1719
1
            } else {
1720
1
                int *x = (int *)value;
1721
1
                if (*x < SSH_ADDRESS_FAMILY_ANY ||
1722
1
                    *x > SSH_ADDRESS_FAMILY_INET6) {
1723
0
                    ssh_set_error_invalid(session);
1724
0
                    return -1;
1725
0
                }
1726
1
                session->opts.address_family = *x;
1727
1
            }
1728
1
            break;
1729
1
        case SSH_OPTIONS_BATCH_MODE:
1730
0
            if (value == NULL) {
1731
0
                ssh_set_error_invalid(session);
1732
0
                return -1;
1733
0
            } else {
1734
0
                bool *x = (bool *)value;
1735
0
                session->opts.batch_mode = *x;
1736
0
            }
1737
0
            break;
1738
1
        case SSH_OPTIONS_ESCAPE_CHAR:
1739
1
            if (value == NULL) {
1740
0
                ssh_set_error_invalid(session);
1741
0
                return -1;
1742
1
            } else {
1743
1
                int *x = (int *)value;
1744
1
                if (*x == 0 || *x < -1 || *x > 255) {
1745
0
                    ssh_set_error_invalid(session);
1746
0
                    return -1;
1747
0
                }
1748
1
                session->opts.escape_char = *x;
1749
1
            }
1750
1
            break;
1751
283
        case SSH_OPTIONS_LOCAL_FORWARD:
1752
283
            v = value;
1753
283
            if (v == NULL || v[0] == '\0') {
1754
0
                ssh_set_error_invalid(session);
1755
0
                return -1;
1756
0
            }
1757
283
            q = strdup(v);
1758
283
            if (q == NULL) {
1759
0
                ssh_set_error_oom(session);
1760
0
                return -1;
1761
0
            }
1762
283
            rc = ssh_list_append(session->opts.local_forward, q);
1763
283
            if (rc < 0) {
1764
0
                free(q);
1765
0
                ssh_set_error_oom(session);
1766
0
                return -1;
1767
0
            }
1768
283
            break;
1769
283
        case SSH_OPTIONS_PREFERRED_AUTHENTICATIONS:
1770
4
            v = value;
1771
4
            SAFE_FREE(session->opts.preferred_authentications);
1772
4
            if (v != NULL) {
1773
4
                if (v[0] == '\0') {
1774
0
                    ssh_set_error_invalid(session);
1775
0
                    return -1;
1776
0
                }
1777
4
                session->opts.preferred_authentications = strdup(v);
1778
4
                if (session->opts.preferred_authentications == NULL) {
1779
0
                    ssh_set_error_oom(session);
1780
0
                    return -1;
1781
0
                }
1782
4
            }
1783
4
            break;
1784
4
        case SSH_OPTIONS_NUMBER_OF_PASSWORD_PROMPTS:
1785
2
            if (value == NULL) {
1786
0
                ssh_set_error_invalid(session);
1787
0
                return -1;
1788
2
            } else {
1789
2
                int *x = (int *)value;
1790
2
                if (*x <= 0) {
1791
0
                    ssh_set_error_invalid(session);
1792
0
                    return -1;
1793
0
                }
1794
2
                session->opts.number_of_password_prompts = *x;
1795
2
            }
1796
2
            break;
1797
2
        case SSH_OPTIONS_REQUEST_TTY:
1798
0
            if (value == NULL) {
1799
0
                ssh_set_error_invalid(session);
1800
0
                return -1;
1801
0
            } else {
1802
0
                int *x = (int *)value;
1803
0
                if (*x < SSH_REQUEST_TTY_NO || *x > SSH_REQUEST_TTY_FORCE) {
1804
0
                    ssh_set_error_invalid(session);
1805
0
                    return -1;
1806
0
                }
1807
0
                session->opts.request_tty = *x;
1808
0
            }
1809
0
            break;
1810
8.75k
        case SSH_OPTIONS_SEND_ENV:
1811
8.75k
            v = value;
1812
8.75k
            if (v == NULL || v[0] == '\0') {
1813
0
                ssh_set_error_invalid(session);
1814
0
                return -1;
1815
0
            }
1816
            /* A leading '-' removes the pattern from the list */
1817
8.75k
            if (v[0] == '-') {
1818
1.44k
                const char *pattern = NULL;
1819
1.44k
                const char *env_value = NULL;
1820
1.44k
                struct ssh_iterator *it = NULL;
1821
1.44k
                struct ssh_iterator *next = NULL;
1822
1.44k
                int cmp = 0;
1823
1824
1.44k
                pattern = v + 1;
1825
1.44k
                if (pattern[0] == '\0') {
1826
298
                    ssh_set_error_invalid(session);
1827
298
                    return -1;
1828
298
                }
1829
1.14k
                it = ssh_list_get_iterator(session->opts.send_env);
1830
381k
                while (it != NULL) {
1831
380k
                    env_value = ssh_iterator_value(const char *, it);
1832
380k
                    cmp = strcmp(env_value, pattern);
1833
380k
                    next = it->next;
1834
380k
                    if (cmp == 0) {
1835
830
                        free((void *)env_value);
1836
830
                        ssh_list_remove(session->opts.send_env, it);
1837
830
                    }
1838
380k
                    it = next;
1839
380k
                }
1840
1.14k
                rc = SSH_OK;
1841
7.31k
            } else {
1842
7.31k
                q = strdup(v);
1843
7.31k
                if (q == NULL) {
1844
0
                    ssh_set_error_oom(session);
1845
0
                    return -1;
1846
0
                }
1847
7.31k
                rc = ssh_list_append(session->opts.send_env, q);
1848
7.31k
                if (rc < 0) {
1849
0
                    free(q);
1850
0
                    ssh_set_error_oom(session);
1851
0
                    return -1;
1852
0
                }
1853
7.31k
            }
1854
8.46k
            break;
1855
8.46k
        default:
1856
4
            ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
1857
4
            return -1;
1858
0
            break;
1859
70.6k
    }
1860
1861
69.9k
    return 0;
1862
70.6k
}
1863
1864
/**
1865
 * @brief This function returns the current algorithms used for algorithm
1866
 * negotiation. It is either libssh default, option manually set or option
1867
 * read from configuration file.
1868
 *
1869
 * This function will return NULL on error
1870
 *
1871
 * @param session An allocated SSH session structure.
1872
 * @param algo One of the ssh_kex_types_e values.
1873
 */
1874
char *ssh_options_get_algo(ssh_session session,
1875
                           enum ssh_kex_types_e algo)
1876
0
{
1877
0
    char *value = NULL;
1878
1879
    /* Check session and algo values are valid */
1880
1881
0
    if (session == NULL) {
1882
0
        return NULL;
1883
0
    }
1884
1885
0
    if (algo >= SSH_LANG_C_S) {
1886
0
        ssh_set_error_invalid(session);
1887
0
        return NULL;
1888
0
    }
1889
1890
    /* Get the option the user has set, if there is one */
1891
0
    value = session->opts.wanted_methods[algo];
1892
0
    if (value == NULL) {
1893
        /* The user has not set a value, return the appropriate default */
1894
0
        if (ssh_fips_mode())
1895
0
            value = (char *)ssh_kex_get_fips_methods(algo);
1896
0
        else
1897
0
            value = (char *)ssh_kex_get_default_methods(algo);
1898
0
    }
1899
1900
0
    return value;
1901
0
}
1902
1903
1904
/**
1905
 * @brief Get an integer or boolean SSH option from the session.
1906
 *
1907
 * This function is useful when the session options have been automatically
1908
 * inferred from the environment or configuration files and the application
1909
 * needs to read back an integer or boolean option value.
1910
 *
1911
 * @param  session   An allocated SSH session structure.
1912
 *
1913
 * @param  type     The option type to get. This could be one of the
1914
 *                  following:
1915
 *                  - SSH_OPTIONS_ADDRESS_FAMILY
1916
 *                  - SSH_OPTIONS_BATCH_MODE
1917
 *                  - SSH_OPTIONS_CONTROL_MASTER
1918
 *                  - SSH_OPTIONS_PORT
1919
 *                  - SSH_OPTIONS_IDENTITIES_ONLY
1920
 *                  - SSH_OPTIONS_LOG_VERBOSITY
1921
 *                  - SSH_OPTIONS_STRICTHOSTKEYCHECK
1922
 *                  - SSH_OPTIONS_NODELAY
1923
 *                  - SSH_OPTIONS_NUMBER_OF_PASSWORD_PROMPTS
1924
 *                  - SSH_OPTIONS_ESCAPE_CHAR
1925
 *                  - SSH_OPTIONS_RSA_MIN_SIZE
1926
 *                  - SSH_OPTIONS_PASSWORD_AUTH
1927
 *                  - SSH_OPTIONS_PUBKEY_AUTH
1928
 *                  - SSH_OPTIONS_KBDINT_AUTH
1929
 *                  - SSH_OPTIONS_GSSAPI_AUTH
1930
 *                  - SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS
1931
 *                  - SSH_OPTIONS_GSSAPI_KEY_EXCHANGE
1932
 *
1933
 * @param  value    A pointer to an integer to store the option value.
1934
 *
1935
 * @return          SSH_OK on success, SSH_ERROR on error.
1936
 */
1937
int ssh_options_get_int(ssh_session session,
1938
                        enum ssh_options_e type,
1939
                        int *value)
1940
0
{
1941
0
    if (session == NULL || value == NULL) {
1942
0
        return SSH_ERROR;
1943
0
    }
1944
1945
0
    switch (type) {
1946
0
    case SSH_OPTIONS_ADDRESS_FAMILY:
1947
0
        *value = session->opts.address_family;
1948
0
        break;
1949
0
    case SSH_OPTIONS_PORT:
1950
0
        *value = (session->opts.port == 0) ? 22 : (int)session->opts.port;
1951
0
        break;
1952
0
    case SSH_OPTIONS_BATCH_MODE:
1953
0
        *value = session->opts.batch_mode ? 1 : 0;
1954
0
        break;
1955
0
    case SSH_OPTIONS_NUMBER_OF_PASSWORD_PROMPTS:
1956
0
        *value = session->opts.number_of_password_prompts;
1957
0
        break;
1958
0
    case SSH_OPTIONS_REQUEST_TTY:
1959
0
        *value = session->opts.request_tty;
1960
0
        break;
1961
0
    case SSH_OPTIONS_ESCAPE_CHAR:
1962
0
        *value = session->opts.escape_char;
1963
0
        break;
1964
0
    case SSH_OPTIONS_CONTROL_MASTER:
1965
0
        *value = session->opts.control_master;
1966
0
        break;
1967
0
    case SSH_OPTIONS_IDENTITIES_ONLY:
1968
0
        *value = session->opts.identities_only ? 1 : 0;
1969
0
        break;
1970
0
    case SSH_OPTIONS_LOG_VERBOSITY:
1971
0
        *value = session->common.log_verbosity;
1972
0
        break;
1973
0
    case SSH_OPTIONS_STRICTHOSTKEYCHECK:
1974
0
        *value = session->opts.StrictHostKeyChecking;
1975
0
        break;
1976
0
    case SSH_OPTIONS_NODELAY:
1977
0
        *value = session->opts.nodelay;
1978
0
        break;
1979
0
    case SSH_OPTIONS_RSA_MIN_SIZE:
1980
0
        *value = session->opts.rsa_min_size;
1981
0
        break;
1982
0
    case SSH_OPTIONS_PASSWORD_AUTH:
1983
0
        *value = (session->opts.flags & SSH_OPT_FLAG_PASSWORD_AUTH) ? 1 : 0;
1984
0
        break;
1985
0
    case SSH_OPTIONS_PUBKEY_AUTH:
1986
0
        *value = (session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH) ? 1 : 0;
1987
0
        break;
1988
0
    case SSH_OPTIONS_KBDINT_AUTH:
1989
0
        *value = (session->opts.flags & SSH_OPT_FLAG_KBDINT_AUTH) ? 1 : 0;
1990
0
        break;
1991
0
    case SSH_OPTIONS_GSSAPI_AUTH:
1992
0
        *value = (session->opts.flags & SSH_OPT_FLAG_GSSAPI_AUTH) ? 1 : 0;
1993
0
        break;
1994
0
    case SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS:
1995
0
        *value = session->opts.gss_delegate_creds ? 1 : 0;
1996
0
        break;
1997
#ifdef WITH_GSSAPI
1998
    case SSH_OPTIONS_GSSAPI_KEY_EXCHANGE:
1999
        *value = session->opts.gssapi_key_exchange ? 1 : 0;
2000
        break;
2001
#endif
2002
0
    default:
2003
0
        ssh_set_error_invalid(session);
2004
0
        return SSH_ERROR;
2005
0
    }
2006
2007
0
    return SSH_OK;
2008
0
}
2009
2010
/**
2011
 * @brief This function returns the port number set for the SSH session.
2012
 *
2013
 * It is either the port set explicitly via ssh_options_set() or the value
2014
 * read from the configuration file. If no port has been set, the default
2015
 * port 22 is returned.
2016
 *
2017
 * @param  session      An allocated SSH session structure.
2018
 *
2019
 * @param  port_target  A pointer to an unsigned integer to store the port.
2020
 *
2021
 * @return              0 on success, < 0 on error.
2022
 */
2023
0
int ssh_options_get_port(ssh_session session, unsigned int* port_target) {
2024
0
    int value;
2025
0
    int rc;
2026
2027
0
    rc = ssh_options_get_int(session, SSH_OPTIONS_PORT, &value);
2028
0
    if (rc != SSH_OK) {
2029
0
        return -1;
2030
0
    }
2031
2032
0
    *port_target = (unsigned int)value;
2033
2034
0
    return 0;
2035
0
}
2036
2037
/**
2038
 * @brief This function can get ssh options, it does not support all options provided for
2039
 *        ssh options set, but mostly those which a user-space program may care about having
2040
 *        trusted the ssh driver to infer these values from underlying configuration files.
2041
 *        It operates only on those SSH_OPTIONS_* which return char*. If you wish to receive
2042
 *        the port then please use ssh_options_get_port() which returns an unsigned int.
2043
 *
2044
 * @param  session An allocated SSH session structure.
2045
 *
2046
 * @param  type The option type to get. This could be one of the
2047
 *              following:
2048
 *
2049
 *              - SSH_OPTIONS_HOST:
2050
 *                The hostname or ip address to connect to (const char *).
2051
 *
2052
 *              - SSH_OPTIONS_USER:
2053
 *                The username for authentication (const char *).\n
2054
 *                \n when not explicitly set this will be inferred from the
2055
 *                ~/.ssh/config file.
2056
 *
2057
 *              - SSH_OPTIONS_IDENTITY:
2058
 *                Get the first identity file name (const char *).\n
2059
 *                \n
2060
 *                By default `id_rsa`, `id_ecdsa`, `id_ed25519`, `id_ecdsa_sk`
2061
 *                and `id_ed25519_sk` (when SK support is built in) files are
2062
 *                used.
2063
 *
2064
 *              - SSH_OPTIONS_NEXT_IDENTITY:
2065
 *                Get the next identity file name (const char *).\n
2066
 *                \n
2067
 *                Repeat calls to get all key paths. SSH_EOF is returned when
2068
 *                the end of list is reached. Another call will start another
2069
 *                iteration over the same list.
2070
 *
2071
 *              - SSH_OPTIONS_LOCAL_FORWARD:
2072
 *                Get the first local forwarding specification from the
2073
 *                local_forward list (const char *).\n
2074
 *                \n
2075
 *                Returns SSH_ERROR if the list is empty.
2076
 *
2077
 *              - SSH_OPTIONS_NEXT_LOCAL_FORWARD:
2078
 *                Get the next local forwarding specification from the
2079
 *                local_forward list (const char *).\n
2080
 *                \n
2081
 *                Repeat calls to get all entries. SSH_EOF is returned when
2082
 *                the end of list is reached.
2083
 *
2084
 *              - SSH_OPTIONS_SEND_ENV:
2085
 *                Get the first environment variable name pattern from the
2086
 *                send_env list (const char *).\n
2087
 *                \n
2088
 *                Returns SSH_ERROR if the list is empty.
2089
 *
2090
 *              - SSH_OPTIONS_NEXT_SEND_ENV:
2091
 *                Get the next environment variable name pattern from the
2092
 *                send_env list (const char *).\n
2093
 *                \n
2094
 *                Repeat calls to get all patterns. SSH_EOF is returned when
2095
 *                the end of list is reached.
2096
 *
2097
 *              - SSH_OPTIONS_PROXYCOMMAND:
2098
 *                Get the proxycommand necessary to log into the
2099
 *                remote host. When not explicitly set, it will be read
2100
 *                from the ~/.ssh/config file.
2101
 *
2102
 *              - SSH_OPTIONS_GLOBAL_KNOWNHOSTS:
2103
 *                Get the path to the global known_hosts file being used.
2104
 *
2105
 *              - SSH_OPTIONS_KNOWNHOSTS:
2106
 *                Get the path to the known_hosts file being used.
2107
 *
2108
 *              - SSH_OPTIONS_CONTROL_PATH:
2109
 *                Get the path to the control socket being used for connection
2110
 *                multiplexing.
2111
 *
2112
 *              - SSH_OPTIONS_KEY_EXCHANGE:
2113
 *                Get the key exchange methods to be used. If the option has
2114
 *                not been set, returns the defaults.
2115
 *
2116
 *              - SSH_OPTIONS_HOSTKEYS:
2117
 *                Get the preferred server host key types. If the option has
2118
 *                not been set, returns the defaults.
2119
 *
2120
 *              - SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES:
2121
 *                Get the preferred public key algorithms to be used for
2122
 *                authentication.
2123
 *
2124
 *              - SSH_OPTIONS_CIPHERS_C_S:
2125
 *                Get the symmetric cipher client to server. If the option has
2126
 *                not been set, returns the defaults.
2127
 *
2128
 *              - SSH_OPTIONS_CIPHERS_S_C:
2129
 *                Get the symmetric cipher server to client. If the option has
2130
 *                not been set, returns the defaults.
2131
 *
2132
 *              - SSH_OPTIONS_HMAC_C_S:
2133
 *                Get the Message Authentication Code algorithm client to server
2134
 *                If the option has not been set, returns the defaults.
2135
 *
2136
 *              - SSH_OPTIONS_HMAC_S_C:
2137
 *                Get the Message Authentication Code algorithm server to client
2138
 *                If the option has not been set, returns the defaults.
2139
 *
2140
 *              - SSH_OPTIONS_COMPRESSION_C_S:
2141
 *                Get the compression to use for client to server communication
2142
 *                If the option has not been set, returns the defaults.
2143
 *
2144
 *              - SSH_OPTIONS_COMPRESSION_S_C:
2145
 *                Get the compression to use for server to client communication
2146
 *                If the option has not been set, returns the defaults.
2147
 *
2148
 * @param  value The value to get into. As a char**, space will be
2149
 *               allocated by the function for the value, it is
2150
 *               your responsibility to free the memory using
2151
 *               ssh_string_free_char().
2152
 *
2153
 * @return       SSH_OK on success, SSH_ERROR on error.
2154
 */
2155
int ssh_options_get(ssh_session session, enum ssh_options_e type, char** value)
2156
0
{
2157
0
    char *src = NULL;
2158
2159
0
    if (session == NULL) {
2160
0
        return SSH_ERROR;
2161
0
    }
2162
2163
0
    if (value == NULL) {
2164
0
        ssh_set_error_invalid(session);
2165
0
        return SSH_ERROR;
2166
0
    }
2167
2168
0
    switch(type)
2169
0
    {
2170
0
        case SSH_OPTIONS_HOST:
2171
0
            src = session->opts.host ? session->opts.host
2172
0
                                     : session->opts.originalhost;
2173
0
            break;
2174
2175
0
        case SSH_OPTIONS_USER:
2176
0
            src = session->opts.username;
2177
0
            break;
2178
2179
0
        case SSH_OPTIONS_PREFERRED_AUTHENTICATIONS:
2180
0
            src = session->opts.preferred_authentications;
2181
0
            break;
2182
2183
0
        case SSH_OPTIONS_IDENTITY: {
2184
0
            struct ssh_iterator *it = NULL;
2185
0
            it = ssh_list_get_iterator(session->opts.identity);
2186
0
            if (it == NULL) {
2187
0
                it = ssh_list_get_iterator(session->opts.identity_non_exp);
2188
0
            }
2189
0
            if (it == NULL) {
2190
0
                return SSH_ERROR;
2191
0
            }
2192
0
            src = ssh_iterator_value(char *, it);
2193
0
            break;
2194
0
        }
2195
2196
0
        case SSH_OPTIONS_NEXT_IDENTITY: {
2197
0
            if (session->opts.identity_it != NULL) {
2198
                /* Move to the next item */
2199
0
                session->opts.identity_it = session->opts.identity_it->next;
2200
0
                if (session->opts.identity_it == NULL) {
2201
0
                    *value = NULL;
2202
0
                    return SSH_EOF;
2203
0
                }
2204
0
            } else {
2205
                /* Get iterator from opts */
2206
0
                struct ssh_iterator *it = NULL;
2207
0
                it = ssh_list_get_iterator(session->opts.identity);
2208
0
                if (it == NULL) {
2209
0
                    it = ssh_list_get_iterator(session->opts.identity_non_exp);
2210
0
                }
2211
0
                if (it == NULL) {
2212
0
                    return SSH_ERROR;
2213
0
                }
2214
0
                session->opts.identity_it = it;
2215
0
            }
2216
0
            src = ssh_iterator_value(char *, session->opts.identity_it);
2217
0
            break;
2218
0
        }
2219
2220
0
        case SSH_OPTIONS_LOCAL_FORWARD: {
2221
0
            struct ssh_iterator *it = NULL;
2222
0
            it = ssh_list_get_iterator(session->opts.local_forward);
2223
0
            if (it == NULL) {
2224
0
                return SSH_ERROR;
2225
0
            }
2226
0
            session->opts.local_forward_it = it;
2227
0
            src = ssh_iterator_value(char *, it);
2228
0
            break;
2229
0
        }
2230
2231
0
        case SSH_OPTIONS_NEXT_LOCAL_FORWARD:
2232
0
            if (session->opts.local_forward_it != NULL) {
2233
0
                session->opts.local_forward_it =
2234
0
                    session->opts.local_forward_it->next;
2235
0
                if (session->opts.local_forward_it == NULL) {
2236
0
                    *value = NULL;
2237
0
                    return SSH_EOF;
2238
0
                }
2239
0
            } else {
2240
0
                return SSH_ERROR;
2241
0
            }
2242
0
            src = ssh_iterator_value(char *, session->opts.local_forward_it);
2243
0
            break;
2244
2245
0
        case SSH_OPTIONS_SEND_ENV: {
2246
0
            struct ssh_iterator *it = NULL;
2247
0
            it = ssh_list_get_iterator(session->opts.send_env);
2248
0
            if (it == NULL) {
2249
0
                return SSH_ERROR;
2250
0
            }
2251
0
            session->opts.send_env_it = it;
2252
0
            src = ssh_iterator_value(char *, it);
2253
0
            break;
2254
0
        }
2255
2256
0
        case SSH_OPTIONS_NEXT_SEND_ENV:
2257
0
            if (session->opts.send_env_it != NULL) {
2258
0
                session->opts.send_env_it = session->opts.send_env_it->next;
2259
0
                if (session->opts.send_env_it == NULL) {
2260
0
                    *value = NULL;
2261
0
                    return SSH_EOF;
2262
0
                }
2263
0
            } else {
2264
0
                return SSH_ERROR;
2265
0
            }
2266
0
            src = ssh_iterator_value(char *, session->opts.send_env_it);
2267
0
            break;
2268
2269
0
        case SSH_OPTIONS_PROXYCOMMAND:
2270
0
            src = session->opts.ProxyCommand;
2271
0
            break;
2272
2273
0
        case SSH_OPTIONS_KNOWNHOSTS:
2274
0
            src = session->opts.knownhosts;
2275
0
            break;
2276
2277
0
        case SSH_OPTIONS_GLOBAL_KNOWNHOSTS:
2278
0
            src = session->opts.global_knownhosts;
2279
0
            break;
2280
0
        case SSH_OPTIONS_CONTROL_PATH:
2281
0
            src = session->opts.control_path;
2282
0
            break;
2283
2284
0
        case SSH_OPTIONS_CIPHERS_C_S:
2285
0
            src = ssh_options_get_algo(session, SSH_CRYPT_C_S);
2286
0
            break;
2287
2288
0
        case SSH_OPTIONS_CIPHERS_S_C:
2289
0
            src = ssh_options_get_algo(session, SSH_CRYPT_S_C);
2290
0
            break;
2291
2292
0
        case SSH_OPTIONS_KEY_EXCHANGE:
2293
0
            src = ssh_options_get_algo(session, SSH_KEX);
2294
0
            break;
2295
2296
0
        case SSH_OPTIONS_HOSTKEYS:
2297
0
            src = ssh_options_get_algo(session, SSH_HOSTKEYS);
2298
0
            break;
2299
2300
0
        case SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES:
2301
0
            src = session->opts.pubkey_accepted_types;
2302
0
            break;
2303
2304
0
        case SSH_OPTIONS_HMAC_C_S:
2305
0
            src = ssh_options_get_algo(session, SSH_MAC_C_S);
2306
0
            break;
2307
2308
0
        case SSH_OPTIONS_HMAC_S_C:
2309
0
            src = ssh_options_get_algo(session, SSH_MAC_S_C);
2310
0
            break;
2311
2312
0
        case SSH_OPTIONS_COMPRESSION_C_S:
2313
0
            src = ssh_options_get_algo(session, SSH_COMP_C_S);
2314
0
            break;
2315
2316
0
        case SSH_OPTIONS_COMPRESSION_S_C:
2317
0
            src = ssh_options_get_algo(session, SSH_COMP_S_C);
2318
0
            break;
2319
2320
0
        default:
2321
0
            ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
2322
0
            return SSH_ERROR;
2323
0
        break;
2324
0
    }
2325
0
    if (src == NULL) {
2326
0
        return SSH_ERROR;
2327
0
    }
2328
0
    *value = strdup(src);
2329
0
    if (*value == NULL) {
2330
0
        ssh_set_error_oom(session);
2331
0
        return SSH_ERROR;
2332
0
    }
2333
0
    return SSH_OK;
2334
0
}
2335
2336
/**
2337
 * @brief Parse command line arguments.
2338
 *
2339
 * This is a helper for your application to generate the appropriate
2340
 * options from the command line arguments.\n
2341
 * The argv array and argc value are changed so that the parsed
2342
 * arguments won't appear anymore in them.\n
2343
 * The single arguments (without switches) are not parsed. thus,
2344
 * myssh -l user localhost\n
2345
 * The command won't set the hostname value of options to localhost.
2346
 *
2347
 * @param session       The session to configure.
2348
 *
2349
 * @param argcptr       The pointer to the argument count.
2350
 *
2351
 * @param argv          The arguments list pointer.
2352
 *
2353
 * @returns 0 on success, < 0 on error.
2354
 *
2355
 * @see ssh_session_new()
2356
 */
2357
int ssh_options_getopt(ssh_session session, int *argcptr, char **argv)
2358
0
{
2359
0
    char *user = NULL;
2360
0
    char *cipher = NULL;
2361
0
    char *identity = NULL;
2362
0
    char *port = NULL;
2363
0
    char **save = NULL;
2364
0
    char **tmp = NULL;
2365
0
    size_t i = 0;
2366
0
    int argc = *argcptr;
2367
0
    int compress = 0;
2368
0
    size_t current = 0;
2369
0
    int opt_rc = 0;
2370
0
    int saveoptind = optind; /* need to save 'em */
2371
0
    int saveopterr = opterr;
2372
0
    int opt;
2373
0
    int rv;
2374
2375
    /* Keep preconfigured global log level and let -v flags raise it further. */
2376
0
    int verbosity = ssh_get_log_level();
2377
0
    int verbosity_set = 0;
2378
0
    if (argc <= 1) {
2379
0
        return SSH_OK;
2380
0
    }
2381
2382
0
    opterr = 0; /* shut up getopt */
2383
0
    while ((opt = getopt(argc, argv, "c:i:o:Cl:p:qvb:r12")) != -1) {
2384
0
        switch(opt) {
2385
0
        case 'l':
2386
0
            user = optarg;
2387
0
            break;
2388
0
        case 'p':
2389
0
            port = optarg;
2390
0
            break;
2391
0
        case 'v':
2392
0
            verbosity++;
2393
0
            verbosity_set = 1;
2394
0
            break;
2395
0
        case 'q':
2396
0
            verbosity = SSH_LOG_NOLOG;
2397
0
            verbosity_set = 1;
2398
0
            break;
2399
0
        case 'r':
2400
0
            break;
2401
0
        case 'c':
2402
0
            cipher = optarg;
2403
0
            break;
2404
0
        case 'i':
2405
0
            identity = optarg;
2406
0
            break;
2407
0
        case 'C':
2408
0
            compress++;
2409
0
            break;
2410
0
        case 'o':
2411
0
            opt_rc = ssh_config_parse_line_cli(session, optarg);
2412
0
            break;
2413
0
        case '2':
2414
0
        case '1':
2415
0
            break;
2416
0
        default:
2417
0
            {
2418
0
                tmp = realloc(save, (current + 1) * sizeof(char*));
2419
0
                if (tmp == NULL) {
2420
0
                    SAFE_FREE(save);
2421
0
                    ssh_set_error_oom(session);
2422
0
                    return -1;
2423
0
                }
2424
0
                save = tmp;
2425
0
                save[current] = argv[optind-1];
2426
0
                current++;
2427
                /* We can not use optarg here as getopt does not set it for
2428
                 * unknown options. We need to manually extract following
2429
                 * option and skip it manually from further processing */
2430
0
                if (optind < argc && argv[optind][0] != '-') {
2431
0
                    tmp = realloc(save, (current + 1) * sizeof(char*));
2432
0
                    if (tmp == NULL) {
2433
0
                        SAFE_FREE(save);
2434
0
                        ssh_set_error_oom(session);
2435
0
                        return -1;
2436
0
                    }
2437
0
                    save = tmp;
2438
0
                    save[current++] = argv[optind];
2439
0
                    optind++;
2440
0
                }
2441
0
            }
2442
0
        } /* switch */
2443
0
        if (opt_rc == SSH_ERROR) {
2444
0
            break;
2445
0
        }
2446
0
    } /* while */
2447
0
    opterr = saveopterr;
2448
0
    tmp = realloc(save, (current + (argc - optind)) * sizeof(char*));
2449
0
    if (tmp == NULL) {
2450
0
        SAFE_FREE(save);
2451
0
        ssh_set_error_oom(session);
2452
0
        return -1;
2453
0
    }
2454
0
    save = tmp;
2455
0
    while (optind < argc) {
2456
0
        tmp = realloc(save, (current + 1) * sizeof(char*));
2457
0
        if (tmp == NULL) {
2458
0
            SAFE_FREE(save);
2459
0
            ssh_set_error_oom(session);
2460
0
            return -1;
2461
0
        }
2462
0
        save = tmp;
2463
0
        save[current] = argv[optind];
2464
0
        current++;
2465
0
        optind++;
2466
0
    }
2467
2468
0
    optind = saveoptind;
2469
2470
0
    if (opt_rc == SSH_ERROR) {
2471
0
        SAFE_FREE(save);
2472
0
        return SSH_ERROR;
2473
0
    }
2474
2475
    /* first recopy the save vector into the original's */
2476
0
    for (i = 0; i < current; i++) {
2477
        /* don't erase argv[0] */
2478
0
        argv[ i + 1] = save[i];
2479
0
    }
2480
0
    argv[current + 1] = NULL;
2481
0
    *argcptr = current + 1;
2482
0
    SAFE_FREE(save);
2483
2484
0
    if (verbosity_set) {
2485
0
        verbosity = MIN(verbosity, SSH_LOG_FUNCTIONS);
2486
0
        rv = ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
2487
0
        if (rv < 0) {
2488
0
            return SSH_ERROR;
2489
0
        }
2490
0
    }
2491
2492
0
    if (compress) {
2493
0
        if (ssh_options_set(session, SSH_OPTIONS_COMPRESSION, "yes") < 0) {
2494
0
            return SSH_ERROR;
2495
0
        }
2496
0
    }
2497
2498
0
    if (cipher) {
2499
0
        int rc_c_s = ssh_options_set(session, SSH_OPTIONS_CIPHERS_C_S, cipher);
2500
0
        int rc_s_c = ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, cipher);
2501
0
        if (rc_c_s < 0 || rc_s_c < 0) {
2502
0
            return SSH_ERROR;
2503
0
        }
2504
0
    }
2505
2506
0
    if (user) {
2507
0
        if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) {
2508
0
            return SSH_ERROR;
2509
0
        }
2510
0
    }
2511
2512
0
    if (identity) {
2513
0
        if (ssh_options_set(session, SSH_OPTIONS_IDENTITY, identity) < 0) {
2514
0
            return SSH_ERROR;
2515
0
        }
2516
0
    }
2517
2518
0
    if (port != NULL) {
2519
0
        ssh_options_set(session, SSH_OPTIONS_PORT_STR, port);
2520
0
    }
2521
2522
0
    return SSH_OK;
2523
0
}
2524
2525
/**
2526
 * @brief Parse the ssh config file.
2527
 *
2528
 * This should be the last call of all options, it may overwrite options which
2529
 * are already set. It requires that the host name is already set with
2530
 * ssh_options_set(SSH_OPTIONS_HOST).
2531
 *
2532
 * @param  session      SSH session handle
2533
 *
2534
 * @param  filename     The options file to use, if NULL the default
2535
 *                      ~/.ssh/config and /etc/ssh/ssh_config will be used.
2536
 *                      If complied with support for hermetic-usr,
2537
 *                      /usr/etc/ssh/ssh_config will be used last.
2538
 *
2539
 * @return 0 on success, < 0 on error.
2540
 *
2541
 * @see ssh_options_set()
2542
 */
2543
int ssh_options_parse_config(ssh_session session, const char *filename)
2544
0
{
2545
0
    char *expanded_filename = NULL;
2546
0
    int r;
2547
0
    FILE *fp = NULL;
2548
2549
0
    if (session == NULL) {
2550
0
        return -1;
2551
0
    }
2552
0
    if (session->opts.originalhost == NULL) {
2553
0
        ssh_set_error_invalid(session);
2554
0
        return -1;
2555
0
    }
2556
2557
0
    if (session->opts.sshdir == NULL) {
2558
0
        r = ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL);
2559
0
        if (r < 0) {
2560
0
            ssh_set_error_oom(session);
2561
0
            return -1;
2562
0
        }
2563
0
    }
2564
2565
    /* set default filename */
2566
0
    if (filename == NULL) {
2567
0
        expanded_filename = ssh_path_expand_escape(session, "%d/.ssh/config");
2568
0
    } else {
2569
0
        expanded_filename = ssh_path_expand_escape(session, filename);
2570
0
    }
2571
0
    if (expanded_filename == NULL) {
2572
0
        return -1;
2573
0
    }
2574
2575
0
    r = ssh_config_parse_file(session, expanded_filename);
2576
0
    if (r < 0) {
2577
0
        goto out;
2578
0
    }
2579
0
    if (filename == NULL) {
2580
0
        fp = ssh_strict_fopen(GLOBAL_CLIENT_CONFIG, SSH_MAX_CONFIG_FILE_SIZE);
2581
0
        if (fp != NULL) {
2582
0
            filename = GLOBAL_CLIENT_CONFIG;
2583
#ifdef USR_GLOBAL_CLIENT_CONFIG
2584
        } else {
2585
            fp = ssh_strict_fopen(USR_GLOBAL_CLIENT_CONFIG,
2586
                                  SSH_MAX_CONFIG_FILE_SIZE);
2587
            if (fp != NULL) {
2588
                filename = USR_GLOBAL_CLIENT_CONFIG;
2589
            }
2590
#endif
2591
0
        }
2592
2593
0
        if (fp) {
2594
0
            SSH_LOG(SSH_LOG_PACKET,
2595
0
                    "Reading configuration data from %s",
2596
0
                    filename);
2597
0
            r = ssh_config_parse(session, fp, true);
2598
0
            fclose(fp);
2599
0
        }
2600
0
    }
2601
2602
    /* Do not process the default configuration as part of connection again */
2603
0
    session->opts.config_processed = true;
2604
0
out:
2605
0
    free(expanded_filename);
2606
0
    return r;
2607
0
}
2608
2609
/** @internal
2610
 * @brief Apply default values for unset session options.
2611
 *
2612
 * Sets default SSH directory and username if not already configured,
2613
 * and resolves any remaining option expansions.
2614
 *
2615
 * @param[in] session  The SSH session to apply defaults to.
2616
 *
2617
 * @return  `SSH_OK` on success, `SSH_ERROR` on error.
2618
 */
2619
int ssh_options_apply(ssh_session session)
2620
5.47k
{
2621
5.47k
    char *tmp = NULL;
2622
5.47k
    int rc;
2623
2624
5.47k
    if (session->opts.host != NULL) {
2625
5.47k
        char *normalized_host = NULL;
2626
5.47k
        rc = ssh_normalize_loose_ip(session->opts.host, &normalized_host);
2627
5.47k
        if (rc == -1) {
2628
            /* Error (e.g. NULL input or OOM) — leave host as it is */
2629
5.47k
        } else if (rc == 0) {
2630
            /* Was a loose IP — use the normalized dotted-quad form */
2631
0
            SAFE_FREE(session->opts.host);
2632
0
            session->opts.host = normalized_host;
2633
5.47k
        } else {
2634
            /* rc == 1: not a loose IP — lowercase if it's not a strict IP */
2635
5.47k
            bool is_ip = ssh_is_ipaddr(session->opts.host);
2636
5.47k
            if (!is_ip) {
2637
273
                char *lower = ssh_lowercase(session->opts.host);
2638
273
                if (lower != NULL) {
2639
273
                    SAFE_FREE(session->opts.host);
2640
273
                    session->opts.host = lower;
2641
273
                }
2642
273
            }
2643
5.47k
        }
2644
5.47k
    }
2645
2646
5.47k
    if (session->opts.sshdir == NULL) {
2647
5.47k
        rc = ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL);
2648
5.47k
        if (rc < 0) {
2649
0
            return -1;
2650
0
        }
2651
5.47k
    }
2652
2653
5.47k
    if (session->opts.username == NULL) {
2654
0
        rc = ssh_options_set(session, SSH_OPTIONS_USER, NULL);
2655
0
        if (rc < 0) {
2656
0
            return -1;
2657
0
        }
2658
0
    }
2659
2660
5.47k
    if (session->opts.config_hostname != NULL) {
2661
0
        char *saved_host = NULL;
2662
2663
0
        tmp = ssh_path_expand_hostname(session, session->opts.config_hostname);
2664
0
        if (tmp == NULL) {
2665
0
            return -1;
2666
0
        }
2667
0
        if (session->opts.host != NULL) {
2668
0
            saved_host = strdup(session->opts.host);
2669
0
            if (saved_host == NULL) {
2670
0
                free(tmp);
2671
0
                ssh_set_error_oom(session);
2672
0
                return -1;
2673
0
            }
2674
0
        }
2675
0
        session->opts.config_hostname_only = true;
2676
0
        rc = ssh_options_set(session, SSH_OPTIONS_HOST, tmp);
2677
0
        session->opts.config_hostname_only = false;
2678
0
        if (rc != SSH_OK) {
2679
            /* If HostName expansion leaves a literal '%', keep the current
2680
             * host instead of treating the deferred HostName as fatal.
2681
             */
2682
0
            if (strchr(tmp, '%') == NULL) {
2683
0
                SAFE_FREE(saved_host);
2684
0
                free(tmp);
2685
0
                return -1;
2686
0
            }
2687
0
            SSH_LOG(SSH_LOG_WARN,
2688
0
                    "HostName %s contains unknown expansion tokens and could "
2689
0
                    "not be applied; falling back to current host",
2690
0
                    tmp);
2691
0
            SAFE_FREE(session->opts.host);
2692
0
            session->opts.host = saved_host;
2693
0
            saved_host = NULL;
2694
0
        }
2695
0
        SAFE_FREE(saved_host);
2696
0
        free(tmp);
2697
0
        SAFE_FREE(session->opts.config_hostname);
2698
0
    }
2699
2700
5.47k
    if ((session->opts.exp_flags & SSH_OPT_EXP_FLAG_KNOWNHOSTS) == 0) {
2701
5.47k
        if (session->opts.knownhosts == NULL) {
2702
5.47k
            tmp = ssh_path_expand_escape(session, "%d/.ssh/known_hosts");
2703
5.47k
        } else {
2704
0
            tmp = ssh_path_expand_escape(session, session->opts.knownhosts);
2705
0
        }
2706
5.47k
        if (tmp == NULL) {
2707
0
            return -1;
2708
0
        }
2709
5.47k
        free(session->opts.knownhosts);
2710
5.47k
        session->opts.knownhosts = tmp;
2711
5.47k
        session->opts.exp_flags |= SSH_OPT_EXP_FLAG_KNOWNHOSTS;
2712
5.47k
    }
2713
2714
5.47k
    if ((session->opts.exp_flags & SSH_OPT_EXP_FLAG_GLOBAL_KNOWNHOSTS) == 0) {
2715
5.47k
        if (session->opts.global_knownhosts == NULL) {
2716
5.47k
            tmp = strdup(GLOBAL_CONF_DIR "/ssh_known_hosts");
2717
5.47k
        } else {
2718
0
            tmp = ssh_path_expand_escape(session,
2719
0
                                         session->opts.global_knownhosts);
2720
0
        }
2721
5.47k
        if (tmp == NULL) {
2722
0
            return -1;
2723
0
        }
2724
5.47k
        free(session->opts.global_knownhosts);
2725
5.47k
        session->opts.global_knownhosts = tmp;
2726
5.47k
        session->opts.exp_flags |= SSH_OPT_EXP_FLAG_GLOBAL_KNOWNHOSTS;
2727
5.47k
    }
2728
2729
2730
5.47k
    if ((session->opts.exp_flags & SSH_OPT_EXP_FLAG_PROXYCOMMAND) == 0) {
2731
5.47k
        if (session->opts.ProxyCommand != NULL) {
2732
0
            char *p = NULL;
2733
0
            size_t plen = strlen(session->opts.ProxyCommand) +
2734
0
                          5 /* strlen("exec ") */;
2735
2736
0
            if (strncmp(session->opts.ProxyCommand, "exec ", 5) != 0) {
2737
0
                p = malloc(plen + 1 /* \0 */);
2738
0
                if (p == NULL) {
2739
0
                    return -1;
2740
0
                }
2741
2742
0
                rc = snprintf(p, plen + 1, "exec %s", session->opts.ProxyCommand);
2743
0
                if ((size_t)rc != plen) {
2744
0
                    free(p);
2745
0
                    return -1;
2746
0
                }
2747
0
                tmp = ssh_path_expand_escape(session, p);
2748
0
                free(p);
2749
0
            } else {
2750
0
                tmp = ssh_path_expand_escape(session,
2751
0
                                             session->opts.ProxyCommand);
2752
0
            }
2753
2754
0
            if (tmp == NULL) {
2755
0
                return -1;
2756
0
            }
2757
0
            free(session->opts.ProxyCommand);
2758
0
            session->opts.ProxyCommand = tmp;
2759
0
            session->opts.exp_flags |= SSH_OPT_EXP_FLAG_PROXYCOMMAND;
2760
0
        }
2761
5.47k
    }
2762
2763
5.47k
    if ((session->opts.exp_flags & SSH_OPT_EXP_FLAG_CONTROL_PATH) == 0) {
2764
5.47k
        if (session->opts.control_path != NULL) {
2765
0
            tmp = ssh_path_expand_escape(session, session->opts.control_path);
2766
0
            if (tmp == NULL) {
2767
0
                return -1;
2768
0
            }
2769
0
            free(session->opts.control_path);
2770
0
            session->opts.control_path = tmp;
2771
0
            session->opts.exp_flags |= SSH_OPT_EXP_FLAG_CONTROL_PATH;
2772
0
        }
2773
5.47k
    }
2774
2775
5.47k
    for (tmp = ssh_list_pop_head(char *, session->opts.identity_non_exp);
2776
21.9k
         tmp != NULL;
2777
16.4k
         tmp = ssh_list_pop_head(char *, session->opts.identity_non_exp)) {
2778
16.4k
        char *id = tmp;
2779
16.4k
        if (strncmp(id, "pkcs11:", 6) != 0) {
2780
            /* PKCS#11 URIs are using percent-encoding so we can not mix
2781
             * it with ssh expansion of ssh escape characters.
2782
             */
2783
16.4k
            tmp = ssh_path_expand_escape(session, id);
2784
16.4k
            free(id);
2785
16.4k
            if (tmp == NULL) {
2786
0
                return -1;
2787
0
            }
2788
16.4k
        }
2789
2790
        /* use append to keep the order at first call and use prepend
2791
         * to put anything that comes on the nth calls to the beginning */
2792
16.4k
        if (session->opts.exp_flags & SSH_OPT_EXP_FLAG_IDENTITY) {
2793
0
            rc = ssh_list_prepend(session->opts.identity, tmp);
2794
16.4k
        } else {
2795
16.4k
            rc = ssh_list_append(session->opts.identity, tmp);
2796
16.4k
        }
2797
16.4k
        if (rc != SSH_OK) {
2798
0
            free(tmp);
2799
0
            return -1;
2800
0
        }
2801
16.4k
    }
2802
5.47k
    session->opts.exp_flags |= SSH_OPT_EXP_FLAG_IDENTITY;
2803
2804
5.47k
    for (tmp = ssh_list_pop_head(char *, session->opts.certificate_non_exp);
2805
5.47k
         tmp != NULL;
2806
5.47k
         tmp = ssh_list_pop_head(char *, session->opts.certificate_non_exp)) {
2807
0
        char *id = tmp;
2808
2809
0
        tmp = ssh_path_expand_escape(session, id);
2810
0
        free(id);
2811
0
        if (tmp == NULL) {
2812
0
            return -1;
2813
0
        }
2814
2815
0
        rc = ssh_list_append(session->opts.certificate, tmp);
2816
0
        if (rc != SSH_OK) {
2817
0
            free(tmp);
2818
0
            return -1;
2819
0
        }
2820
0
    }
2821
2822
#ifdef WITH_GSSAPI
2823
    if (session->opts.gssapi_key_exchange) {
2824
        rc = ssh_gssapi_check_client_config(session);
2825
        if (rc != SSH_OK) {
2826
            SSH_LOG(SSH_LOG_WARN, "Disabled GSSAPI key exchange");
2827
            session->opts.gssapi_key_exchange = false;
2828
        }
2829
    }
2830
#endif
2831
2832
5.47k
    return 0;
2833
5.47k
}
2834
2835
/** @} */
2836
2837
#ifdef WITH_SERVER
2838
static bool ssh_bind_key_size_allowed(ssh_bind sshbind, ssh_key key)
2839
9.62k
{
2840
9.62k
    int min_size = 0;
2841
2842
9.62k
    switch (ssh_key_type(key)) {
2843
9.35k
    case SSH_KEYTYPE_RSA:
2844
9.35k
    case SSH_KEYTYPE_RSA_CERT01:
2845
9.35k
        min_size = sshbind->rsa_min_size;
2846
9.35k
        return ssh_key_size_allowed_rsa(min_size, key);
2847
273
    default:
2848
273
        return true;
2849
9.62k
    }
2850
9.62k
}
2851
2852
/**
2853
 * @addtogroup libssh_server
2854
 * @{
2855
 */
2856
static int
2857
ssh_bind_set_key(ssh_bind sshbind, char **key_loc, const void *value)
2858
9.62k
{
2859
9.62k
    if (value == NULL) {
2860
0
        ssh_set_error_invalid(sshbind);
2861
0
        return -1;
2862
9.62k
    } else {
2863
9.62k
        SAFE_FREE(*key_loc);
2864
9.62k
        *key_loc = strdup(value);
2865
9.62k
        if (*key_loc == NULL) {
2866
0
            ssh_set_error_oom(sshbind);
2867
0
            return -1;
2868
0
        }
2869
9.62k
    }
2870
9.62k
    return 0;
2871
9.62k
}
2872
2873
static int ssh_bind_set_algo(ssh_bind sshbind,
2874
                             enum ssh_kex_types_e algo,
2875
                             const char *list,
2876
                             char **place)
2877
38.8k
{
2878
    /* sshbind is needed only for ssh_set_error which takes void*
2879
     * the typecast is only to satisfy function parameter type */
2880
38.8k
    return ssh_options_set_algo((ssh_session)sshbind, algo, list, place);
2881
38.8k
}
2882
2883
/**
2884
 * @brief Set options for an SSH server bind.
2885
 *
2886
 * @param  sshbind      The ssh server bind to configure.
2887
 *
2888
 * @param  type         The option type to set. This should be one of the
2889
 *                      following:
2890
 *
2891
 *                      - SSH_BIND_OPTIONS_HOSTKEY:
2892
 *                        Set the path to an ssh host key, regardless
2893
 *                        of type.  Only one key from per key type
2894
 *                        (RSA, ED25519 and ECDSA) is allowed in an ssh_bind
2895
 *                        at a time, and later calls to this function
2896
 *                        with this option for the same key type will
2897
 *                        override prior calls (const char *).
2898
 *
2899
 *                      - SSH_BIND_OPTIONS_BINDADDR:
2900
 *                        Set the IP address to bind (const char *).
2901
 *
2902
 *                      - SSH_BIND_OPTIONS_BINDPORT:
2903
 *                        Set the port to bind (unsigned int).
2904
 *
2905
 *                      - SSH_BIND_OPTIONS_BINDPORT_STR:
2906
 *                        Set the port to bind (const char *).
2907
 *
2908
 *                      - SSH_BIND_OPTIONS_LOG_VERBOSITY:
2909
 *                        Set the session logging verbosity (int).
2910
 *                        The logging verbosity should have one of the
2911
 *                        following values, which are listed in order
2912
 *                        of increasing verbosity.  Every log message
2913
 *                        with verbosity less than or equal to the
2914
 *                        logging verbosity will be shown.
2915
 *                        - SSH_LOG_NOLOG: No logging
2916
 *                        - SSH_LOG_WARNING: Only warnings
2917
 *                        - SSH_LOG_PROTOCOL: High level protocol information
2918
 *                        - SSH_LOG_PACKET: Lower level protocol information,
2919
 *                          packet level
2920
 *                        - SSH_LOG_FUNCTIONS: Every function path
2921
 *                        The default is SSH_LOG_NOLOG.
2922
 *
2923
 *                      - SSH_BIND_OPTIONS_LOG_VERBOSITY_STR:
2924
 *                        Set the session logging verbosity via a
2925
 *                        string that will be converted to a numerical
2926
 *                        value (e.g. "3") and interpreted according
2927
 *                        to the values of
2928
 *                        SSH_BIND_OPTIONS_LOG_VERBOSITY above
2929
 *                        (const char *).
2930
 *
2931
 *                      - SSH_BIND_OPTIONS_RSAKEY:
2932
 *                        Deprecated alias to SSH_BIND_OPTIONS_HOSTKEY
2933
 *                        (const char *).
2934
 *
2935
 *                      - SSH_BIND_OPTIONS_ECDSAKEY:
2936
 *                        Deprecated alias to SSH_BIND_OPTIONS_HOSTKEY
2937
 *                        (const char *).
2938
 *
2939
 *                      - SSH_BIND_OPTIONS_BANNER:
2940
 *                        Set the server banner sent to clients (const char *).
2941
 *
2942
 *                      - SSH_BIND_OPTIONS_DSAKEY:
2943
 *                        This is DEPRECATED, please do not use.
2944
 *
2945
 *                      - SSH_BIND_OPTIONS_IMPORT_KEY:
2946
 *                        Set the Private Key for the server directly
2947
 *                        (ssh_key). It will be free'd by ssh_bind_free().
2948
 *
2949
 *                      - SSH_BIND_OPTIONS_IMPORT_KEY_STR:
2950
 *                        Set the Private key for the server from a
2951
 *                        base64 encoded buffer (const char *).
2952
 *
2953
 *                      - SSH_BIND_OPTIONS_CIPHERS_C_S:
2954
 *                        Set the symmetric cipher client to server
2955
 *                        (const char *, comma-separated list).
2956
 *
2957
 *                      - SSH_BIND_OPTIONS_CIPHERS_S_C:
2958
 *                        Set the symmetric cipher server to client
2959
 *                        (const char *, comma-separated list).
2960
 *
2961
 *                      - SSH_BIND_OPTIONS_KEY_EXCHANGE:
2962
 *                        Set the key exchange method to be used
2963
 *                        (const char *, comma-separated list). ex:
2964
 *                        "ecdh-sha2-nistp256,diffie-hellman-group14-sha1"
2965
 *
2966
 *                      - SSH_BIND_OPTIONS_HMAC_C_S:
2967
 *                        Set the Message Authentication Code algorithm client
2968
 *                        to server (const char *, comma-separated list).
2969
 *
2970
 *                      - SSH_BIND_OPTIONS_HMAC_S_C:
2971
 *                        Set the Message Authentication Code algorithm server
2972
 *                        to client (const char *, comma-separated list).
2973
 *
2974
 *                      - SSH_BIND_OPTIONS_CONFIG_DIR:
2975
 *                        Set the directory (const char *, format string)
2976
 *                        to be used when the "%d" scape is used when providing
2977
 *                        paths of configuration files to
2978
 *                        ssh_bind_options_parse_config().
2979
 *
2980
 *                      - SSH_BIND_OPTIONS_PROCESS_CONFIG
2981
 *                        Set it to false to disable automatic processing of
2982
 *                        system-wide configuration files. LibSSH automatically
2983
 *                        uses these configuration files otherwise. This
2984
 *                        option will only have effect if set before any call
2985
 *                        to ssh_bind_options_parse_config() (bool).
2986
 *
2987
 *                      - SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES:
2988
 *                        Set the public key algorithm accepted by the server
2989
 *                        (const char *, comma-separated list).
2990
 *
2991
 *                      - SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS:
2992
 *                        Set the list of allowed hostkey signatures algorithms
2993
 *                        to offer to the client, ordered by preference. This
2994
 *                        list is used as a filter when creating the list of
2995
 *                        algorithms to offer to the client: first the list of
2996
 *                        possible algorithms is created from the list of keys
2997
 *                        set and then filtered against this list.
2998
 *                        (const char *, comma-separated list).
2999
 *
3000
 *                      - SSH_BIND_OPTIONS_MODULI
3001
 *                        Set the path to the moduli file. Defaults to
3002
 *                        /etc/ssh/moduli if not specified (const char *).
3003
 *
3004
 *                      - SSH_BIND_OPTIONS_RSA_MIN_SIZE
3005
 *                        Set the minimum RSA key size in bits to be accepted by
3006
 *                        the server for both authentication and hostkey
3007
 *                        operations. The values under 1024 bits are not accepted
3008
 *                        even with this configuration option as they are
3009
 *                        considered completely broken. Setting 0 will revert
3010
 *                        the value to defaults.
3011
 *                        Default is 3072 bits or 2048 bits in FIPS mode.
3012
 *                        (int)
3013
 *
3014
 *                      - SSH_BIND_OPTIONS_GSSAPI_KEY_EXCHANGE
3015
 *                        Set true to enable GSSAPI key exchange,
3016
 *                        false to disable GSSAPI key exchange. (bool)
3017
 *
3018
 *                      - SSH_BIND_OPTIONS_GSSAPI_KEY_EXCHANGE_ALGS
3019
 *                        Set the GSSAPI key exchange method to be used
3020
 *                        (const char *, comma-separated list).
3021
 *                        ex: "gss-group14-sha256-,gss-group16-sha512-"
3022
 *
3023
 * @param  value        The value to set. This is a generic pointer and the
3024
 *                      datatype which should be used is described at the
3025
 *                      corresponding value of type above.
3026
 *
3027
 * @return              0 on success, < 0 on error, invalid option, or
3028
 *                      parameter.
3029
 *
3030
 * @warning             When the option value to set is represented via a
3031
 *                      pointer (e.g const char * in case of strings, ssh_key
3032
 *                      in case of a libssh key), the value parameter should be
3033
 *                      that pointer. Do NOT pass a pointer to a pointer (const
3034
 *                      char **, ssh_key *)
3035
 *
3036
 * @warning             When the option value to set is not a pointer (e.g int,
3037
 *                      unsigned int, bool, long), the value parameter should be
3038
 *                      a pointer to the location storing the value to set (int
3039
 *                      *, unsigned int *, bool *, long *)
3040
 *
3041
 * @warning             If the value parameter has an invalid type (e.g if its
3042
 *                      not a pointer when it should have been a pointer, or if
3043
 *                      its a pointer to a pointer when it should have just been
3044
 *                      a pointer), then the behaviour is undefined.
3045
 *
3046
 * @warning             Options set via this function may be overridden if a
3047
 *                      configuration file is parsed afterwards (e.g., by an
3048
 *                      implicit call to ssh_bind_options_parse_config() inside
3049
 *                      ssh_bind_listen(), or by a manual call to the same
3050
 *                      function) and contains the same options.\n
3051
 *                      It is the caller’s responsibility to ensure the correct
3052
 *                      order of API calls if explicit options must take
3053
 *                      precedence.
3054
 */
3055
int
3056
ssh_bind_options_set(ssh_bind sshbind,
3057
                     enum ssh_bind_options_e type,
3058
                     const void *value)
3059
59.6k
{
3060
59.6k
    bool allowed;
3061
59.6k
    char *p = NULL, *q = NULL;
3062
59.6k
    const char *v = NULL;
3063
59.6k
    int i, rc;
3064
59.6k
    char **wanted_methods = sshbind->wanted_methods;
3065
3066
59.6k
    if (sshbind == NULL) {
3067
0
        return -1;
3068
0
    }
3069
3070
59.6k
    switch (type) {
3071
0
    case SSH_BIND_OPTIONS_RSAKEY:
3072
0
    case SSH_BIND_OPTIONS_ECDSAKEY:
3073
        /* deprecated */
3074
11.0k
    case SSH_BIND_OPTIONS_HOSTKEY:
3075
11.0k
    case SSH_BIND_OPTIONS_IMPORT_KEY:
3076
11.0k
    case SSH_BIND_OPTIONS_IMPORT_KEY_STR:
3077
11.0k
        if (value == NULL) {
3078
0
            ssh_set_error_invalid(sshbind);
3079
0
            return -1;
3080
11.0k
        } else {
3081
11.0k
            int key_type;
3082
11.0k
            ssh_key *bind_key_loc = NULL;
3083
11.0k
            ssh_key key = NULL;
3084
11.0k
            char **bind_key_path_loc = NULL;
3085
3086
11.0k
            if (type == SSH_BIND_OPTIONS_IMPORT_KEY_STR) {
3087
0
                const char *key_str = (const char *)value;
3088
0
                rc = ssh_pki_import_privkey_base64(key_str,
3089
0
                                                   NULL,
3090
0
                                                   NULL,
3091
0
                                                   NULL,
3092
0
                                                   &key);
3093
0
                if (rc == SSH_ERROR) {
3094
0
                    ssh_set_error(sshbind,
3095
0
                                  SSH_FATAL,
3096
0
                                  "Failed to import key from buffer");
3097
0
                    return -1;
3098
0
                }
3099
11.0k
            } else if (type == SSH_BIND_OPTIONS_IMPORT_KEY) {
3100
0
                key = (ssh_key)value;
3101
11.0k
            } else {
3102
11.0k
                rc = ssh_pki_import_privkey_file(value, NULL, NULL, NULL, &key);
3103
11.0k
                if (rc != SSH_OK) {
3104
1.47k
                    return -1;
3105
1.47k
                }
3106
11.0k
            }
3107
9.62k
            allowed = ssh_bind_key_size_allowed(sshbind, key);
3108
9.62k
            if (!allowed) {
3109
0
                ssh_set_error(sshbind,
3110
0
                              SSH_FATAL,
3111
0
                              "The host key size %d is too small.",
3112
0
                              ssh_key_size(key));
3113
0
                if (type != SSH_BIND_OPTIONS_IMPORT_KEY) {
3114
0
                    SSH_KEY_FREE(key);
3115
0
                }
3116
0
                return -1;
3117
0
            }
3118
9.62k
            key_type = ssh_key_type(key);
3119
9.62k
            switch (key_type) {
3120
0
            case SSH_KEYTYPE_ECDSA_P256:
3121
0
            case SSH_KEYTYPE_ECDSA_P384:
3122
0
            case SSH_KEYTYPE_ECDSA_P521:
3123
0
#ifdef HAVE_ECC
3124
0
                bind_key_loc = &sshbind->ecdsa;
3125
0
                bind_key_path_loc = &sshbind->ecdsakey;
3126
#else
3127
                ssh_set_error(sshbind,
3128
                              SSH_FATAL,
3129
                              "ECDSA key used and libssh compiled "
3130
                              "without ECDSA support");
3131
#endif
3132
0
                break;
3133
9.35k
            case SSH_KEYTYPE_RSA:
3134
9.35k
                bind_key_loc = &sshbind->rsa;
3135
9.35k
                bind_key_path_loc = &sshbind->rsakey;
3136
9.35k
                break;
3137
273
            case SSH_KEYTYPE_ED25519:
3138
273
                bind_key_loc = &sshbind->ed25519;
3139
273
                bind_key_path_loc = &sshbind->ed25519key;
3140
273
                break;
3141
0
            default:
3142
0
                ssh_set_error(sshbind,
3143
9.62k
                              SSH_FATAL,
3144
9.62k
                              "Unsupported key type %d",
3145
9.62k
                              key_type);
3146
9.62k
            }
3147
9.62k
            if (type == SSH_BIND_OPTIONS_RSAKEY ||
3148
9.62k
                type == SSH_BIND_OPTIONS_ECDSAKEY ||
3149
9.62k
                type == SSH_BIND_OPTIONS_HOSTKEY) {
3150
9.62k
                if (bind_key_loc == NULL) {
3151
0
                    ssh_key_free(key);
3152
0
                    return -1;
3153
0
                }
3154
                /* Set the location of the key on disk even though we don't
3155
                   need it in case some other function wants it */
3156
9.62k
                rc = ssh_bind_set_key(sshbind, bind_key_path_loc, value);
3157
9.62k
                if (rc < 0) {
3158
0
                    ssh_key_free(key);
3159
0
                    return -1;
3160
0
                }
3161
9.62k
            } else if (type == SSH_BIND_OPTIONS_IMPORT_KEY_STR) {
3162
0
                if (bind_key_loc == NULL) {
3163
0
                    ssh_key_free(key);
3164
0
                    return -1;
3165
0
                }
3166
0
            } else {
3167
0
                if (bind_key_loc == NULL) {
3168
0
                    return -1;
3169
0
                }
3170
0
            }
3171
9.62k
            ssh_key_free(*bind_key_loc);
3172
9.62k
            *bind_key_loc = key;
3173
9.62k
        }
3174
9.62k
        break;
3175
9.62k
    case SSH_BIND_OPTIONS_BINDADDR:
3176
0
        if (value == NULL) {
3177
0
            ssh_set_error_invalid(sshbind);
3178
0
            return -1;
3179
0
        } else {
3180
0
            SAFE_FREE(sshbind->bindaddr);
3181
0
            sshbind->bindaddr = strdup(value);
3182
0
            if (sshbind->bindaddr == NULL) {
3183
0
                ssh_set_error_oom(sshbind);
3184
0
                return -1;
3185
0
            }
3186
0
        }
3187
0
        break;
3188
0
    case SSH_BIND_OPTIONS_BINDPORT:
3189
0
        if (value == NULL) {
3190
0
            ssh_set_error_invalid(sshbind);
3191
0
            return -1;
3192
0
        } else {
3193
0
            int *x = (int *)value;
3194
0
            sshbind->bindport = *x & 0xffffU;
3195
0
        }
3196
0
        break;
3197
2
    case SSH_BIND_OPTIONS_BINDPORT_STR:
3198
2
        if (value == NULL) {
3199
0
            sshbind->bindport = 22 & 0xffffU;
3200
2
        } else {
3201
2
            q = strdup(value);
3202
2
            if (q == NULL) {
3203
0
                ssh_set_error_oom(sshbind);
3204
0
                return -1;
3205
0
            }
3206
2
            i = strtol(q, &p, 10);
3207
2
            if (q == p) {
3208
2
                SSH_LOG(SSH_LOG_DEBUG, "No bind port was parsed");
3209
2
                SAFE_FREE(q);
3210
2
                return -1;
3211
2
            }
3212
0
            SAFE_FREE(q);
3213
3214
0
            sshbind->bindport = i & 0xffffU;
3215
0
        }
3216
0
        break;
3217
14
    case SSH_BIND_OPTIONS_LOG_VERBOSITY:
3218
14
        if (value == NULL) {
3219
0
            ssh_set_error_invalid(sshbind);
3220
0
            return -1;
3221
14
        } else {
3222
14
            int *x = (int *)value;
3223
14
            ssh_set_log_level(*x & 0xffffU);
3224
14
        }
3225
14
        break;
3226
14
    case SSH_BIND_OPTIONS_LOG_VERBOSITY_STR:
3227
0
        if (value == NULL) {
3228
0
            ssh_set_log_level(0);
3229
0
        } else {
3230
0
            q = strdup(value);
3231
0
            if (q == NULL) {
3232
0
                ssh_set_error_oom(sshbind);
3233
0
                return -1;
3234
0
            }
3235
0
            i = strtol(q, &p, 10);
3236
0
            if (q == p) {
3237
0
                SSH_LOG(SSH_LOG_DEBUG, "No log verbositiy was parsed");
3238
0
                SAFE_FREE(q);
3239
0
                return -1;
3240
0
            }
3241
0
            SAFE_FREE(q);
3242
3243
0
            ssh_set_log_level(i & 0xffffU);
3244
0
        }
3245
0
        break;
3246
0
    case SSH_BIND_OPTIONS_BANNER:
3247
0
        if (value == NULL) {
3248
0
            ssh_set_error_invalid(sshbind);
3249
0
            return -1;
3250
0
        } else {
3251
0
            SAFE_FREE(sshbind->banner);
3252
0
            sshbind->banner = strdup(value);
3253
0
            if (sshbind->banner == NULL) {
3254
0
                ssh_set_error_oom(sshbind);
3255
0
                return -1;
3256
0
            }
3257
0
        }
3258
0
        break;
3259
9.65k
    case SSH_BIND_OPTIONS_CIPHERS_C_S:
3260
9.65k
        v = value;
3261
9.65k
        if (v == NULL || v[0] == '\0') {
3262
0
            ssh_set_error_invalid(sshbind);
3263
0
            return -1;
3264
9.65k
        } else {
3265
9.65k
            rc = ssh_bind_set_algo(sshbind,
3266
9.65k
                                   SSH_CRYPT_C_S,
3267
9.65k
                                   v,
3268
9.65k
                                   &wanted_methods[SSH_CRYPT_C_S]);
3269
9.65k
            if (rc < 0) {
3270
7
                return -1;
3271
7
            }
3272
9.65k
        }
3273
9.64k
        break;
3274
9.64k
    case SSH_BIND_OPTIONS_CIPHERS_S_C:
3275
9.64k
        v = value;
3276
9.64k
        if (v == NULL || v[0] == '\0') {
3277
0
            ssh_set_error_invalid(sshbind);
3278
0
            return -1;
3279
9.64k
        } else {
3280
9.64k
            rc = ssh_bind_set_algo(sshbind,
3281
9.64k
                                   SSH_CRYPT_S_C,
3282
9.64k
                                   v,
3283
9.64k
                                   &wanted_methods[SSH_CRYPT_S_C]);
3284
9.64k
            if (rc < 0) {
3285
0
                return -1;
3286
0
            }
3287
9.64k
        }
3288
9.64k
        break;
3289
9.64k
    case SSH_BIND_OPTIONS_KEY_EXCHANGE:
3290
151
        v = value;
3291
151
        if (v == NULL || v[0] == '\0') {
3292
0
            ssh_set_error_invalid(sshbind);
3293
0
            return -1;
3294
151
        } else {
3295
151
            rc = ssh_bind_set_algo(sshbind,
3296
151
                                   SSH_KEX,
3297
151
                                   v,
3298
151
                                   &wanted_methods[SSH_KEX]);
3299
151
            if (rc < 0) {
3300
51
                return -1;
3301
51
            }
3302
151
        }
3303
100
        break;
3304
9.70k
    case SSH_BIND_OPTIONS_HMAC_C_S:
3305
9.70k
        v = value;
3306
9.70k
        if (v == NULL || v[0] == '\0') {
3307
0
            ssh_set_error_invalid(sshbind);
3308
0
            return -1;
3309
9.70k
        } else {
3310
9.70k
            rc = ssh_bind_set_algo(sshbind,
3311
9.70k
                                   SSH_MAC_C_S,
3312
9.70k
                                   v,
3313
9.70k
                                   &wanted_methods[SSH_MAC_C_S]);
3314
9.70k
            if (rc < 0) {
3315
24
                return -1;
3316
24
            }
3317
9.70k
        }
3318
9.68k
        break;
3319
9.68k
    case SSH_BIND_OPTIONS_HMAC_S_C:
3320
9.68k
        v = value;
3321
9.68k
        if (v == NULL || v[0] == '\0') {
3322
0
            ssh_set_error_invalid(sshbind);
3323
0
            return -1;
3324
9.68k
        } else {
3325
9.68k
            rc = ssh_bind_set_algo(sshbind,
3326
9.68k
                                   SSH_MAC_S_C,
3327
9.68k
                                   v,
3328
9.68k
                                   &wanted_methods[SSH_MAC_S_C]);
3329
9.68k
            if (rc < 0) {
3330
0
                return -1;
3331
0
            }
3332
9.68k
        }
3333
9.68k
        break;
3334
9.68k
    case SSH_BIND_OPTIONS_CONFIG_DIR:
3335
0
        v = value;
3336
0
        SAFE_FREE(sshbind->config_dir);
3337
0
        if (v == NULL) {
3338
0
            break;
3339
0
        } else if (v[0] == '\0') {
3340
0
            ssh_set_error_invalid(sshbind);
3341
0
            return -1;
3342
0
        } else {
3343
0
            sshbind->config_dir = ssh_path_expand_tilde(v);
3344
0
            if (sshbind->config_dir == NULL) {
3345
0
                ssh_set_error_oom(sshbind);
3346
0
                return -1;
3347
0
            }
3348
0
        }
3349
0
        break;
3350
12
    case SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES:
3351
12
        v = value;
3352
12
        if (v == NULL || v[0] == '\0') {
3353
0
            ssh_set_error_invalid(sshbind);
3354
0
            return -1;
3355
12
        } else {
3356
12
            rc = ssh_bind_set_algo(sshbind,
3357
12
                                   SSH_HOSTKEYS,
3358
12
                                   v,
3359
12
                                   &sshbind->pubkey_accepted_key_types);
3360
12
            if (rc < 0) {
3361
5
                return -1;
3362
5
            }
3363
12
        }
3364
7
        break;
3365
28
    case SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS:
3366
28
        v = value;
3367
28
        if (v == NULL || v[0] == '\0') {
3368
0
            ssh_set_error_invalid(sshbind);
3369
0
            return -1;
3370
28
        } else {
3371
28
            rc = ssh_bind_set_algo(sshbind,
3372
28
                                   SSH_HOSTKEYS,
3373
28
                                   v,
3374
28
                                   &wanted_methods[SSH_HOSTKEYS]);
3375
28
            if (rc < 0) {
3376
12
                return -1;
3377
12
            }
3378
28
        }
3379
16
        break;
3380
9.62k
    case SSH_BIND_OPTIONS_PROCESS_CONFIG:
3381
9.62k
        if (value == NULL) {
3382
0
            ssh_set_error_invalid(sshbind);
3383
0
            return -1;
3384
9.62k
        } else {
3385
9.62k
            bool *x = (bool *)value;
3386
9.62k
            sshbind->config_processed = !(*x);
3387
9.62k
        }
3388
9.62k
        break;
3389
9.62k
    case SSH_BIND_OPTIONS_MODULI:
3390
0
        if (value == NULL) {
3391
0
            ssh_set_error_invalid(sshbind);
3392
0
            return -1;
3393
0
        } else {
3394
0
            SAFE_FREE(sshbind->moduli_file);
3395
0
            sshbind->moduli_file = strdup(value);
3396
0
            if (sshbind->moduli_file == NULL) {
3397
0
                ssh_set_error_oom(sshbind);
3398
0
                return -1;
3399
0
            }
3400
0
        }
3401
0
        break;
3402
13
    case SSH_BIND_OPTIONS_RSA_MIN_SIZE:
3403
13
        if (value == NULL) {
3404
0
            ssh_set_error_invalid(sshbind);
3405
0
            return -1;
3406
13
        } else {
3407
13
            int *x = (int *)value;
3408
3409
13
            if (*x < 0) {
3410
0
                ssh_set_error_invalid(sshbind);
3411
0
                return -1;
3412
0
            }
3413
3414
            /* (*x == 0) is allowed as it is used to revert to default */
3415
3416
13
            if (*x > 0 && *x < RSA_MIN_KEY_SIZE) {
3417
4
                ssh_set_error(sshbind,
3418
4
                              SSH_REQUEST_DENIED,
3419
4
                              "The provided value (%d) for minimal RSA key "
3420
4
                              "size is too small. Use at least %d bits.",
3421
4
                              *x,
3422
4
                              RSA_MIN_KEY_SIZE);
3423
4
                return -1;
3424
4
            }
3425
9
            sshbind->rsa_min_size = *x;
3426
9
        }
3427
9
        break;
3428
#ifdef WITH_GSSAPI
3429
    case SSH_BIND_OPTIONS_GSSAPI_KEY_EXCHANGE:
3430
        if (value == NULL) {
3431
            ssh_set_error_invalid(sshbind);
3432
            return -1;
3433
        } else {
3434
            bool *x = (bool *)value;
3435
            sshbind->gssapi_key_exchange = *x;
3436
        }
3437
        break;
3438
    case SSH_BIND_OPTIONS_GSSAPI_KEY_EXCHANGE_ALGS:
3439
        if (value == NULL) {
3440
            ssh_set_error_invalid(sshbind);
3441
            return -1;
3442
        } else {
3443
            char *ret = NULL;
3444
            SAFE_FREE(sshbind->gssapi_key_exchange_algs);
3445
            ret = ssh_find_all_matching(GSSAPI_KEY_EXCHANGE_SUPPORTED, value);
3446
            if (ret == NULL) {
3447
                ssh_set_error(
3448
                    sshbind,
3449
                    SSH_REQUEST_DENIED,
3450
                    "GSSAPI key exchange algorithms not supported or invalid");
3451
                return -1;
3452
            }
3453
            sshbind->gssapi_key_exchange_algs = ret;
3454
        }
3455
        break;
3456
#endif /* WITH_GSSAPI */
3457
9
    default:
3458
0
        ssh_set_error(sshbind,
3459
0
                      SSH_REQUEST_DENIED,
3460
0
                      "Unknown ssh option %d",
3461
0
                      type);
3462
0
        return -1;
3463
0
        break;
3464
59.6k
    }
3465
3466
58.0k
    return 0;
3467
59.6k
}
3468
3469
static char *ssh_bind_options_expand_escape(ssh_bind sshbind, const char *s)
3470
0
{
3471
0
    char *buf = NULL;
3472
0
    char *r = NULL;
3473
0
    char *x = NULL;
3474
0
    const char *p = NULL;
3475
0
    size_t i, l;
3476
3477
0
    r = ssh_path_expand_tilde(s);
3478
0
    if (r == NULL) {
3479
0
        ssh_set_error_oom(sshbind);
3480
0
        return NULL;
3481
0
    }
3482
3483
0
    if (strlen(r) > MAX_BUF_SIZE) {
3484
0
        ssh_set_error(sshbind, SSH_FATAL, "string to expand too long");
3485
0
        free(r);
3486
0
        return NULL;
3487
0
    }
3488
3489
0
    buf = malloc(MAX_BUF_SIZE);
3490
0
    if (buf == NULL) {
3491
0
        ssh_set_error_oom(sshbind);
3492
0
        free(r);
3493
0
        return NULL;
3494
0
    }
3495
3496
0
    p = r;
3497
0
    buf[0] = '\0';
3498
3499
0
    for (i = 0; *p != '\0'; p++) {
3500
0
        if (*p != '%') {
3501
0
            buf[i] = *p;
3502
0
            i++;
3503
0
            if (i >= MAX_BUF_SIZE) {
3504
0
                free(buf);
3505
0
                free(r);
3506
0
                return NULL;
3507
0
            }
3508
0
            buf[i] = '\0';
3509
0
            continue;
3510
0
        }
3511
3512
0
        p++;
3513
0
        if (*p == '\0') {
3514
0
            break;
3515
0
        }
3516
3517
0
        switch (*p) {
3518
0
            case 'd':
3519
0
                x = strdup(sshbind->config_dir);
3520
0
                break;
3521
0
            default:
3522
0
                ssh_set_error(sshbind, SSH_FATAL,
3523
0
                        "Wrong escape sequence detected");
3524
0
                free(buf);
3525
0
                free(r);
3526
0
                return NULL;
3527
0
        }
3528
3529
0
        if (x == NULL) {
3530
0
            ssh_set_error_oom(sshbind);
3531
0
            free(buf);
3532
0
            free(r);
3533
0
            return NULL;
3534
0
        }
3535
3536
0
        i += strlen(x);
3537
0
        if (i >= MAX_BUF_SIZE) {
3538
0
            ssh_set_error(sshbind, SSH_FATAL,
3539
0
                    "String too long");
3540
0
            free(buf);
3541
0
            free(x);
3542
0
            free(r);
3543
0
            return NULL;
3544
0
        }
3545
0
        l = strlen(buf);
3546
0
        strlcpy(buf + l, x, MAX_BUF_SIZE - l);
3547
0
        buf[i] = '\0';
3548
0
        SAFE_FREE(x);
3549
0
    }
3550
3551
0
    free(r);
3552
3553
    /* strip the unused space by realloc */
3554
0
    x = realloc(buf, strlen(buf) + 1);
3555
0
    if (x == NULL) {
3556
0
        ssh_set_error_oom(sshbind);
3557
0
        free(buf);
3558
0
    }
3559
0
    return x;
3560
0
}
3561
3562
/**
3563
 * @brief Parse a ssh bind options configuration file.
3564
 *
3565
 * This parses the options file and set them to the ssh_bind handle provided. If
3566
 * an option was previously set, it is overridden. If the global configuration
3567
 * hasn't been processed yet, it is processed prior to the provided file.
3568
 *
3569
 * @param  sshbind      SSH bind handle
3570
 *
3571
 * @param  filename     The options file to use; if NULL only the global
3572
 *                      configuration is parsed and applied (if it hasn't been
3573
 *                      processed before).
3574
 *
3575
 * @return 0 on success, < 0 on error.
3576
 */
3577
int ssh_bind_options_parse_config(ssh_bind sshbind, const char *filename)
3578
0
{
3579
0
    int rc = 0;
3580
0
    char *expanded_filename = NULL;
3581
3582
0
    if (sshbind == NULL) {
3583
0
        return -1;
3584
0
    }
3585
3586
    /* If the global default configuration hasn't been processed yet, process it
3587
     * before the provided configuration. */
3588
0
    if (!(sshbind->config_processed)) {
3589
0
        if (ssh_file_readaccess_ok(GLOBAL_BIND_CONFIG)) {
3590
0
            rc = ssh_bind_config_parse_file(sshbind, GLOBAL_BIND_CONFIG);
3591
#ifdef USR_GLOBAL_BIND_CONFIG
3592
        } else {
3593
            rc = ssh_bind_config_parse_file(sshbind, USR_GLOBAL_BIND_CONFIG);
3594
#endif
3595
0
        }
3596
0
        if (rc != 0) {
3597
0
            return rc;
3598
0
        }
3599
0
        sshbind->config_processed = true;
3600
0
    }
3601
3602
0
    if (filename != NULL) {
3603
0
        expanded_filename = ssh_bind_options_expand_escape(sshbind, filename);
3604
0
        if (expanded_filename == NULL) {
3605
0
            return -1;
3606
0
        }
3607
3608
        /* Apply the user provided configuration */
3609
0
        rc = ssh_bind_config_parse_file(sshbind, expanded_filename);
3610
0
        free(expanded_filename);
3611
0
    }
3612
3613
0
    return rc;
3614
0
}
3615
3616
#endif
3617
3618
/** @} */
3619