forked from erlang/otp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathssh.hrl
More file actions
1466 lines (1212 loc) · 56.3 KB
/
Copy pathssh.hrl
File metadata and controls
1466 lines (1212 loc) · 56.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
%%
%% %CopyrightBegin%
%%
%% SPDX-License-Identifier: Apache-2.0
%%
%% Copyright Ericsson AB 2004-2026. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
%%
%%
%% SSH definitions
%%
-ifndef(SSH_HRL).
-define(SSH_HRL, 1).
-define(SSH_DEFAULT_PORT, 22).
-define(SSH_MAX_PACKET_SIZE, (256*1024)).
-define(REKEY_DATA_TIMOUT, 60000).
-define(DEFAULT_PROFILE, default).
-define(DEFAULT_TRANSPORT, {tcp, gen_tcp, tcp_closed} ).
-define(DEFAULT_TIMEOUT, 5000).
-define(MAX_RND_PADDING_LEN, 15).
%% Hybrid KEX limits
-define(MLKEM768_PUBLICKEY_SIZE, 1184).
-define(MLKEM768_CIPHERTEXT_SIZE, 1088).
-define(X25519_PUBLICKEY_SIZE, 32).
-define(MLKEM768_INIT_SIZE, ?MLKEM768_PUBLICKEY_SIZE + ?X25519_PUBLICKEY_SIZE). % NIST FIPS 203: 1184 + 32
-define(MLKEM768_REPLY_SIZE, ?MLKEM768_CIPHERTEXT_SIZE + ?X25519_PUBLICKEY_SIZE). % NIST FIPS 203: 1088 + 32
%% Pre-authentication message size limits
%% Transport layer (RFC 4253 Section 11)
%% OpenSSH uses 1024-byte C buffer (packet.c, commit d4a8b7e34);
%% vsnprintf reserves 1 byte for null terminator, max wire length is
%% 1023
-define(MAX_DISCONNECT_DESC_SIZE, 1023).
%% Practical limit (RFC 3066: subtags max 8 chars, no overall limit
%% specified)
-define(MAX_LANG_SIZE, 64).
% RFC 4253 Section 6.1 (32768 byte payload)
-define(MAX_IGNORE_DATA_SIZE, 32768).
%% Limit for receiving debug messages from peers; intentionally larger
%% than OpenSSH (1023 bytes, packet.c commit d4a8b7e34) to accommodate
%% verbose diagnostics from various SSH implementations
-define(MAX_DEBUG_MSG_SIZE, 4096).
%% Key exchange (RFC 4253 Section 7-8, RFC 4419, RFC 5656, RFC 8270)
%% RFC 4253 Section 6.1 (32768 byte payload, real-world: 500-2000 bytes)
-define(MAX_KEXINIT_SIZE, 32768).
% RFC 4253 Section 8 (8192-bit = 1024 bytes + mpint encoding overhead)
-define(MAX_DH_MPINT_SIZE, 1032).
%% RFC 5656 Section 4 (P-521 uncompressed: 133 bytes)
-define(MAX_ECDH_POINT_SIZE, 256).
%% Service request (RFC 4253 Section 10, RFC 8308)
%% RFC 4251 Section 6 (SSH name limit)
-define(MAX_SERVICE_NAME_SIZE, 64).
% Practical limit (RFC 8308 defines no maximum)
-define(MAX_EXT_INFO_SIZE, 8192).
% Practical limit (typical: 200-400 bytes, allows future extensions)
-define(MAX_EXT_VALUE_SIZE, 1024).
%% Cryptographic limits
%% Accommodates RSA-8192 keys (~1046 bytes, largest supported key type)
%% and post-quantum algorithms (Dilithium5: 2592 bytes). Other key
%% types are much smaller: DSA-1024 (~431 bytes), ECDSA P-521 (~172
%% bytes), Ed25519 (~51 bytes)
-define(MAX_HOST_KEY_SIZE, 4096).
%% Accommodates RSA-8192 signatures (~1039 bytes) and post-quantum
%% algorithms (Dilithium5: 4595 bytes). Provides consistent PQ
%% readiness with MAX_HOST_KEY_SIZE.
-define(MAX_SIGNATURE_SIZE, 5120).
-define(SUPPORTED_AUTH_METHODS, "publickey,keyboard-interactive,password").
-define(FALSE, 0).
-define(TRUE, 1).
%% basic binary constructors
-define(BOOLEAN(X), (X):8/unsigned-big-integer).
-define(BYTE(X), (X):8/unsigned-big-integer).
-define(UINT16(X), (X):16/unsigned-big-integer).
-define(UINT32(X), (X):32/unsigned-big-integer).
-define(UINT64(X), (X):64/unsigned-big-integer).
-define(STRING(X), ?UINT32((byte_size(X))), (X)/binary).
-define(DEC_BIN(X,Len), ?UINT32(Len), X:Len/binary ).
-define(DEC_INT(I,Len), ?UINT32(Len), I:Len/big-signed-integer-unit:8 ).
-define(DEC_MPINT(I,Len), ?UINT32(Len), I:Len/big-signed-integer-unit:8 ).
%% building macros
-define(boolean(X),
case X of
true -> <<?BOOLEAN(1)>>;
false -> (<<?BOOLEAN(0)>>)
end).
-define(byte(X), << ?BYTE(X) >> ).
-define(uint16(X), << ?UINT16(X) >> ).
-define(uint32(X), << ?UINT32(X) >> ).
-define(uint64(X), << ?UINT64(X) >> ).
-define(string_utf8(X), << ?STRING(unicode:characters_to_binary(X)) >> ).
-define(string(X), ?string_utf8(X)).
-define(binary(X), << ?STRING(X) >>).
-define('2bin'(X), (if is_binary(X) -> X;
is_list(X) -> list_to_binary(X);
X==undefined -> <<>>
end) ).
%% encoding macros
-define('E...'(X), ?'2bin'(X)/binary ).
-define(Eboolean(X), ?BOOLEAN(case X of
true -> ?TRUE;
false -> ?FALSE
end) ).
-define(Ebyte(X), ?BYTE(X) ).
-define(Euint32(X), ?UINT32(X) ).
-define(Estring(X), ?STRING(?'2bin'(X)) ).
-define(Estring_utf8(X), ?string_utf8(X)/binary ).
-define(Ename_list(X), ?STRING(ssh_bits:name_list(X)) ).
-define(Empint(X), (ssh_bits:mpint(X))/binary ).
-define(Ebinary(X), ?STRING(X) ).
%% Other macros
-define(to_binary(X), (try iolist_to_binary(X) catch _:_ -> unicode:characters_to_binary(X) end) ).
%% Cipher details
-define(SSH_CIPHER_NONE, 0).
-define(SSH_CIPHER_3DES, 3).
-define(SSH_CIPHER_AUTHFILE, ?SSH_CIPHER_3DES).
%% PKBDF2 password hashing parameters
-define(SSH_PKBDF2_DIGEST, sha256).
-define(SSH_PKBDF2_ITERATIONS, 600_000).
-define(SSH_PKBDF2_KEYLENGTH, 32). %% matches digest output length
%% Option access macros
-define(do_get_opt(C,K,O), ssh_options:get_value(C,K,O, ?MODULE,?LINE)).
-define(do_get_opt(C,K,O,D), ssh_options:get_value(C,K,O,?LAZY(D),?MODULE,?LINE)).
-define(LAZY(D), fun()-> D end).
-define(GET_OPT(Key,Opts), ?do_get_opt(user_options, Key,Opts ) ).
-define(GET_OPT(Key,Opts,Def), ?do_get_opt(user_options, Key,Opts,Def) ).
-define(GET_INTERNAL_OPT(Key,Opts), ?do_get_opt(internal_options,Key,Opts ) ).
-define(GET_INTERNAL_OPT(Key,Opts,Def), ?do_get_opt(internal_options,Key,Opts,Def) ).
-define(GET_SOCKET_OPT(Key,Opts), ?do_get_opt(socket_options, Key,Opts ) ).
-define(GET_SOCKET_OPT(Key,Opts,Def), ?do_get_opt(socket_options, Key,Opts,Def) ).
-define(GET_ALIVE_OPT(Opts),
begin
#{count_max := C, interval := I} = ?do_get_opt(user_options, alive, Opts),
{C, I}
end).
-define(do_put_opt(C,KV,O), ssh_options:put_value(C,KV,O, ?MODULE,?LINE)).
-define(PUT_OPT(KeyVal,Opts), ?do_put_opt(user_options, KeyVal,Opts) ).
-define(PUT_INTERNAL_OPT(KeyVal,Opts), ?do_put_opt(internal_options,KeyVal,Opts) ).
-define(PUT_SOCKET_OPT(KeyVal,Opts), ?do_put_opt(socket_options, KeyVal,Opts) ).
-define(do_del_opt(C,K,O), ssh_options:delete_key(C,K,O, ?MODULE,?LINE)).
-define(DELETE_INTERNAL_OPT(Key,Opts), ?do_del_opt(internal_options,Key,Opts) ).
%% Types
-type role() :: client | server .
-type host() :: string() | inet:ip_address() | loopback .
-doc """
The socket is supposed to be result of a [gen_tcp:connect](`gen_tcp:connect/3`)
or a [gen_tcp:accept](`gen_tcp:accept/1`). The socket must be in passive mode
(that is, opened with the option `{active,false})`.
""".
-type open_socket() :: gen_tcp:socket().
-doc """
Defines a subsystem in the daemon.
The `subsystem_name` is the name that a client requests to start with for
example `ssh_connection:subsystem/4`.
The `channel_callback` is the module that implements the `m:ssh_server_channel`
(replaces ssh_daemon_channel) behaviour in the daemon. See the section
[Creating a Subsystem](using_ssh.md#usersguide_creating_a_subsystem) in the
User's Guide for more information and an example.
If the subsystems option is not present, the default is an empty list
and no subsystems are enabled.
To enable the SFTP subsystem:
```
ssh:daemon(Port, [{subsystems, [ssh_sftpd:subsystem_spec([])]} | Options])
```
""".
-doc(#{group => <<"Daemon Options">>}).
-type subsystem_spec() :: {Name::string(), mod_args()} .
-doc(#{group => <<"Common Options">>}).
-type algs_list() :: list( alg_entry() ).
-doc(#{group => <<"Common Options">>}).
-type alg_entry() :: {kex, [kex_alg()]}
| {public_key, [pubkey_alg()]}
| {cipher, double_algs(cipher_alg())}
| {mac, double_algs(mac_alg())}
| {compression, double_algs(compression_alg())} .
-doc(#{group => <<"Common Options">>}).
-type kex_alg() ::
'diffie-hellman-group-exchange-sha256' |
'diffie-hellman-group14-sha256' |
'diffie-hellman-group16-sha512' |
'diffie-hellman-group18-sha512' |
'curve25519-sha256' |
'curve25519-sha256@libssh.org' |
'curve448-sha512' |
'ecdh-sha2-nistp256' |
'ecdh-sha2-nistp384' |
'ecdh-sha2-nistp521' |
'mlkem768x25519-sha256' |
legacy_kex_alg().
-doc(#{group => <<"Legacy Algorithms">>}).
-type legacy_kex_alg() ::
%% Gone in OpenSSH 7.3.p1
'diffie-hellman-group1-sha1' |
%% Gone in OpenSSH 8.2
'diffie-hellman-group14-sha1' |
'diffie-hellman-group-exchange-sha1'.
-doc(#{group => <<"Common Options">>}).
-type pubkey_alg() ::
'ecdsa-sha2-nistp256' |
'ecdsa-sha2-nistp384' |
'ecdsa-sha2-nistp521' |
'ssh-ed25519' |
'ssh-ed448' |
'rsa-sha2-256' |
'rsa-sha2-512' |
legacy_pubkey_alg().
-doc(#{group => <<"Legacy Algorithms">>}).
-type legacy_pubkey_alg() ::
'ssh-rsa' |
%% Gone in OpenSSH 7.3.p1:
'ssh-dss'.
-doc(#{group => <<"Common Options">>}).
-type cipher_alg() ::
'aes128-ctr' |
'aes128-gcm@openssh.com' |
'aes192-ctr' |
'aes256-ctr' |
'aes256-gcm@openssh.com' |
'chacha20-poly1305@openssh.com' |
disabled_cipher_alg() |
legacy_cipher_alg().
-doc(#{group => <<"Common Options">>}).
-type disabled_cipher_alg() ::
%% not enabled by default as it might not be compatible with
%% other implemenations
%% read more in commit message of a895fc7303497f1795cf49360980abeb68be2223
'AEAD_AES_128_GCM' |
'AEAD_AES_256_GCM'.
-doc(#{group => <<"Legacy Algorithms">>}).
-type legacy_cipher_alg() ::
%% Gone in OpenSSH 7.6
'aes128-cbc' |
'aes192-cbc' |
'aes256-cbc' |
'3des-cbc'.
-doc(#{group => <<"Common Options">>}).
-type mac_alg() ::
'hmac-sha1' |
'hmac-sha1-etm@openssh.com' |
'hmac-sha2-256' |
'hmac-sha2-512' |
'hmac-sha2-256-etm@openssh.com' |
'hmac-sha2-512-etm@openssh.com' |
disabled_mac_alg() |
legacy_mac_alg().
-doc(#{group => <<"Common Options">>}).
-type disabled_mac_alg() ::
'AEAD_AES_128_GCM' |
'AEAD_AES_256_GCM'.
-doc(#{group => <<"Legacy Algorithms">>}).
-type legacy_mac_alg() ::
'hmac-sha1-96'.
-doc(#{group => <<"Common Options">>}).
-type compression_alg() :: 'none' |
'zlib' |
'zlib@openssh.com'
.
-doc """
List of algorithms to use in the algorithm negotiation. The default
`t:algs_list/0` can be obtained from `default_algorithms/0`.
If an alg_entry() is missing in the algs_list(), the default value is used for
that entry.
Here is an example of this option:
```erlang
{preferred_algorithms,
[{public_key,['ssh-rsa','ssh-dss']},
{cipher,[{client2server,['aes128-ctr']},
{server2client,['aes128-cbc','3des-cbc']}]},
{mac,['hmac-sha2-256','hmac-sha1']},
{compression,[none,zlib]}
]
}
```
The example specifies different algorithms in the two directions (client2server
and server2client), for cipher but specifies the same algorithms for mac and
compression in both directions. The kex (key exchange) is implicit but
public_key is set explicitly.
For background and more examples see the
[User's Guide](configure_algos.md#introduction).
If an algorithm name occurs more than once in a list, the behaviour is
undefined. The tags in the property lists are also assumed to occur at most one
time.
> #### Warning {: .warning }
>
> Changing the values can make a connection less secure. Do not change unless
> you know exactly what you are doing. If you do not understand the values then
> you are not supposed to change them.
""".
-doc(#{group => <<"Common Options">>}).
-type double_algs(AlgType) :: list( {client2server,[AlgType]} | {server2client,[AlgType]} )
| [AlgType].
-doc """
Modifies the list of algorithms to use in the algorithm negotiation. The
modifications are applied after the option `preferred_algorithms` (if existing)
is applied.
The algorithm for modifications works like this:
- Input is the `t:modify_algs_list/0` and a set of algorithms `A` obtained from
the `preferred_algorithms` option if existing, or else from the
[ssh:default_algorithms/0](`default_algorithms/0`).
- The head of the `t:modify_algs_list/0` modifies `A` giving the result `A'`.
The possible modifications are:
- Append or prepend supported but not enabled algorithm(s) to the list of
algorithms. If the wanted algorithms already are in `A` they will first be
removed and then appended or prepended,
- Remove (rm) one or more algorithms from `A`.
- Repeat the modification step with the tail of `t:modify_algs_list/0` and the
resulting `A'`.
If an unsupported algorithm is in the `t:modify_algs_list/0`, it will be
silently ignored
If there are more than one modify_algorithms options, the result is undefined.
Here is an example of this option:
```text
{modify_algorithms,
[{prepend, [{kex, ['diffie-hellman-group1-sha1']}],
{rm, [{compression, [none]}]}
]
}
```
The example specifies that:
- the old key exchange algorithm 'diffie-hellman-group1-sha1' should be the main
alternative. It will be the main alternative since it is prepened to the list
- The compression algorithm none (= no compression) is removed so compression is
enforced
For background and more examples see the
[User's Guide](configure_algos.md#introduction).
""".
-doc(#{group => <<"Common Options">>}).
-type modify_algs_list() :: list( {append,algs_list()} | {prepend,algs_list()} | {rm,algs_list()} ) .
-type internal_options() :: ssh_options:private_options().
-type socket_options() :: [gen_tcp:connect_option() | gen_tcp:listen_option()].
-doc(#{group => <<"Client Options">>}).
-type client_options() :: [ client_option() ] .
-doc(#{group => <<"Daemon Options">>}).
-type daemon_options() :: [ daemon_option() ].
-doc(#{group => <<"Common Options">>}).
-type common_options() :: [ common_option() ].
-doc """
The options above can be used both in clients and in daemons (servers). They are
further explained below.
""".
-doc(#{group => <<"Common Options">>}).
-type common_option() ::
ssh_file:user_dir_common_option()
| profile_common_option()
| max_idle_time_common_option()
| max_log_item_len_common_option()
| key_cb_common_option()
| disconnectfun_common_option()
| unexpectedfun_common_option()
| ssh_msg_debug_fun_common_option()
| rekey_limit_common_option()
| id_string_common_option()
| pref_public_key_algs_common_option()
| preferred_algorithms_common_option()
| modify_algorithms_common_option()
| auth_methods_common_option()
| inet_common_option()
| fd_common_option()
| alive_common_option()
.
-doc """
Used together with `ip-address` and `port` to uniquely identify a ssh daemon.
This can be useful in a virtualized environment, where there can be more that
one server that has the same `ip-address` and `port`. If this property is not
explicitly set, it is assumed that the the `ip-address` and `port` uniquely
identifies the SSH daemon.
""".
-doc(#{group => <<"Common Options">>}).
-type profile_common_option() :: {profile, atom() }.
-doc """
Sets a time-out on a connection when no channels are open. Defaults to
`infinity`. The unit is milliseconds.
The timeout is not active until channels are started, so it does not limit the
time from the connection creation to the first channel opening.
For more information about timeouts, see the
[Timeouts section ](hardening.md#timeouts)in the User's Guide
[Hardening](hardening.md) chapter.
""".
-doc(#{group => <<"Common Options">>}).
-type max_idle_time_common_option() :: {idle_time, timeout()}.
-doc(#{group => <<"Common Options">>}).
-type rekey_limit_common_option() :: {rekey_limit, Bytes::limit_bytes() |
{Minutes::limit_time(), Bytes::limit_bytes()}
}.
-doc """
Sets a limit for the size of a logged item excluding a header. The unit is bytes
and the value defaults to 500.
""".
-doc(#{group => <<"Common Options">>}).
-type max_log_item_len_common_option() :: {max_log_item_len, limit_bytes()} .
-doc(#{group => <<"Common Options">>}).
-type limit_bytes() :: non_neg_integer() | infinity . % non_neg_integer due to compatibility
-doc """
Sets the limit when rekeying is to be initiated. Both the max time and max
amount of data could be configured:
- `{Minutes, Bytes}` initiate rekeying when any of the limits are reached.
- `Bytes` initiate rekeying when `Bytes` number of bytes are transferred, or at
latest after one hour.
When a rekeying is done, both the timer and the byte counter are restarted.
Defaults to one hour and one GByte.
If `Minutes` is set to `infinity`, no rekeying will ever occur due to that max
time has passed. Setting `Bytes` to `infinity` will inhibit rekeying after a
certain amount of data has been transferred. If the option value is set to
`{infinity, infinity}`, no rekeying will be initiated. Note that rekeying
initiated by the peer will still be performed.
""".
-doc(#{group => <<"Common Options">>}).
-type limit_time() :: pos_integer() | infinity .
-doc """
Module implementing the behaviour `m:ssh_client_key_api` and/or
`m:ssh_server_key_api`. Can be used to customize the handling of public keys. If
callback options are provided along with the module name, they are made
available to the callback module via the options passed to it under the key
'key_cb_private'.
The `Opts` defaults to `[]` when only the `Module` is specified.
The default value of this option is `{ssh_file, []}`. See also the manpage of
`m:ssh_file`.
A call to the call-back function `F` will be
```text
Module:F(..., [{key_cb_private,Opts}|UserOptions])
```
where `...` are arguments to `F` as in `m:ssh_client_key_api` and/or
`m:ssh_server_key_api`. The `UserOptions` are the options given to
[ssh:connect](`connect/3`), [ssh:shell](`shell/1`) or [ssh:daemon](`daemon/2`).
""".
-doc(#{group => <<"Common Options">>}).
-type key_cb_common_option() :: {key_cb, Module::atom() | {Module::atom(),Opts::[term()]} } .
-doc "Provides a fun to implement your own logging or other handling at disconnects.".
-doc(#{group => <<"Common Options">>}).
-type disconnectfun_common_option() ::
{disconnectfun, fun((Reason::term()) -> void | any()) }.
-doc """
Provides a fun to implement your own logging or other action when an unexpected
message arrives. If the fun returns `report` the usual info report is issued but
if `skip` is returned no report is generated.
""".
-doc(#{group => <<"Common Options">>}).
-type unexpectedfun_common_option() ::
{unexpectedfun, fun((Message::term(),{Host::term(),Port::term()}) -> report | skip ) }.
-doc """
Provide a fun to implement your own logging of the SSH message SSH_MSG_DEBUG.
The last three parameters are from the message, see
[RFC 4253, section 11.3](https://tools.ietf.org/html/rfc4253#section-11.3). The
`t:connection_ref/0` is the reference to the connection on which the message
arrived. The return value from the fun is not checked.
The default behaviour is ignore the message. To get a printout for each message
with `AlwaysDisplay = true`, use for example
`{ssh_msg_debug_fun, fun(_,true,M,_)-> io:format("DEBUG: ~p~n", [M]) end}`
""".
-doc(#{group => <<"Common Options">>}).
-type ssh_msg_debug_fun_common_option() ::
{ssh_msg_debug_fun, fun((ssh:connection_ref(),AlwaysDisplay::boolean(),Msg::binary(),LanguageTag::binary()) -> any()) } .
-doc """
The string the daemon will present to a connecting peer initially. The default
value is "Erlang/VSN" where VSN is the ssh application version number.
The value `random` will cause a random string to be created at each connection
attempt. This is to make it a bit more difficult for a malicious peer to find
the ssh software brand and version.
The value `{random, Nmin, Nmax}` will make a random string with at least `Nmin`
characters and at most `Nmax` characters.
""".
-doc(#{group => <<"Common Options">>}).
-type id_string_common_option() :: {id_string, string() | random | {random,Nmin::pos_integer(),Nmax::pos_integer()} }.
-doc """
List of user (client) public key algorithms to try to use.
The default value is the `public_key` entry in the list returned by
[ssh:default_algorithms/0](`default_algorithms/0`).
If there is no public key of a specified type available, the corresponding entry
is ignored. Note that the available set is dependent on the underlying cryptolib
and current user's public keys.
See also the option [`user_dir`](`t:ssh_file:user_dir_common_option/0`) for
specifying the path to the user's keys.
""".
-doc(#{group => <<"Common Options">>}).
-type pref_public_key_algs_common_option() :: {pref_public_key_algs, [pubkey_alg()] } .
-doc(#{group => <<"Common Options">>}).
-type preferred_algorithms_common_option():: {preferred_algorithms, algs_list()}.
-doc(#{group => <<"Common Options">>}).
-type modify_algorithms_common_option() :: {modify_algorithms, modify_algs_list()}.
-doc """
Comma-separated string that determines which authentication methods that the
client shall support and in which order they are tried. Defaults to
`"publickey,keyboard-interactive,password"`
Note that the client is free to use any order and to exclude methods.
""".
-doc(#{group => <<"Common Options">>}).
-type auth_methods_common_option() :: {auth_methods, string() }.
-doc "IP version to use when the host address is specified as `any`.".
-doc(#{group => <<"Common Options">>}).
-type inet_common_option() :: {inet, inet | inet6} .
-doc """
Allows an existing file-descriptor to be used (passed on to the transport
protocol).
""".
-doc(#{group => <<"Common Options">>}).
-type fd_common_option() :: {fd, gen_tcp:socket()} .
-doc """
This option is used to configure the alive messages. Alive messages are sent
through the encrypted channel and are typically used to detect that a
connection became unresponsive.
`count_max` sets the maximum number
of alive messages which may be sent without receiving any messages back
from the peer. If this threshold is reached the connection will be terminated.
`interval` sets a timeout interval, in milliseconds, after which, if no data
has been received from the peer, a message to request a response from the peer is sent.
The default is `#{count_max => 3, interval => infinity}`, which means that alive
messages will not be sent to the peer, since the `interval` is set to `infinity`.
No alive messages are sent during renegotiation, however, a timeout derived from
the alive parameters is set to ensure that unresponsive connections are terminated.
""".
-doc(#{group => <<"Common Options">>}).
-type alive_common_option() :: {alive, #{count_max := CountMax::pos_integer(),
interval := Interval::timeout()}}.
-doc """
Experimental options that should not to be used in products.
""".
-type experimental_common_options() ::
{transport, {atom(),atom(),atom()} }
| {vsn, {non_neg_integer(),non_neg_integer()} }
| {tstflg, list(term())}
| ssh_file:user_dir_fun_common_option()
| {max_random_length_padding, non_neg_integer()} .
-doc """
Options for [clients](`connect/3`). The individual options are further explained
below or by following the hyperlinks.
Note that not every `t:gen_tcp:connect_option/0` is accepted. See
`set_sock_opts/2` for a list of prohibited options.
Also note that setting a `t:gen_tcp:connect_option/0` could change the socket in
a way that impacts the ssh client's behaviour negatively. You use it on your own
risk.
""".
-doc(#{group => <<"Client Options">>}).
-type client_option() ::
ssh_file:pubkey_passphrase_client_options()
| host_accepting_client_options()
| authentication_client_options()
| diffie_hellman_group_exchange_client_option()
| connect_timeout_client_option()
| recv_ext_info_client_option()
| gen_tcp:connect_option()
| common_option()
| experimental_client_options() .
-doc """
Experimental options that should not to be used in products.
""".
-type experimental_client_options() ::
{keyboard_interact_fun, fun((Name::iodata(),
Instruction::iodata(),
Prompts::[{Prompt::iodata(), Echo::boolean()}] ) ->
[Response::iodata()])}
| experimental_common_options().
-doc """
- **`silently_accept_hosts`{: #hardening_client_options-silently_accept_hosts
}** - This option guides the `connect` function on how to act when the
connected server presents a Host Key that the client has not seen before. The
default is to ask the user with a question on stdio of whether to accept or
reject the new Host Key. See the option
[`user_dir`](`t:ssh_file:user_dir_common_option/0`) for specifying the path to
the file `known_hosts` where previously accepted Host Keys are recorded. See
also the option [key_cb](`t:key_cb_common_option/0`) for the general way to
handle keys.
The option can be given in three different forms as seen
[above](`t:accept_hosts/0`):
- The value is a `t:boolean/0`. The value `true` will make the client accept
any unknown Host Key without any user interaction. The value `false`
preserves the default behaviour of asking the user on stdio.
- An `t:accept_callback/0` will be called and the boolean return value `true`
will make the client accept the Host Key. A return value of `false` will
make the client to reject the Host Key and as a result the connection will
be closed. The arguments to the fun are:
- `PeerName` \- a string with the name or address of the remote host.
- `FingerPrint` \- the fingerprint of the Host Key as
`hostkey_fingerprint/1` calculates it.
- A tuple `{HashAlgoSpec, accept_callback}`. The `HashAlgoSpec` specifies
which hash algorithm shall be used to calculate the fingerprint used in the
call of the `t:accept_callback/0`. The `HashALgoSpec` is either an atom or a
list of atoms as the first argument in `hostkey_fingerprint/2`. If it is a
list of hash algorithm names, the `FingerPrint` argument in the
`t:accept_callback/0` will be a list of fingerprints in the same order as
the corresponding name in the `HashAlgoSpec` list.
- **`user_interaction`** - If `false`, disables the client to connect to the
server if any user interaction is needed, such as accepting the server to be
added to the `known_hosts` file, or supplying a password.
Even if user interaction is allowed it can be suppressed by other options,
such as `silently_accept_hosts` and `password`. However, those options are not
always desirable to use from a security point of view.
Defaults to `true`.
- **`save_accepted_host`** - If `true`, the client saves an accepted host key to
avoid the accept question the next time the same host is connected. If the
option [`key_cb`](`t:key_cb_common_option/0`) is not present, the key is saved
in the file "known_hosts". See option
[`user_dir`](`t:ssh_file:user_dir_common_option/0`) for the location of that
file.
If `false`, the key is not saved and the key will still be unknown at the next
access of the same host.
Defaults to `true`
- **`quiet_mode`** - If `true`, the client does not print anything on
authorization.
Defaults to `false`
""".
-doc(#{group => <<"Client Options">>}).
-type host_accepting_client_options() ::
{silently_accept_hosts, accept_hosts()}
| {user_interaction, boolean()}
| {save_accepted_host, boolean()}
| {quiet_mode, boolean()} .
-doc(#{group => <<"Client Options">>}).
-type accept_hosts() :: boolean()
| accept_callback()
| {HashAlgoSpec::fp_digest_alg(), accept_callback()}.
-doc(#{group => <<"Client Options">>}).
-type fp_digest_alg() :: 'md5' | crypto:sha1() | crypto:sha2() .
-doc(#{group => <<"Client Options">>}).
-type accept_callback() :: fun((PeerName::string(), fingerprint() ) -> boolean()) % Old style
| fun((PeerName::string(), Port::inet:port_number(), fingerprint() ) -> boolean()) % New style
.
-doc(#{group => <<"Client Options">>}).
-type fingerprint() :: string() | [string()].
-doc """
- **`user`** - Provides the username. If this option is not given, `ssh` reads
from the environment (`LOGNAME` or `USER` on UNIX, `USERNAME` on Windows).
- **`password`** - Provides a password for password authentication. If this
option is not given, the user is asked for a password, if the password
authentication method is attempted.
""".
-doc(#{group => <<"Client Options">>}).
-type authentication_client_options() ::
{user, string()}
| {password, string()} .
-doc """
Sets the three diffie-hellman-group-exchange parameters that guides the
connected server in choosing a group. See
[RFC 4419](https://tools.ietf.org/html/rfc4419) for the details. The default
value is `{1024, 6144, 8192}`.
""".
-doc(#{group => <<"Client Options">>}).
-type diffie_hellman_group_exchange_client_option() ::
{dh_gex_limits, {Min::pos_integer(), I::pos_integer(), Max::pos_integer()} } .
-doc """
Sets a timeout on the transport layer connect time. For `m:gen_tcp` the time is
in milli-seconds and the default value is `infinity`.
See the parameter `Timeout` in `connect/4` for a timeout of the negotiation
phase.
""".
-doc(#{group => <<"Client Options">>}).
-type connect_timeout_client_option() :: {connect_timeout, timeout()} .
-doc """
Make the client tell the server that the client accepts extension negotiation,
that is, include `ext-info-c` in the kexinit message sent. See
[RFC 8308](https://tools.ietf.org/html/rfc8308) for details and
[ssh](ssh_app.md#supported-ext-info) for a list of currently implemented
extensions.
Default value is `true` which is compatible with other implementations not
supporting ext-info.
""".
-doc(#{group => <<"Client Options">>}).
-type recv_ext_info_client_option() :: {recv_ext_info, boolean()} .
-doc """
Options for [daemons](`daemon/1`). The individual options are further explained
below or by following the hyperlinks.
Note that not every `t:gen_tcp:listen_option/0` is accepted. See
`set_sock_opts/2` for a list of prohibited options.
Also note that setting a `t:gen_tcp:listen_option/0` could change the socket in
a way that impacts the ssh deamon's behaviour negatively. You use it on your own
risk.
""".
-doc(#{group => <<"Daemon Options">>}).
-type daemon_option() ::
subsystem_daemon_option()
| shell_daemon_option()
| exec_daemon_option()
| ssh_cli_daemon_option()
| tcpip_tunnel_out_daemon_option()
| tcpip_tunnel_in_daemon_option()
| authentication_daemon_options()
| diffie_hellman_group_exchange_daemon_option()
| max_initial_idle_time_daemon_option()
| negotiation_timeout_daemon_option()
| hello_timeout_daemon_option()
| hardening_daemon_options()
| callbacks_daemon_options()
| send_ext_info_daemon_option()
| gen_tcp:listen_option()
| common_option()
| experimental_daemon_options() .
-doc(#{group => <<"Daemon Options">>}).
-type subsystem_daemon_option() :: {subsystems, subsystem_specs()}.
-doc(#{group => <<"Daemon Options">>}).
-type subsystem_specs() :: [ subsystem_spec() ].
-doc(#{group => <<"Daemon Options">>,
equiv => 'shell_fun/2'/0}).
-type shell_daemon_option() :: {shell, shell_spec()} .
-doc(#{group => <<"Daemon Options">>}).
-type shell_spec() :: mod_fun_args() | shell_fun() | disabled .
-doc """
The default is `disabled`.
To enable the Erlang shell (the behavior from OTP versions prior to OTP @OTP-19969@):
```
ssh:daemon(Port, [{shell, {shell, start, []}} | Options])
```
""".
-doc(#{group => <<"Daemon Options">>,
equiv => 'shell_fun/2'/0}).
-type shell_fun() :: 'shell_fun/1'() | 'shell_fun/2'() .
-doc(#{group => <<"Daemon Options">>,
equiv => 'shell_fun/2'/0}).
-type 'shell_fun/1'() :: fun((User::string()) -> pid()) .
-doc """
Defines the read-eval-print loop used in a daemon when a shell is requested by
the client.
See the option [`exec-option`](`t:exec_daemon_option/0`) for a description of
how the daemon executes shell-requests and exec-requests depending on the shell-
and exec-options.
""".
-doc(#{group => <<"Daemon Options">>}).
-type 'shell_fun/2'() :: fun((User::string(), PeerAddr::inet:ip_address()) -> pid()).
-doc(#{group => <<"Daemon Options">>}).
-type exec_daemon_option() :: {exec, exec_spec()} .
-doc(#{group => <<"Daemon Options">>}).
-type exec_spec() :: {direct, exec_fun()} | disabled | deprecated_exec_opt() | erlang_eval.
-doc """
The default is `disabled`.
Value `erlang_eval` enables evaluation of Erlang terms via exec requests.
This works when the shell option is either `disabled` (no shell) or
`{shell, start, []}` (Erlang shell). It does not work with custom shells.
To restore the behavior from OTP versions prior to OTP @OTP-19969@, configure:
```
ssh:daemon(Port, [{shell, {shell, start, []}},
{exec, erlang_eval}
| Options])
```
For new code, consider using `{direct, Fun}` for more controlled exec handling.
""".
-doc(#{group => <<"Daemon Options">>}).
-type exec_fun() :: 'exec_fun/1'() | 'exec_fun/2'() | 'exec_fun/3'().
-doc(#{group => <<"Daemon Options">>}).
-type 'exec_fun/1'() :: fun((Cmd::string()) -> exec_result()) .
-doc(#{group => <<"Daemon Options">>}).
-type 'exec_fun/2'() :: fun((Cmd::string(), User::string()) -> exec_result()) .
-doc(#{group => <<"Daemon Options">>}).
-type 'exec_fun/3'() :: fun((Cmd::string(), User::string(), ClientAddr::ip_port()) -> exec_result()) .
-doc """
This option changes how the daemon executes exec-requests from clients. The term
in the return value is formatted to a string if it is a non-string type. No
trailing newline is added in the ok-case.
See the User's Guide section on
[One-Time Execution](using_ssh.md#one-time-execution) for examples.
Error texts are returned on channel-type 1 which usually is piped to `stderr` on
e.g Linux systems. Texts from a successful execution are returned on
channel-type 0 and will in similar manner be piped to `stdout`. The exit-status
code is set to 0 for success and 255 for errors. The exact results presented on
the client side depends on the client and the client's operating system.
In case of the `{direct, exec_fun()}` variant or no exec-option at all, all
reads from `standard_input` will be from the received data-events of type 0.
Those are sent by the client. Similarly all writes to `standard_output` will be
sent as data-events to the client. An OS shell client like the command 'ssh'
will usually use stdin and stdout for the user interface.
The option cooperates with the daemon-option
[`shell`](`t:shell_daemon_option/0`) in the following way:
- **1\. If neither the [`exec-option`](`t:exec_daemon_option/0`) nor the
[`shell-option`](`t:shell_daemon_option/0`) is present:** - The default Erlang
evaluator is used both for exec and shell requests. The result is returned to
the client.
- **2\. If the [`exec_spec`](`t:exec_daemon_option/0`)'s value is `disabled`
(the [`shell-option`](`t:shell_daemon_option/0`) may or may not be
present):** - No exec-requests are executed but shell-requests are not
affected, they follow the [`shell_spec`](`t:shell_daemon_option/0`)'s value.
- **3\. If the [`exec-option`](`t:exec_daemon_option/0`) is present and the
[`exec_spec`](`t:exec_daemon_option/0`) value =/= `disabled` (the
[`shell-option`](`t:shell_daemon_option/0`) may or may not be present):** -
The [`exec_spec`](`t:exec_daemon_option/0`) `fun()` is called with the same
number of parameters as the arity of the fun, and the result is returned to
the client. Shell-requests are not affected, they follow the
[`shell_spec`](`t:shell_daemon_option/0`)'s value.
- **4\. If the [`exec-option`](`t:exec_daemon_option/0`) is absent, and the
[`shell-option`](`t:shell_daemon_option/0`) is present with the default Erlang
shell as the [`shell_spec`](`t:shell_daemon_option/0`)'s value:** - The
default Erlang evaluator is used both for exec and shell requests. The result
is returned to the client.
- **5\. If the [`exec-option`](`t:exec_daemon_option/0`) is absent, and the
[`shell-option`](`t:shell_daemon_option/0`) is present with a value that is
neither the default Erlang shell nor the value `disabled`:** - The
exec-request is not evaluated and an error message is returned to the client.
Shell-requests are executed according to the value of the
[`shell_spec`](`t:shell_daemon_option/0`).
- **6\. If the [`exec-option`](`t:exec_daemon_option/0`) is absent, and the
[`shell_spec`](`t:shell_daemon_option/0`)'s value is `disabled`:** - Exec
requests are executed by the default shell, but shell-requests are not
executed.
If a custom CLI is installed (see the option
[`ssh_cli`](`t:ssh_cli_daemon_option/0`)) the rules above are replaced by thoose
implied by the custom CLI.
> #### Note {: .info }
>
> The [`exec-option`](`t:exec_daemon_option/0`) has existed for a long time but
> has not previously been documented. The old definition and behaviour are
> retained but obey the rules 1-6 above if conflicting. The old and undocumented
> style should not be used in new programs.
""".
-doc(#{group => <<"Daemon Options">>}).
-type exec_result() :: {ok,Result::term()} | {error,Reason::term()} .
-doc """
Old-style exec specification that are kept for compatibility, but should not be
used in new programs
""".
-doc(#{group => <<"Daemon Options">>}).
-type deprecated_exec_opt() :: fun() | mod_fun_args() .
-doc """
Provides your own CLI implementation in a daemon.
It is a channel callback module that implements a shell and command execution.
The shell's read-eval-print loop can be customized, using the option
[`shell`](`t:shell_daemon_option/0`). This means less work than implementing an
own CLI channel. If `ssh_cli` is set to `no_cli`, the CLI channels like
[`shell`](`t:shell_daemon_option/0`) and [`exec`](`t:exec_daemon_option/0`) are
disabled and only subsystem channels are allowed.
""".
-doc(#{group => <<"Daemon Options">>}).
-type ssh_cli_daemon_option() :: {ssh_cli, mod_args() | no_cli }.
-doc """
Enables (`true`) or disables (`false`) the possibility to tunnel a TCP/IP
connection out of a [server](`daemon/2`). Disabled per default.
""".
-doc(#{group => <<"Daemon Options">>}).
-type tcpip_tunnel_out_daemon_option() :: {tcpip_tunnel_out, boolean()} .
-doc """
Enables (`true`) or disables (`false`) the possibility to tunnel a TCP/IP
connection in to a [server](`daemon/2`). Disabled per default.