1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2004-2020. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21%%
22
23%%
24%% SSH definitions
25%%
26
27-ifndef(SSH_HRL).
28-define(SSH_HRL, 1).
29
30-define(SSH_DEFAULT_PORT, 22).
31-define(SSH_MAX_PACKET_SIZE, (256*1024)).
32-define(REKEY_DATA_TIMOUT, 60000).
33-define(DEFAULT_PROFILE, default).
34
35-define(DEFAULT_TRANSPORT,  {tcp, gen_tcp, tcp_closed} ).
36
37-define(DEFAULT_SHELL, {shell, start, []} ).
38
39-define(DEFAULT_TIMEOUT, 5000).
40
41-define(MAX_RND_PADDING_LEN, 15).
42
43-define(SUPPORTED_AUTH_METHODS, "publickey,keyboard-interactive,password").
44
45-define(FALSE, 0).
46-define(TRUE,  1).
47%% basic binary constructors
48-define(BOOLEAN(X),  (X):8/unsigned-big-integer).
49-define(BYTE(X),     (X):8/unsigned-big-integer).
50-define(UINT16(X),   (X):16/unsigned-big-integer).
51-define(UINT32(X),   (X):32/unsigned-big-integer).
52-define(UINT64(X),   (X):64/unsigned-big-integer).
53-define(STRING(X),   ?UINT32((size(X))), (X)/binary).
54
55-define(DEC_BIN(X,Len),   ?UINT32(Len), X:Len/binary ).
56-define(DEC_INT(I,Len),   ?UINT32(Len), I:Len/big-signed-integer-unit:8 ).
57-define(DEC_MPINT(I,Len), ?UINT32(Len), I:Len/big-signed-integer-unit:8 ).
58
59%% building macros
60-define(boolean(X),
61	case X of
62	    true -> <<?BOOLEAN(1)>>;
63	    false -> (<<?BOOLEAN(0)>>)
64	end).
65
66-define(byte(X),   << ?BYTE(X) >> ).
67-define(uint16(X), << ?UINT16(X) >> ).
68-define(uint32(X), << ?UINT32(X) >> ).
69-define(uint64(X), << ?UINT64(X) >> ).
70-define(string_utf8(X), << ?STRING(unicode:characters_to_binary(X)) >> ).
71-define(string(X), ?string_utf8(X)).
72-define(binary(X), << ?STRING(X) >>).
73
74-define('2bin'(X), (if is_binary(X) -> X;
75		       is_list(X) -> list_to_binary(X);
76		       X==undefined -> <<>>
77		    end) ).
78
79%% encoding macros
80-define('E...'(X),    ?'2bin'(X)/binary ).
81-define(Eboolean(X),  ?BOOLEAN(case X of
82				   true -> ?TRUE;
83				   false -> ?FALSE
84			       end) ).
85-define(Ebyte(X),        ?BYTE(X) ).
86-define(Euint32(X),      ?UINT32(X) ).
87-define(Estring(X),      ?STRING(?'2bin'(X)) ).
88-define(Estring_utf8(X), ?string_utf8(X)/binary ).
89-define(Ename_list(X),   ?STRING(ssh_bits:name_list(X)) ).
90-define(Empint(X),       (ssh_bits:mpint(X))/binary ).
91-define(Ebinary(X),      ?STRING(X) ).
92
93%% Other macros
94-define(to_binary(X), (try iolist_to_binary(X) catch _:_ -> unicode:characters_to_binary(X) end) ).
95
96%% Cipher details
97-define(SSH_CIPHER_NONE, 0).
98-define(SSH_CIPHER_3DES, 3).
99-define(SSH_CIPHER_AUTHFILE, ?SSH_CIPHER_3DES).
100
101%% Option access macros
102-define(do_get_opt(C,K,O),   ssh_options:get_value(C,K,O,  ?MODULE,?LINE)).
103-define(do_get_opt(C,K,O,D), ssh_options:get_value(C,K,O,?LAZY(D),?MODULE,?LINE)).
104
105-define(LAZY(D), fun()-> D end).
106
107-define(GET_OPT(Key,Opts),              ?do_get_opt(user_options,    Key,Opts    ) ).
108-define(GET_OPT(Key,Opts,Def),          ?do_get_opt(user_options,    Key,Opts,Def) ).
109-define(GET_INTERNAL_OPT(Key,Opts),     ?do_get_opt(internal_options,Key,Opts    ) ).
110-define(GET_INTERNAL_OPT(Key,Opts,Def), ?do_get_opt(internal_options,Key,Opts,Def) ).
111-define(GET_SOCKET_OPT(Key,Opts),       ?do_get_opt(socket_options,  Key,Opts    ) ).
112-define(GET_SOCKET_OPT(Key,Opts,Def),   ?do_get_opt(socket_options,  Key,Opts,Def) ).
113
114-define(do_put_opt(C,KV,O),  ssh_options:put_value(C,KV,O, ?MODULE,?LINE)).
115
116-define(PUT_OPT(KeyVal,Opts),           ?do_put_opt(user_options,    KeyVal,Opts) ).
117-define(PUT_INTERNAL_OPT(KeyVal,Opts),  ?do_put_opt(internal_options,KeyVal,Opts) ).
118-define(PUT_SOCKET_OPT(KeyVal,Opts),    ?do_put_opt(socket_options,  KeyVal,Opts) ).
119
120-define(do_del_opt(C,K,O),  ssh_options:delete_key(C,K,O, ?MODULE,?LINE)).
121-define(DELETE_INTERNAL_OPT(Key,Opts),  ?do_del_opt(internal_options,Key,Opts) ).
122
123
124%% Types
125-type role()                  :: client | server .
126
127-type host()                  :: string() | inet:ip_address() | loopback .
128-type open_socket()           :: gen_tcp:socket().
129
130-type subsystem_spec()        :: {Name::string(), mod_args()} .
131
132-type algs_list()             :: list( alg_entry() ).
133-type alg_entry()             :: {kex, [kex_alg()]}
134                               | {public_key, [pubkey_alg()]}
135                               | {cipher, double_algs(cipher_alg())}
136                               | {mac, double_algs(mac_alg())}
137                               | {compression, double_algs(compression_alg())} .
138
139-type kex_alg()          :: 'diffie-hellman-group-exchange-sha1' |
140                            'diffie-hellman-group-exchange-sha256' |
141                            'diffie-hellman-group1-sha1' |
142                            'diffie-hellman-group14-sha1' |
143                            'diffie-hellman-group14-sha256' |
144                            'diffie-hellman-group16-sha512' |
145                            'diffie-hellman-group18-sha512' |
146                            'curve25519-sha256' |
147                            'curve25519-sha256@libssh.org' |
148                            'curve448-sha512' |
149                            'ecdh-sha2-nistp256' |
150                            'ecdh-sha2-nistp384' |
151                            'ecdh-sha2-nistp521'
152                            .
153
154-type pubkey_alg()       :: 'ecdsa-sha2-nistp256' |
155                            'ecdsa-sha2-nistp384' |
156                            'ecdsa-sha2-nistp521' |
157                            'ssh-ed25519'  |
158                            'ssh-ed448'  |
159                            'rsa-sha2-256' |
160                            'rsa-sha2-512' |
161                            'ssh-dss' |
162                            'ssh-rsa'
163                            .
164
165-type cipher_alg()       :: '3des-cbc' |
166                            'AEAD_AES_128_GCM' |
167                            'AEAD_AES_256_GCM' |
168                            'aes128-cbc' |
169                            'aes128-ctr' |
170                            'aes128-gcm@openssh.com' |
171                            'aes192-ctr' |
172                            'aes192-cbc' |
173                            'aes256-cbc' |
174                            'aes256-ctr' |
175                            'aes256-gcm@openssh.com' |
176                            'chacha20-poly1305@openssh.com'
177                            .
178
179-type mac_alg()          :: 'AEAD_AES_128_GCM' |
180                            'AEAD_AES_256_GCM' |
181                            'hmac-sha1' |
182                            'hmac-sha1-etm@openssh.com' |
183                            'hmac-sha1-96' |
184                            'hmac-sha2-256' |
185                            'hmac-sha2-512' |
186                            'hmac-sha2-256-etm@openssh.com' |
187                            'hmac-sha2-512-etm@openssh.com'
188                            .
189
190-type compression_alg()  :: 'none' |
191                            'zlib' |
192                            'zlib@openssh.com'
193                            .
194
195-type double_algs(AlgType)  :: list( {client2server,[AlgType]} | {server2client,[AlgType]} )
196                             | [AlgType].
197
198-type modify_algs_list()      :: list( {append,algs_list()} | {prepend,algs_list()} | {rm,algs_list()} ) .
199
200-type internal_options()      :: ssh_options:private_options().
201-type socket_options()        :: [gen_tcp:connect_option() | gen_tcp:listen_option()].
202
203-type client_options()        :: [ client_option() ] .
204-type daemon_options()        :: [ daemon_option() ].
205
206
207-type common_options() :: [ common_option() ].
208-type common_option() ::
209        ssh_file:user_dir_common_option()
210      | profile_common_option()
211      | max_idle_time_common_option()
212      | key_cb_common_option()
213      | disconnectfun_common_option()
214      | unexpectedfun_common_option()
215      | ssh_msg_debug_fun_common_option()
216      | rekey_limit_common_option()
217      | id_string_common_option()
218      | pref_public_key_algs_common_option()
219      | preferred_algorithms_common_option()
220      | modify_algorithms_common_option()
221      | auth_methods_common_option()
222      | inet_common_option()
223      | fd_common_option()
224        .
225
226-define(COMMON_OPTION, common_option()).
227
228-type profile_common_option()       :: {profile,   atom() }.
229-type max_idle_time_common_option() :: {idle_time, timeout()}.
230-type rekey_limit_common_option()   :: {rekey_limit, Bytes::limit_bytes() |
231                                                     {Minutes::limit_time(), Bytes::limit_bytes()}
232                                       }.
233
234-type limit_bytes() :: non_neg_integer() | infinity .  % non_neg_integer due to compatibility
235-type limit_time()  :: pos_integer() | infinity .
236
237-type key_cb_common_option()            :: {key_cb,  Module::atom() | {Module::atom(),Opts::[term()]} } .
238-type disconnectfun_common_option()     ::
239        {disconnectfun, fun((Reason::term()) -> void | any()) }.
240-type unexpectedfun_common_option()     ::
241        {unexpectedfun, fun((Message::term(),{Host::term(),Port::term()}) -> report | skip ) }.
242-type ssh_msg_debug_fun_common_option() ::
243        {ssh_msg_debug_fun, fun((ssh:connection_ref(),AlwaysDisplay::boolean(),Msg::binary(),LanguageTag::binary()) -> any()) } .
244
245-type id_string_common_option()           :: {id_string,  string() | random | {random,Nmin::pos_integer(),Nmax::pos_integer()} }.
246-type pref_public_key_algs_common_option() :: {pref_public_key_algs, [pubkey_alg()] } .
247-type preferred_algorithms_common_option():: {preferred_algorithms, algs_list()}.
248-type modify_algorithms_common_option()   :: {modify_algorithms,    modify_algs_list()}.
249-type auth_methods_common_option()        :: {auth_methods,         string() }.
250
251-type inet_common_option() :: {inet, inet | inet6} .
252-type fd_common_option() :: {fd, gen_tcp:socket()} .
253
254
255-type opaque_common_options() ::
256        {transport, {atom(),atom(),atom()} }
257      | {vsn, {non_neg_integer(),non_neg_integer()} }
258      | {tstflg, list(term())}
259      | ssh_file:user_dir_fun_common_option()
260      | {max_random_length_padding, non_neg_integer()} .
261
262
263
264-type client_option()         ::
265        ssh_file:pubkey_passphrase_client_options()
266      | host_accepting_client_options()
267      | authentication_client_options()
268      | diffie_hellman_group_exchange_client_option()
269      | connect_timeout_client_option()
270      | recv_ext_info_client_option()
271      | opaque_client_options()
272      | gen_tcp:connect_option()
273      | ?COMMON_OPTION .
274
275-type opaque_client_options() ::
276        {keyboard_interact_fun, fun((Name::iodata(),
277                                     Instruction::iodata(),
278                                     Prompts::[{Prompt::iodata(),Echo::boolean()}]
279                                    ) ->
280                                      [Response::iodata()]
281                                   )}
282        | opaque_common_options().
283
284-type host_accepting_client_options() ::
285        {silently_accept_hosts, accept_hosts()}
286      | {user_interaction,     boolean()}
287      | {save_accepted_host,   boolean()}
288      | {quiet_mode,           boolean()} .
289
290-type accept_hosts() :: boolean()
291                      | accept_callback()
292                      | {HashAlgoSpec::fp_digest_alg(), accept_callback()}.
293
294-type fp_digest_alg() :: 'md5' | crypto:sha1() | crypto:sha2() .
295
296-type accept_callback() :: fun((PeerName::string(), fingerprint() ) -> boolean()) % Old style
297                         | fun((PeerName::string(), Port::inet:port_number(), fingerprint() ) -> boolean()) % New style
298                           .
299-type fingerprint() :: string() | [string()].
300
301-type authentication_client_options() ::
302        {user,                 string()}
303      | {password,             string()} .
304
305-type diffie_hellman_group_exchange_client_option() ::
306        {dh_gex_limits,        {Min::pos_integer(), I::pos_integer(), Max::pos_integer()} } .
307
308-type connect_timeout_client_option() :: {connect_timeout, timeout()} .
309
310-type recv_ext_info_client_option() :: {recv_ext_info, boolean()} .
311
312
313
314-type daemon_option()         ::
315        subsystem_daemon_option()
316      | shell_daemon_option()
317      | exec_daemon_option()
318      | ssh_cli_daemon_option()
319      | tcpip_tunnel_out_daemon_option()
320      | tcpip_tunnel_in_daemon_option()
321      | authentication_daemon_options()
322      | diffie_hellman_group_exchange_daemon_option()
323      | negotiation_timeout_daemon_option()
324      | hello_timeout_daemon_option()
325      | hardening_daemon_options()
326      | callbacks_daemon_options()
327      | send_ext_info_daemon_option()
328      | opaque_daemon_options()
329      | gen_tcp:listen_option()
330      | ?COMMON_OPTION .
331
332-type subsystem_daemon_option() :: {subsystems, subsystem_specs()}.
333-type subsystem_specs() :: [ subsystem_spec() ].
334
335-type shell_daemon_option()     :: {shell, shell_spec()} .
336-type shell_spec() :: mod_fun_args() | shell_fun() | disabled .
337-type shell_fun() :: 'shell_fun/1'()  | 'shell_fun/2'() .
338-type 'shell_fun/1'() :: fun((User::string()) -> pid()) .
339-type 'shell_fun/2'() :: fun((User::string(),  PeerAddr::inet:ip_address()) -> pid()).
340
341-type exec_daemon_option()      :: {exec, exec_spec()} .
342-type exec_spec()               :: {direct, exec_fun()} | disabled | deprecated_exec_opt().
343-type exec_fun()                :: 'exec_fun/1'() | 'exec_fun/2'() | 'exec_fun/3'().
344-type 'exec_fun/1'() :: fun((Cmd::string()) -> exec_result()) .
345-type 'exec_fun/2'() :: fun((Cmd::string(), User::string()) -> exec_result()) .
346-type 'exec_fun/3'() :: fun((Cmd::string(), User::string(), ClientAddr::ip_port()) -> exec_result()) .
347-type exec_result()  :: {ok,Result::term()} | {error,Reason::term()} .
348-type deprecated_exec_opt() :: fun() | mod_fun_args() .
349
350-type ssh_cli_daemon_option()   :: {ssh_cli, mod_args() | no_cli }.
351
352-type tcpip_tunnel_out_daemon_option() :: {tcpip_tunnel_out, boolean()} .
353-type tcpip_tunnel_in_daemon_option() :: {tcpip_tunnel_in, boolean()} .
354
355-type send_ext_info_daemon_option() :: {send_ext_info, boolean()} .
356
357-type authentication_daemon_options() ::
358        ssh_file:system_dir_daemon_option()
359      | {auth_method_kb_interactive_data, prompt_texts() }
360      | {user_passwords, [{UserName::string(),Pwd::string()}]}
361      | {pk_check_user, boolean()}
362      | {password, string()}
363      | {pwdfun, pwdfun_2() | pwdfun_4()} .
364
365-type prompt_texts() ::
366        kb_int_tuple()
367      | kb_int_fun_3()
368      | kb_int_fun_4()
369      .
370
371-type kb_int_fun_3() :: fun((Peer::ip_port(), User::string(), Service::string()) -> kb_int_tuple()).
372-type kb_int_fun_4() :: fun((Peer::ip_port(), User::string(), Service::string(), State::any()) -> kb_int_tuple()).
373-type kb_int_tuple() :: {Name::string(), Instruction::string(), Prompt::string(), Echo::boolean()}.
374
375-type pwdfun_2() :: fun((User::string(), Password::string()|pubkey) -> boolean()) .
376-type pwdfun_4() :: fun((User::string(),
377                         Password::string()|pubkey,
378                         PeerAddress::ip_port(),
379                         State::any()) ->
380                               boolean() | disconnect | {boolean(),NewState::any()}
381                       ) .
382
383-type diffie_hellman_group_exchange_daemon_option() ::
384        {dh_gex_groups, [explicit_group()] | explicit_group_file() | ssh_moduli_file()}
385      | {dh_gex_limits, {Min::pos_integer(), Max::pos_integer()} } .
386
387-type explicit_group() :: {Size::pos_integer(),G::pos_integer(),P::pos_integer()} .
388-type explicit_group_file() :: {file,string()} .
389-type ssh_moduli_file() :: {ssh_moduli_file,string()}.
390
391-type negotiation_timeout_daemon_option() :: {negotiation_timeout, timeout()} .
392-type hello_timeout_daemon_option() :: {hello_timeout, timeout()} .
393
394-type hardening_daemon_options() ::
395        {max_sessions, pos_integer()}
396      | {max_channels, pos_integer()}
397      | {parallel_login, boolean()}
398      | {minimal_remote_max_packet_size, pos_integer()}.
399
400-type callbacks_daemon_options() ::
401        {failfun, fun((User::string(), PeerAddress::inet:ip_address(), Reason::term()) -> _)}
402      | {connectfun, fun((User::string(), PeerAddress::inet:ip_address(), Method::string()) ->_)} .
403
404-type opaque_daemon_options()  ::
405        {infofun, fun()}
406      | opaque_common_options().
407
408-type ip_port() :: {inet:ip_address(), inet:port_number()} .
409
410-type mod_args() :: {Module::atom(), Args::list()} .
411-type mod_fun_args() :: {Module::atom(), Function::atom(), Args::list()} .
412
413
414%% Records
415-record(address, {address,
416                  port,
417                  profile
418                 }).
419
420-record(ssh,
421	{
422	  role :: client | role(),
423	  peer :: undefined |
424                  {inet:hostname(),ip_port()},         %% string version of peer address
425
426          local,        %% Local sockname. Need this AFTER a socket is closed by i.e. a crash
427
428	  c_vsn,        %% client version {Major,Minor}
429	  s_vsn,        %% server version {Major,Minor}
430
431	  c_version,    %% client version string
432	  s_version,    %% server version string
433
434	  c_keyinit,    %% binary payload of kexinit packet
435	  s_keyinit,    %% binary payload of kexinit packet
436
437          send_ext_info, %% May send ext-info to peer
438          recv_ext_info, %% Expect ext-info from peer
439
440	  algorithms,   %% #alg{}
441
442	  send_mac = none, %% send MAC algorithm
443	  send_mac_key,  %% key used in send MAC algorithm
444	  send_mac_size = 0,
445
446	  recv_mac = none, %% recv MAC algorithm
447	  recv_mac_key,  %% key used in recv MAC algorithm
448	  recv_mac_size = 0,
449
450	  encrypt = none,       %% encrypt algorithm
451          encrypt_cipher,       %% cipher. could be different from the algorithm
452	  encrypt_keys,         %% encrypt keys
453	  encrypt_block_size = 8,
454	  encrypt_ctx,
455
456	  decrypt = none,       %% decrypt algorithm
457          decrypt_cipher,       %% cipher. could be different from the algorithm
458	  decrypt_keys,         %% decrypt keys
459	  decrypt_block_size = 8,
460	  decrypt_ctx,          %% Decryption context
461
462	  compress = none,
463	  compress_ctx,
464	  decompress = none,
465	  decompress_ctx,
466
467	  c_lng=none,   %% client to server languages
468	  s_lng=none,   %% server to client languages
469
470	  user_ack    = true,   %% client
471	  timeout     = infinity,
472
473	  shared_secret,        %% K from key exchange
474	  exchanged_hash,       %% H from key exchange
475	  session_id,           %% same as FIRST exchanged_hash
476
477	  opts = [],
478	  send_sequence = 0,
479	  recv_sequence = 0,
480	  keyex_key,
481	  keyex_info,
482	  random_length_padding = ?MAX_RND_PADDING_LEN, % From RFC 4253 section 6.
483
484	  %% User auth
485	  user,
486	  service,
487	  userauth_quiet_mode,              %  boolean()
488	  userauth_methods,                 %  list( string() )  eg ["keyboard-interactive", "password"]
489	  userauth_supported_methods,       %  string() eg "keyboard-interactive,password"
490          userauth_pubkeys,
491	  kb_tries_left = 0,                %  integer(), num tries left for "keyboard-interactive"
492	  userauth_preference,
493	  available_host_keys,
494	  pwdfun_user_state,
495	  authenticated = false
496	 }).
497
498-record(alg,
499	{
500	  kex,
501	  hkey,
502	  send_mac,
503	  recv_mac,
504	  encrypt,
505	  decrypt,
506	  compress,
507	  decompress,
508	  c_lng,
509	  s_lng,
510          send_ext_info,
511          recv_ext_info
512	 }).
513
514-record(ssh_pty, {c_version = "", % client version string, e.g "SSH-2.0-Erlang/4.10.5"
515                  term = "",      % e.g. "xterm"
516		  width = 80,
517		  height = 25,
518		  pixel_width = 1024,
519		  pixel_height = 768,
520		  modes = <<>>}).
521
522
523%% dbg help macros
524-define(wr_record(N,BlackList),
525        wr_record(R=#N{}) ->  ssh_dbg:wr_record(R, record_info(fields,N), BlackList)
526        ).
527
528-define(wr_record(N), ?wr_record(N, [])).
529
530
531%% Circular trace buffer macros
532
533-record(circ_buf_entry,
534        {
535          module,
536          line,
537          function,
538          pid = self(),
539          value
540        }).
541
542-define(CIRC_BUF_IN(VALUE),
543        ssh_dbg:cbuf_in(
544          #circ_buf_entry{module = ?MODULE,
545                          line = ?LINE,
546                          function = {?FUNCTION_NAME,?FUNCTION_ARITY},
547                          pid = self(),
548                          value = (VALUE)
549                         })
550       ).
551
552-define(CIRC_BUF_IN_ONCE(VALUE),
553        ((fun(V) -> ?CIRC_BUF_IN(V), V end)(VALUE))
554       ).
555
556-endif. % SSH_HRL defined
557