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