Coverage Report

Created: 2024-05-20 06:25

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