1 /* This is a sample implementation of a libssh based SSH server */ 2 /* 3 Copyright 2014 Audrius Butkevicius 4 5 This file is part of the SSH Library 6 7 You are free to copy this file, modify it in any way, consider it being public 8 domain. This does not apply to the rest of the library though, but it is 9 allowed to cut-and-paste working code from this file to any license of 10 program. 11 The goal is to show the API in action. 12 */ 13 14 #include "config.h" 15 16 #include <libssh/callbacks.h> 17 #include <libssh/server.h> 18 19 #include <poll.h> 20 #ifdef HAVE_ARGP_H 21 #include <argp.h> 22 #endif 23 #include <fcntl.h> 24 #ifdef HAVE_LIBUTIL_H 25 #include <libutil.h> 26 #endif 27 #ifdef HAVE_PTY_H 28 #include <pty.h> 29 #endif 30 #include <signal.h> 31 #include <stdlib.h> 32 #ifdef HAVE_UTMP_H 33 #include <utmp.h> 34 #endif 35 #ifdef HAVE_UTIL_H 36 #include <util.h> 37 #endif 38 #include <sys/ioctl.h> 39 #include <sys/wait.h> 40 #include <sys/stat.h> 41 #include <stdio.h> 42 43 #ifndef KEYS_FOLDER 44 #ifdef _WIN32 45 #define KEYS_FOLDER 46 #else 47 #define KEYS_FOLDER "/etc/ssh/" 48 #endif 49 #endif 50 51 #define USER "myuser" 52 #define PASS "mypassword" 53 #define BUF_SIZE 1048576 54 #define SESSION_END (SSH_CLOSED | SSH_CLOSED_ERROR) 55 #define SFTP_SERVER_PATH "/usr/lib/sftp-server" 56 57 static void set_default_keys(ssh_bind sshbind, 58 int rsa_already_set, 59 int dsa_already_set, 60 int ecdsa_already_set) { 61 if (!rsa_already_set) { 62 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, 63 KEYS_FOLDER "ssh_host_rsa_key"); 64 } 65 if (!dsa_already_set) { 66 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, 67 KEYS_FOLDER "ssh_host_dsa_key"); 68 } 69 if (!ecdsa_already_set) { 70 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY, 71 KEYS_FOLDER "ssh_host_ecdsa_key"); 72 } 73 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, 74 KEYS_FOLDER "ssh_host_ed25519_key"); 75 } 76 #define DEF_STR_SIZE 1024 77 char authorizedkeys[DEF_STR_SIZE] = {0}; 78 #ifdef HAVE_ARGP_H 79 const char *argp_program_version = "libssh server example " 80 SSH_STRINGIFY(LIBSSH_VERSION); 81 const char *argp_program_bug_address = "<libssh@libssh.org>"; 82 83 /* Program documentation. */ 84 static char doc[] = "libssh -- a Secure Shell protocol implementation"; 85 86 /* A description of the arguments we accept. */ 87 static char args_doc[] = "BINDADDR"; 88 89 /* The options we understand. */ 90 static struct argp_option options[] = { 91 { 92 .name = "port", 93 .key = 'p', 94 .arg = "PORT", 95 .flags = 0, 96 .doc = "Set the port to bind.", 97 .group = 0 98 }, 99 { 100 .name = "hostkey", 101 .key = 'k', 102 .arg = "FILE", 103 .flags = 0, 104 .doc = "Set a host key. Can be used multiple times. " 105 "Implies no default keys.", 106 .group = 0 107 }, 108 { 109 .name = "dsakey", 110 .key = 'd', 111 .arg = "FILE", 112 .flags = 0, 113 .doc = "Set the dsa key.", 114 .group = 0 115 }, 116 { 117 .name = "rsakey", 118 .key = 'r', 119 .arg = "FILE", 120 .flags = 0, 121 .doc = "Set the rsa key.", 122 .group = 0 123 }, 124 { 125 .name = "ecdsakey", 126 .key = 'e', 127 .arg = "FILE", 128 .flags = 0, 129 .doc = "Set the ecdsa key.", 130 .group = 0 131 }, 132 { 133 .name = "authorizedkeys", 134 .key = 'a', 135 .arg = "FILE", 136 .flags = 0, 137 .doc = "Set the authorized keys file.", 138 .group = 0 139 }, 140 { 141 .name = "no-default-keys", 142 .key = 'n', 143 .arg = NULL, 144 .flags = 0, 145 .doc = "Do not set default key locations.", 146 .group = 0 147 }, 148 { 149 .name = "verbose", 150 .key = 'v', 151 .arg = NULL, 152 .flags = 0, 153 .doc = "Get verbose output.", 154 .group = 0 155 }, 156 {NULL, 0, NULL, 0, NULL, 0} 157 }; 158 159 /* Parse a single option. */ 160 static error_t parse_opt (int key, char *arg, struct argp_state *state) { 161 /* Get the input argument from argp_parse, which we 162 * know is a pointer to our arguments structure. */ 163 ssh_bind sshbind = state->input; 164 static int no_default_keys = 0; 165 static int rsa_already_set = 0, dsa_already_set = 0, ecdsa_already_set = 0; 166 167 switch (key) { 168 case 'n': 169 no_default_keys = 1; 170 break; 171 case 'p': 172 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg); 173 break; 174 case 'd': 175 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg); 176 dsa_already_set = 1; 177 break; 178 case 'k': 179 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg); 180 /* We can't track the types of keys being added with this 181 option, so let's ensure we keep the keys we're adding 182 by just not setting the default keys */ 183 no_default_keys = 1; 184 break; 185 case 'r': 186 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg); 187 rsa_already_set = 1; 188 break; 189 case 'e': 190 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY, arg); 191 ecdsa_already_set = 1; 192 break; 193 case 'a': 194 strncpy(authorizedkeys, arg, DEF_STR_SIZE-1); 195 break; 196 case 'v': 197 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, 198 "3"); 199 break; 200 case ARGP_KEY_ARG: 201 if (state->arg_num >= 1) { 202 /* Too many arguments. */ 203 argp_usage (state); 204 } 205 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, arg); 206 break; 207 case ARGP_KEY_END: 208 if (state->arg_num < 1) { 209 /* Not enough arguments. */ 210 argp_usage (state); 211 } 212 213 if (!no_default_keys) { 214 set_default_keys(sshbind, 215 rsa_already_set, 216 dsa_already_set, 217 ecdsa_already_set); 218 } 219 220 break; 221 default: 222 return ARGP_ERR_UNKNOWN; 223 } 224 return 0; 225 } 226 227 /* Our argp parser. */ 228 static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL}; 229 #endif /* HAVE_ARGP_H */ 230 231 /* A userdata struct for channel. */ 232 struct channel_data_struct { 233 /* pid of the child process the channel will spawn. */ 234 pid_t pid; 235 /* For PTY allocation */ 236 socket_t pty_master; 237 socket_t pty_slave; 238 /* For communication with the child process. */ 239 socket_t child_stdin; 240 socket_t child_stdout; 241 /* Only used for subsystem and exec requests. */ 242 socket_t child_stderr; 243 /* Event which is used to poll the above descriptors. */ 244 ssh_event event; 245 /* Terminal size struct. */ 246 struct winsize *winsize; 247 }; 248 249 /* A userdata struct for session. */ 250 struct session_data_struct { 251 /* Pointer to the channel the session will allocate. */ 252 ssh_channel channel; 253 int auth_attempts; 254 int authenticated; 255 }; 256 257 static int data_function(ssh_session session, ssh_channel channel, void *data, 258 uint32_t len, int is_stderr, void *userdata) { 259 struct channel_data_struct *cdata = (struct channel_data_struct *) userdata; 260 261 (void) session; 262 (void) channel; 263 (void) is_stderr; 264 265 if (len == 0 || cdata->pid < 1 || kill(cdata->pid, 0) < 0) { 266 return 0; 267 } 268 269 return write(cdata->child_stdin, (char *) data, len); 270 } 271 272 static int pty_request(ssh_session session, ssh_channel channel, 273 const char *term, int cols, int rows, int py, int px, 274 void *userdata) { 275 struct channel_data_struct *cdata = (struct channel_data_struct *)userdata; 276 277 (void) session; 278 (void) channel; 279 (void) term; 280 281 cdata->winsize->ws_row = rows; 282 cdata->winsize->ws_col = cols; 283 cdata->winsize->ws_xpixel = px; 284 cdata->winsize->ws_ypixel = py; 285 286 if (openpty(&cdata->pty_master, &cdata->pty_slave, NULL, NULL, 287 cdata->winsize) != 0) { 288 fprintf(stderr, "Failed to open pty\n"); 289 return SSH_ERROR; 290 } 291 return SSH_OK; 292 } 293 294 static int pty_resize(ssh_session session, ssh_channel channel, int cols, 295 int rows, int py, int px, void *userdata) { 296 struct channel_data_struct *cdata = (struct channel_data_struct *)userdata; 297 298 (void) session; 299 (void) channel; 300 301 cdata->winsize->ws_row = rows; 302 cdata->winsize->ws_col = cols; 303 cdata->winsize->ws_xpixel = px; 304 cdata->winsize->ws_ypixel = py; 305 306 if (cdata->pty_master != -1) { 307 return ioctl(cdata->pty_master, TIOCSWINSZ, cdata->winsize); 308 } 309 310 return SSH_ERROR; 311 } 312 313 static int exec_pty(const char *mode, const char *command, 314 struct channel_data_struct *cdata) { 315 switch(cdata->pid = fork()) { 316 case -1: 317 close(cdata->pty_master); 318 close(cdata->pty_slave); 319 fprintf(stderr, "Failed to fork\n"); 320 return SSH_ERROR; 321 case 0: 322 close(cdata->pty_master); 323 if (login_tty(cdata->pty_slave) != 0) { 324 exit(1); 325 } 326 execl("/bin/sh", "sh", mode, command, NULL); 327 exit(0); 328 default: 329 close(cdata->pty_slave); 330 /* pty fd is bi-directional */ 331 cdata->child_stdout = cdata->child_stdin = cdata->pty_master; 332 } 333 return SSH_OK; 334 } 335 336 static int exec_nopty(const char *command, struct channel_data_struct *cdata) { 337 int in[2], out[2], err[2]; 338 339 /* Do the plumbing to be able to talk with the child process. */ 340 if (pipe(in) != 0) { 341 goto stdin_failed; 342 } 343 if (pipe(out) != 0) { 344 goto stdout_failed; 345 } 346 if (pipe(err) != 0) { 347 goto stderr_failed; 348 } 349 350 switch(cdata->pid = fork()) { 351 case -1: 352 goto fork_failed; 353 case 0: 354 /* Finish the plumbing in the child process. */ 355 close(in[1]); 356 close(out[0]); 357 close(err[0]); 358 dup2(in[0], STDIN_FILENO); 359 dup2(out[1], STDOUT_FILENO); 360 dup2(err[1], STDERR_FILENO); 361 close(in[0]); 362 close(out[1]); 363 close(err[1]); 364 /* exec the requested command. */ 365 execl("/bin/sh", "sh", "-c", command, NULL); 366 exit(0); 367 } 368 369 close(in[0]); 370 close(out[1]); 371 close(err[1]); 372 373 cdata->child_stdin = in[1]; 374 cdata->child_stdout = out[0]; 375 cdata->child_stderr = err[0]; 376 377 return SSH_OK; 378 379 fork_failed: 380 close(err[0]); 381 close(err[1]); 382 stderr_failed: 383 close(out[0]); 384 close(out[1]); 385 stdout_failed: 386 close(in[0]); 387 close(in[1]); 388 stdin_failed: 389 return SSH_ERROR; 390 } 391 392 static int exec_request(ssh_session session, ssh_channel channel, 393 const char *command, void *userdata) { 394 struct channel_data_struct *cdata = (struct channel_data_struct *) userdata; 395 396 397 (void) session; 398 (void) channel; 399 400 if(cdata->pid > 0) { 401 return SSH_ERROR; 402 } 403 404 if (cdata->pty_master != -1 && cdata->pty_slave != -1) { 405 return exec_pty("-c", command, cdata); 406 } 407 return exec_nopty(command, cdata); 408 } 409 410 static int shell_request(ssh_session session, ssh_channel channel, 411 void *userdata) { 412 struct channel_data_struct *cdata = (struct channel_data_struct *) userdata; 413 414 (void) session; 415 (void) channel; 416 417 if(cdata->pid > 0) { 418 return SSH_ERROR; 419 } 420 421 if (cdata->pty_master != -1 && cdata->pty_slave != -1) { 422 return exec_pty("-l", NULL, cdata); 423 } 424 /* Client requested a shell without a pty, let's pretend we allow that */ 425 return SSH_OK; 426 } 427 428 static int subsystem_request(ssh_session session, ssh_channel channel, 429 const char *subsystem, void *userdata) { 430 /* subsystem requests behave simillarly to exec requests. */ 431 if (strcmp(subsystem, "sftp") == 0) { 432 return exec_request(session, channel, SFTP_SERVER_PATH, userdata); 433 } 434 return SSH_ERROR; 435 } 436 437 static int auth_password(ssh_session session, const char *user, 438 const char *pass, void *userdata) { 439 struct session_data_struct *sdata = (struct session_data_struct *) userdata; 440 441 (void) session; 442 443 if (strcmp(user, USER) == 0 && strcmp(pass, PASS) == 0) { 444 sdata->authenticated = 1; 445 return SSH_AUTH_SUCCESS; 446 } 447 448 sdata->auth_attempts++; 449 return SSH_AUTH_DENIED; 450 } 451 452 static int auth_publickey(ssh_session session, 453 const char *user, 454 struct ssh_key_struct *pubkey, 455 char signature_state, 456 void *userdata) 457 { 458 struct session_data_struct *sdata = (struct session_data_struct *) userdata; 459 460 (void) user; 461 (void) session; 462 463 if (signature_state == SSH_PUBLICKEY_STATE_NONE) { 464 return SSH_AUTH_SUCCESS; 465 } 466 467 if (signature_state != SSH_PUBLICKEY_STATE_VALID) { 468 return SSH_AUTH_DENIED; 469 } 470 471 // valid so far. Now look through authorized keys for a match 472 if (authorizedkeys[0]) { 473 ssh_key key = NULL; 474 int result; 475 struct stat buf; 476 477 if (stat(authorizedkeys, &buf) == 0) { 478 result = ssh_pki_import_pubkey_file( authorizedkeys, &key ); 479 if ((result != SSH_OK) || (key==NULL)) { 480 fprintf(stderr, 481 "Unable to import public key file %s\n", 482 authorizedkeys); 483 } else { 484 result = ssh_key_cmp( key, pubkey, SSH_KEY_CMP_PUBLIC ); 485 ssh_key_free(key); 486 if (result == 0) { 487 sdata->authenticated = 1; 488 return SSH_AUTH_SUCCESS; 489 } 490 } 491 } 492 } 493 494 // no matches 495 sdata->authenticated = 0; 496 return SSH_AUTH_DENIED; 497 } 498 499 static ssh_channel channel_open(ssh_session session, void *userdata) { 500 struct session_data_struct *sdata = (struct session_data_struct *) userdata; 501 502 sdata->channel = ssh_channel_new(session); 503 return sdata->channel; 504 } 505 506 static int process_stdout(socket_t fd, int revents, void *userdata) { 507 char buf[BUF_SIZE]; 508 int n = -1; 509 ssh_channel channel = (ssh_channel) userdata; 510 511 if (channel != NULL && (revents & POLLIN) != 0) { 512 n = read(fd, buf, BUF_SIZE); 513 if (n > 0) { 514 ssh_channel_write(channel, buf, n); 515 } 516 } 517 518 return n; 519 } 520 521 static int process_stderr(socket_t fd, int revents, void *userdata) { 522 char buf[BUF_SIZE]; 523 int n = -1; 524 ssh_channel channel = (ssh_channel) userdata; 525 526 if (channel != NULL && (revents & POLLIN) != 0) { 527 n = read(fd, buf, BUF_SIZE); 528 if (n > 0) { 529 ssh_channel_write_stderr(channel, buf, n); 530 } 531 } 532 533 return n; 534 } 535 536 static void handle_session(ssh_event event, ssh_session session) { 537 int n; 538 int rc = 0; 539 540 /* Structure for storing the pty size. */ 541 struct winsize wsize = { 542 .ws_row = 0, 543 .ws_col = 0, 544 .ws_xpixel = 0, 545 .ws_ypixel = 0 546 }; 547 548 /* Our struct holding information about the channel. */ 549 struct channel_data_struct cdata = { 550 .pid = 0, 551 .pty_master = -1, 552 .pty_slave = -1, 553 .child_stdin = -1, 554 .child_stdout = -1, 555 .child_stderr = -1, 556 .event = NULL, 557 .winsize = &wsize 558 }; 559 560 /* Our struct holding information about the session. */ 561 struct session_data_struct sdata = { 562 .channel = NULL, 563 .auth_attempts = 0, 564 .authenticated = 0 565 }; 566 567 struct ssh_channel_callbacks_struct channel_cb = { 568 .userdata = &cdata, 569 .channel_pty_request_function = pty_request, 570 .channel_pty_window_change_function = pty_resize, 571 .channel_shell_request_function = shell_request, 572 .channel_exec_request_function = exec_request, 573 .channel_data_function = data_function, 574 .channel_subsystem_request_function = subsystem_request 575 }; 576 577 struct ssh_server_callbacks_struct server_cb = { 578 .userdata = &sdata, 579 .auth_password_function = auth_password, 580 .channel_open_request_session_function = channel_open, 581 }; 582 583 if (authorizedkeys[0]) { 584 server_cb.auth_pubkey_function = auth_publickey; 585 ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_PUBLICKEY); 586 } else 587 ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD); 588 589 ssh_callbacks_init(&server_cb); 590 ssh_callbacks_init(&channel_cb); 591 592 ssh_set_server_callbacks(session, &server_cb); 593 594 if (ssh_handle_key_exchange(session) != SSH_OK) { 595 fprintf(stderr, "%s\n", ssh_get_error(session)); 596 return; 597 } 598 599 ssh_event_add_session(event, session); 600 601 n = 0; 602 while (sdata.authenticated == 0 || sdata.channel == NULL) { 603 /* If the user has used up all attempts, or if he hasn't been able to 604 * authenticate in 10 seconds (n * 100ms), disconnect. */ 605 if (sdata.auth_attempts >= 3 || n >= 100) { 606 return; 607 } 608 609 if (ssh_event_dopoll(event, 100) == SSH_ERROR) { 610 fprintf(stderr, "%s\n", ssh_get_error(session)); 611 return; 612 } 613 n++; 614 } 615 616 ssh_set_channel_callbacks(sdata.channel, &channel_cb); 617 618 do { 619 /* Poll the main event which takes care of the session, the channel and 620 * even our child process's stdout/stderr (once it's started). */ 621 if (ssh_event_dopoll(event, -1) == SSH_ERROR) { 622 ssh_channel_close(sdata.channel); 623 } 624 625 /* If child process's stdout/stderr has been registered with the event, 626 * or the child process hasn't started yet, continue. */ 627 if (cdata.event != NULL || cdata.pid == 0) { 628 continue; 629 } 630 /* Executed only once, once the child process starts. */ 631 cdata.event = event; 632 /* If stdout valid, add stdout to be monitored by the poll event. */ 633 if (cdata.child_stdout != -1) { 634 if (ssh_event_add_fd(event, cdata.child_stdout, POLLIN, process_stdout, 635 sdata.channel) != SSH_OK) { 636 fprintf(stderr, "Failed to register stdout to poll context\n"); 637 ssh_channel_close(sdata.channel); 638 } 639 } 640 641 /* If stderr valid, add stderr to be monitored by the poll event. */ 642 if (cdata.child_stderr != -1){ 643 if (ssh_event_add_fd(event, cdata.child_stderr, POLLIN, process_stderr, 644 sdata.channel) != SSH_OK) { 645 fprintf(stderr, "Failed to register stderr to poll context\n"); 646 ssh_channel_close(sdata.channel); 647 } 648 } 649 } while(ssh_channel_is_open(sdata.channel) && 650 (cdata.pid == 0 || waitpid(cdata.pid, &rc, WNOHANG) == 0)); 651 652 close(cdata.pty_master); 653 close(cdata.child_stdin); 654 close(cdata.child_stdout); 655 close(cdata.child_stderr); 656 657 /* Remove the descriptors from the polling context, since they are now 658 * closed, they will always trigger during the poll calls. */ 659 ssh_event_remove_fd(event, cdata.child_stdout); 660 ssh_event_remove_fd(event, cdata.child_stderr); 661 662 /* If the child process exited. */ 663 if (kill(cdata.pid, 0) < 0 && WIFEXITED(rc)) { 664 rc = WEXITSTATUS(rc); 665 ssh_channel_request_send_exit_status(sdata.channel, rc); 666 /* If client terminated the channel or the process did not exit nicely, 667 * but only if something has been forked. */ 668 } else if (cdata.pid > 0) { 669 kill(cdata.pid, SIGKILL); 670 } 671 672 ssh_channel_send_eof(sdata.channel); 673 ssh_channel_close(sdata.channel); 674 675 /* Wait up to 5 seconds for the client to terminate the session. */ 676 for (n = 0; n < 50 && (ssh_get_status(session) & SESSION_END) == 0; n++) { 677 ssh_event_dopoll(event, 100); 678 } 679 } 680 681 /* SIGCHLD handler for cleaning up dead children. */ 682 static void sigchld_handler(int signo) { 683 (void) signo; 684 while (waitpid(-1, NULL, WNOHANG) > 0); 685 } 686 687 int main(int argc, char **argv) { 688 ssh_bind sshbind; 689 ssh_session session; 690 ssh_event event; 691 struct sigaction sa; 692 int rc; 693 694 /* Set up SIGCHLD handler. */ 695 sa.sa_handler = sigchld_handler; 696 sigemptyset(&sa.sa_mask); 697 sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; 698 if (sigaction(SIGCHLD, &sa, NULL) != 0) { 699 fprintf(stderr, "Failed to register SIGCHLD handler\n"); 700 return 1; 701 } 702 703 rc = ssh_init(); 704 if (rc < 0) { 705 fprintf(stderr, "ssh_init failed\n"); 706 return 1; 707 } 708 709 sshbind = ssh_bind_new(); 710 if (sshbind == NULL) { 711 fprintf(stderr, "ssh_bind_new failed\n"); 712 return 1; 713 } 714 715 #ifdef HAVE_ARGP_H 716 argp_parse(&argp, argc, argv, 0, 0, sshbind); 717 #else 718 (void) argc; 719 (void) argv; 720 721 set_default_keys(sshbind, 0, 0, 0); 722 #endif /* HAVE_ARGP_H */ 723 724 if(ssh_bind_listen(sshbind) < 0) { 725 fprintf(stderr, "%s\n", ssh_get_error(sshbind)); 726 return 1; 727 } 728 729 while (1) { 730 session = ssh_new(); 731 if (session == NULL) { 732 fprintf(stderr, "Failed to allocate session\n"); 733 continue; 734 } 735 736 /* Blocks until there is a new incoming connection. */ 737 if(ssh_bind_accept(sshbind, session) != SSH_ERROR) { 738 switch(fork()) { 739 case 0: 740 /* Remove the SIGCHLD handler inherited from parent. */ 741 sa.sa_handler = SIG_DFL; 742 sigaction(SIGCHLD, &sa, NULL); 743 /* Remove socket binding, which allows us to restart the 744 * parent process, without terminating existing sessions. */ 745 ssh_bind_free(sshbind); 746 747 event = ssh_event_new(); 748 if (event != NULL) { 749 /* Blocks until the SSH session ends by either 750 * child process exiting, or client disconnecting. */ 751 handle_session(event, session); 752 ssh_event_free(event); 753 } else { 754 fprintf(stderr, "Could not create polling context\n"); 755 } 756 ssh_disconnect(session); 757 ssh_free(session); 758 759 exit(0); 760 case -1: 761 fprintf(stderr, "Failed to fork\n"); 762 } 763 } else { 764 fprintf(stderr, "%s\n", ssh_get_error(sshbind)); 765 } 766 /* Since the session has been passed to a child fork, do some cleaning 767 * up at the parent process. */ 768 ssh_disconnect(session); 769 ssh_free(session); 770 } 771 772 ssh_bind_free(sshbind); 773 ssh_finalize(); 774 return 0; 775 } 776