Coverage Report

Created: 2025-07-04 06:59

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