1 /* 2 * This file is part of the SSH Library 3 * 4 * Copyright (c) 2018 by Red Hat, Inc. 5 * 6 * Author: Anderson Toshiyuki Sasaki <ansasaki@redhat.com> 7 * 8 * The SSH Library is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License as published by 10 * the Free Software Foundation; either version 2.1 of the License, or (at your 11 * option) any later version. 12 * 13 * The SSH Library is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 16 * License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License 19 * along with the SSH Library; see the file COPYING. If not, write to 20 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, 21 * MA 02111-1307, USA. 22 */ 23 24 #include "config.h" 25 26 #define LIBSSH_STATIC 27 28 #include <sys/types.h> 29 #include <sys/stat.h> 30 #include <errno.h> 31 #include <pwd.h> 32 33 #include "torture.h" 34 #include "torture_key.h" 35 #include "libssh/libssh.h" 36 #include "libssh/priv.h" 37 #include "libssh/session.h" 38 39 #include "test_server.h" 40 #include "default_cb.h" 41 42 #define TORTURE_KNOWN_HOSTS_FILE "libssh_torture_knownhosts" 43 44 const char template[] = "temp_dir_XXXXXX"; 45 46 struct test_server_st { 47 struct torture_state *state; 48 struct server_state_st *ss; 49 char *cwd; 50 char *temp_dir; 51 }; 52 53 static int setup_default_server(void **state) 54 { 55 struct torture_state *s; 56 struct server_state_st *ss; 57 struct test_server_st *tss; 58 #ifdef HAVE_DSA 59 char dsa_hostkey[1024]; 60 #endif /* HAVE_DSA */ 61 62 char ed25519_hostkey[1024] = {0}; 63 char rsa_hostkey[1024]; 64 char ecdsa_hostkey[1024]; 65 //char trusted_ca_pubkey[1024]; 66 67 char sshd_path[1024]; 68 struct stat sb; 69 70 const char *sftp_server_locations[] = { 71 "/usr/lib/ssh/sftp-server", 72 "/usr/libexec/sftp-server", 73 "/usr/libexec/openssh/sftp-server", 74 "/usr/lib/openssh/sftp-server", /* Debian */ 75 }; 76 77 size_t sftp_sl_size = ARRAY_SIZE(sftp_server_locations); 78 const char *sftp_server; 79 80 size_t i; 81 int rc; 82 83 char pid_str[1024]; 84 85 pid_t pid; 86 87 assert_non_null(state); 88 89 tss = (struct test_server_st*)calloc(1, sizeof(struct test_server_st)); 90 assert_non_null(tss); 91 92 torture_setup_socket_dir((void **)&s); 93 assert_non_null(s->socket_dir); 94 95 /* Set the default interface for the server */ 96 setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "10", 1); 97 setenv("PAM_WRAPPER", "1", 1); 98 99 snprintf(sshd_path, 100 sizeof(sshd_path), 101 "%s/sshd", 102 s->socket_dir); 103 104 rc = mkdir(sshd_path, 0755); 105 assert_return_code(rc, errno); 106 107 snprintf(ed25519_hostkey, 108 sizeof(ed25519_hostkey), 109 "%s/sshd/ssh_host_ed25519_key", 110 s->socket_dir); 111 torture_write_file(ed25519_hostkey, 112 torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 0)); 113 114 #ifdef HAVE_DSA 115 snprintf(dsa_hostkey, 116 sizeof(dsa_hostkey), 117 "%s/sshd/ssh_host_dsa_key", 118 s->socket_dir); 119 torture_write_file(dsa_hostkey, torture_get_testkey(SSH_KEYTYPE_DSS, 0)); 120 #endif /* HAVE_DSA */ 121 122 snprintf(rsa_hostkey, 123 sizeof(rsa_hostkey), 124 "%s/sshd/ssh_host_rsa_key", 125 s->socket_dir); 126 torture_write_file(rsa_hostkey, torture_get_testkey(SSH_KEYTYPE_RSA, 0)); 127 128 snprintf(ecdsa_hostkey, 129 sizeof(ecdsa_hostkey), 130 "%s/sshd/ssh_host_ecdsa_key", 131 s->socket_dir); 132 torture_write_file(ecdsa_hostkey, 133 torture_get_testkey(SSH_KEYTYPE_ECDSA_P521, 0)); 134 135 sftp_server = getenv("TORTURE_SFTP_SERVER"); 136 if (sftp_server == NULL) { 137 for (i = 0; i < sftp_sl_size; i++) { 138 sftp_server = sftp_server_locations[i]; 139 rc = lstat(sftp_server, &sb); 140 if (rc == 0) { 141 break; 142 } 143 } 144 } 145 assert_non_null(sftp_server); 146 147 /* Create default server state */ 148 ss = (struct server_state_st *)calloc(1, sizeof(struct server_state_st)); 149 assert_non_null(ss); 150 151 ss->address = strdup("127.0.0.10"); 152 assert_non_null(ss->address); 153 154 ss->port = 22; 155 156 ss->ecdsa_key = strdup(ecdsa_hostkey); 157 assert_non_null(ss->ecdsa_key); 158 159 #ifdef HAVE_DSA 160 ss->dsa_key = strdup(dsa_hostkey); 161 assert_non_null(ss->dsa_key); 162 #endif /* HAVE_DSA */ 163 164 ss->ed25519_key = strdup(ed25519_hostkey); 165 assert_non_null(ed25519_hostkey); 166 167 ss->rsa_key = strdup(rsa_hostkey); 168 assert_non_null(ss->rsa_key); 169 170 ss->host_key = NULL; 171 172 /* Use default username and password (set in default_handle_session_cb) */ 173 ss->expected_username = NULL; 174 ss->expected_password = NULL; 175 176 ss->verbosity = torture_libssh_verbosity(); 177 178 ss->auth_methods = SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_PUBLICKEY; 179 180 #ifdef WITH_PCAP 181 ss->with_pcap = 1; 182 ss->pcap_file = strdup(s->pcap_file); 183 assert_non_null(ss->pcap_file); 184 #endif 185 186 /* TODO make configurable */ 187 ss->max_tries = 3; 188 ss->error = 0; 189 190 /* Use the default session handling function */ 191 ss->handle_session = default_handle_session_cb; 192 assert_non_null(ss->handle_session); 193 194 /* Do not use global configuration */ 195 ss->parse_global_config = false; 196 197 /* Start the server using the default values */ 198 pid = fork_run_server(ss); 199 if (pid < 0) { 200 fail(); 201 } 202 203 snprintf(pid_str, sizeof(pid_str), "%d", pid); 204 205 torture_write_file(s->srv_pidfile, (const char *)pid_str); 206 207 setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "21", 1); 208 unsetenv("PAM_WRAPPER"); 209 210 /* Wait until the sshd is ready to accept connections */ 211 //rc = torture_wait_for_daemon(5); 212 //assert_int_equal(rc, 0); 213 214 /* TODO properly wait for the server (use ping approach) */ 215 /* Wait 200ms */ 216 usleep(200 * 1000); 217 218 tss->state = s; 219 tss->ss = ss; 220 221 *state = tss; 222 223 return 0; 224 } 225 226 static int teardown_default_server(void **state) 227 { 228 struct torture_state *s; 229 struct server_state_st *ss; 230 struct test_server_st *tss; 231 232 tss = *state; 233 assert_non_null(tss); 234 235 s = tss->state; 236 assert_non_null(s); 237 238 ss = tss->ss; 239 assert_non_null(ss); 240 241 /* This function can be reused */ 242 torture_teardown_sshd_server((void **)&s); 243 244 free_server_state(tss->ss); 245 SAFE_FREE(tss->ss); 246 SAFE_FREE(tss); 247 248 return 0; 249 } 250 251 static int session_setup(void **state) 252 { 253 struct test_server_st *tss = *state; 254 struct torture_state *s; 255 int verbosity = torture_libssh_verbosity(); 256 struct passwd *pwd; 257 char *cwd = NULL; 258 char *tmp_dir = NULL; 259 bool b = false; 260 int rc; 261 262 assert_non_null(tss); 263 264 /* Make sure we do not test the agent */ 265 unsetenv("SSH_AUTH_SOCK"); 266 267 cwd = torture_get_current_working_dir(); 268 assert_non_null(cwd); 269 270 tmp_dir = torture_make_temp_dir(template); 271 assert_non_null(tmp_dir); 272 273 tss->cwd = cwd; 274 tss->temp_dir = tmp_dir; 275 276 s = tss->state; 277 assert_non_null(s); 278 279 pwd = getpwnam("bob"); 280 assert_non_null(pwd); 281 282 rc = setuid(pwd->pw_uid); 283 assert_return_code(rc, errno); 284 285 s->ssh.session = ssh_new(); 286 assert_non_null(s->ssh.session); 287 288 rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity); 289 assert_ssh_return_code(s->ssh.session, rc); 290 rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER); 291 assert_ssh_return_code(s->ssh.session, rc); 292 /* Make sure no other configuration options from system will get used */ 293 rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_PROCESS_CONFIG, &b); 294 assert_ssh_return_code(s->ssh.session, rc); 295 296 return 0; 297 } 298 299 static int session_teardown(void **state) 300 { 301 struct test_server_st *tss = *state; 302 struct torture_state *s; 303 int rc = 0; 304 305 assert_non_null(tss); 306 307 s = tss->state; 308 assert_non_null(s); 309 310 ssh_disconnect(s->ssh.session); 311 ssh_free(s->ssh.session); 312 313 rc = torture_change_dir(tss->cwd); 314 assert_int_equal(rc, 0); 315 316 rc = torture_rmdirs(tss->temp_dir); 317 assert_int_equal(rc, 0); 318 319 SAFE_FREE(tss->temp_dir); 320 SAFE_FREE(tss->cwd); 321 322 return 0; 323 } 324 325 static void torture_server_auth_none(void **state) 326 { 327 struct test_server_st *tss = *state; 328 struct torture_state *s = NULL; 329 ssh_session session = NULL; 330 int rc; 331 332 assert_non_null(tss); 333 334 s = tss->state; 335 assert_non_null(s); 336 337 session = s->ssh.session; 338 assert_non_null(session); 339 340 rc = ssh_options_set(session, SSH_OPTIONS_USER, TORTURE_SSH_USER_BOB); 341 assert_int_equal(rc, SSH_OK); 342 343 rc = ssh_connect(session); 344 assert_int_equal(rc, SSH_OK); 345 346 rc = ssh_userauth_none(session, NULL); 347 assert_int_equal(rc, SSH_AUTH_DENIED); 348 349 /* This request should return a SSH_REQUEST_DENIED error */ 350 if (rc == SSH_ERROR) { 351 assert_int_equal(ssh_get_error_code(session), SSH_REQUEST_DENIED); 352 } 353 } 354 355 static void torture_server_auth_password(void **state) 356 { 357 struct test_server_st *tss = *state; 358 struct torture_state *s; 359 ssh_session session; 360 int rc; 361 362 assert_non_null(tss); 363 364 s = tss->state; 365 assert_non_null(s); 366 367 session = s->ssh.session; 368 assert_non_null(session); 369 370 /* TODO: implement proper pam authentication in callback */ 371 /* Using the default user for the server */ 372 rc = ssh_options_set(session, SSH_OPTIONS_USER, SSHD_DEFAULT_USER); 373 assert_int_equal(rc, SSH_OK); 374 375 rc = ssh_connect(session); 376 assert_int_equal(rc, SSH_OK); 377 378 rc = ssh_userauth_none(session, NULL); 379 /* This request should return a SSH_REQUEST_DENIED error */ 380 if (rc == SSH_AUTH_ERROR) { 381 assert_int_equal(ssh_get_error_code(session), SSH_REQUEST_DENIED); 382 } 383 rc = ssh_userauth_list(session, NULL); 384 assert_true(rc & SSH_AUTH_METHOD_PASSWORD); 385 386 /* TODO: implement proper pam authentication in callback */ 387 /* Using the default password for the server */ 388 rc = ssh_userauth_password(session, NULL, SSHD_DEFAULT_PASSWORD); 389 assert_int_equal(rc, SSH_AUTH_SUCCESS); 390 } 391 392 static void torture_server_auth_pubkey(void **state) 393 { 394 struct test_server_st *tss = *state; 395 struct torture_state *s; 396 ssh_session session; 397 int rc; 398 399 assert_non_null(tss); 400 401 s = tss->state; 402 assert_non_null(s); 403 404 session = s->ssh.session; 405 assert_non_null(session); 406 407 /* Authenticate as alice with bob's pubkey */ 408 rc = ssh_options_set(session, SSH_OPTIONS_USER, TORTURE_SSH_USER_ALICE); 409 assert_int_equal(rc, SSH_OK); 410 411 rc = ssh_connect(session); 412 assert_int_equal(rc, SSH_OK); 413 414 rc = ssh_userauth_none(session,NULL); 415 /* This request should return a SSH_REQUEST_DENIED error */ 416 if (rc == SSH_ERROR) { 417 assert_int_equal(ssh_get_error_code(session), SSH_REQUEST_DENIED); 418 } 419 rc = ssh_userauth_list(session, NULL); 420 assert_true(rc & SSH_AUTH_METHOD_PUBLICKEY); 421 422 rc = ssh_userauth_publickey_auto(session, NULL, NULL); 423 assert_int_equal(rc, SSH_AUTH_SUCCESS); 424 } 425 426 static void torture_server_hostkey_mismatch(void **state) 427 { 428 struct test_server_st *tss = *state; 429 struct torture_state *s = NULL; 430 ssh_session session = NULL; 431 char known_hosts_file[1024] = {0}; 432 FILE *file = NULL; 433 enum ssh_known_hosts_e found; 434 int rc; 435 436 assert_non_null(tss); 437 438 s = tss->state; 439 assert_non_null(s); 440 441 session = s->ssh.session; 442 assert_non_null(session); 443 444 /* Store the testkey in the knownhosts file */ 445 snprintf(known_hosts_file, 446 sizeof(known_hosts_file), 447 "%s/%s", 448 s->socket_dir, 449 TORTURE_KNOWN_HOSTS_FILE); 450 451 file = fopen(known_hosts_file, "w"); 452 assert_non_null(file); 453 fprintf(file, 454 "127.0.0.10 %s\n", 455 torture_get_testkey_pub(SSH_KEYTYPE_RSA)); 456 fclose(file); 457 458 rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file); 459 assert_ssh_return_code(session, rc); 460 /* Using the default user for the server */ 461 rc = ssh_options_set(session, SSH_OPTIONS_USER, SSHD_DEFAULT_USER); 462 assert_ssh_return_code(session, rc); 463 464 /* Configure the client to offer only rsa-sha2-256 hostkey algorithm */ 465 rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "rsa-sha2-256"); 466 assert_ssh_return_code(session, rc); 467 468 rc = ssh_connect(session); 469 assert_ssh_return_code(session, rc); 470 471 /* Make sure we can verify the signature */ 472 found = ssh_session_is_known_server(session); 473 assert_int_equal(found, SSH_KNOWN_HOSTS_OK); 474 } 475 476 static void torture_server_unknown_global_request(void **state) 477 { 478 struct test_server_st *tss = *state; 479 struct torture_state *s = NULL; 480 ssh_session session = NULL; 481 ssh_channel channel; 482 int rc; 483 484 assert_non_null(tss); 485 486 s = tss->state; 487 assert_non_null(s); 488 489 session = s->ssh.session; 490 assert_non_null(session); 491 492 rc = ssh_options_set(session, SSH_OPTIONS_USER, SSHD_DEFAULT_USER); 493 assert_int_equal(rc, SSH_OK); 494 495 rc = ssh_connect(session); 496 assert_int_equal(rc, SSH_OK); 497 498 /* Using the default password for the server */ 499 rc = ssh_userauth_password(session, NULL, SSHD_DEFAULT_PASSWORD); 500 assert_int_equal(rc, SSH_AUTH_SUCCESS); 501 502 /* Request asking for reply */ 503 rc = ssh_global_request(session, "unknown-request-00@test.com", NULL, 1); 504 assert_ssh_return_code_equal(session, rc, SSH_ERROR); 505 506 /* Request and don't ask for reply */ 507 rc = ssh_global_request(session, "another-bad-req-00@test.com", NULL, 0); 508 assert_ssh_return_code(session, rc); 509 510 /* Open channel to make sure the session is still working */ 511 channel = ssh_channel_new(session); 512 assert_non_null(channel); 513 514 rc = ssh_channel_open_session(channel); 515 assert_ssh_return_code(session, rc); 516 517 ssh_channel_close(channel); 518 } 519 520 int torture_run_tests(void) { 521 int rc; 522 struct CMUnitTest tests[] = { 523 cmocka_unit_test_setup_teardown(torture_server_auth_none, 524 session_setup, 525 session_teardown), 526 cmocka_unit_test_setup_teardown(torture_server_auth_password, 527 session_setup, 528 session_teardown), 529 cmocka_unit_test_setup_teardown(torture_server_auth_pubkey, 530 session_setup, 531 session_teardown), 532 cmocka_unit_test_setup_teardown(torture_server_hostkey_mismatch, 533 session_setup, 534 session_teardown), 535 cmocka_unit_test_setup_teardown(torture_server_unknown_global_request, 536 session_setup, 537 session_teardown), 538 }; 539 540 ssh_init(); 541 542 torture_filter_tests(tests); 543 rc = cmocka_run_group_tests(tests, 544 setup_default_server, 545 teardown_default_server); 546 547 ssh_finalize(); 548 549 return rc; 550 } 551