Coverage Report

Created: 2025-11-24 06:19

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