Blame examples/samplesshd-kbdint.c

Packit Service 31306d
/* This is a sample implementation of a libssh based SSH server */
Packit Service 31306d
/*
Packit Service 31306d
Copyright 2003-2011 Aris Adamantiadis
Packit Service 31306d
Packit Service 31306d
This file is part of the SSH Library
Packit Service 31306d
Packit Service 31306d
You are free to copy this file, modify it in any way, consider it being public
Packit Service 31306d
domain. This does not apply to the rest of the library though, but it is
Packit Service 31306d
allowed to cut-and-paste working code from this file to any license of
Packit Service 31306d
program.
Packit Service 31306d
The goal is to show the API in action. It's not a reference on how terminal
Packit Service 31306d
clients must be made or how a client should react.
Packit Service 31306d
*/
Packit Service 31306d
Packit Service 31306d
#include "config.h"
Packit Service 31306d
Packit Service 31306d
#include <libssh/libssh.h>
Packit Service 31306d
#include <libssh/server.h>
Packit Service 31306d
Packit Service 31306d
#ifdef HAVE_ARGP_H
Packit Service 31306d
#include <argp.h>
Packit Service 31306d
#endif
Packit Service 31306d
#include <stdlib.h>
Packit Service 31306d
#include <string.h>
Packit Service 31306d
#include <stdio.h>
Packit Service 31306d
#include <stdbool.h>
Packit Service 31306d
Packit Service 31306d
#define SSHD_USER "libssh"
Packit Service 31306d
#define SSHD_PASSWORD "libssh"
Packit Service 31306d
Packit Service 31306d
#ifndef KEYS_FOLDER
Packit Service 31306d
#ifdef _WIN32
Packit Service 31306d
#define KEYS_FOLDER
Packit Service 31306d
#else
Packit Service 31306d
#define KEYS_FOLDER "/etc/ssh/"
Packit Service 31306d
#endif
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
static int port = 22;
Packit Service 31306d
static bool authenticated = false;
Packit Service 31306d
Packit Service 31306d
#ifdef WITH_PCAP
Packit Service 31306d
static const char *pcap_file = "debug.server.pcap";
Packit Service 31306d
static ssh_pcap_file pcap;
Packit Service 31306d
Packit Service 31306d
static void set_pcap(ssh_session session){
Packit Service 31306d
	if(!pcap_file)
Packit Service 31306d
		return;
Packit Service 31306d
	pcap=ssh_pcap_file_new();
Packit Service 31306d
	if(ssh_pcap_file_open(pcap,pcap_file) == SSH_ERROR){
Packit Service 31306d
		printf("Error opening pcap file\n");
Packit Service 31306d
		ssh_pcap_file_free(pcap);
Packit Service 31306d
		pcap=NULL;
Packit Service 31306d
		return;
Packit Service 31306d
	}
Packit Service 31306d
	ssh_set_pcap_file(session,pcap);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static void cleanup_pcap(void) {
Packit Service 31306d
	ssh_pcap_file_free(pcap);
Packit Service 31306d
	pcap=NULL;
Packit Service 31306d
}
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
static int auth_password(const char *user, const char *password)
Packit Service 31306d
{
Packit Service 31306d
    int cmp;
Packit Service 31306d
Packit Service 31306d
    cmp = strcmp(user, SSHD_USER);
Packit Service 31306d
    if (cmp != 0) {
Packit Service 31306d
        return 0;
Packit Service 31306d
    }
Packit Service 31306d
    cmp = strcmp(password, SSHD_PASSWORD);
Packit Service 31306d
    if (cmp != 0) {
Packit Service 31306d
        return 0;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    authenticated = true;
Packit Service 31306d
    return 1; // authenticated
Packit Service 31306d
}
Packit Service 31306d
#ifdef HAVE_ARGP_H
Packit Service 31306d
const char *argp_program_version = "libssh server example "
Packit Service 31306d
  SSH_STRINGIFY(LIBSSH_VERSION);
Packit Service 31306d
const char *argp_program_bug_address = "<libssh@libssh.org>";
Packit Service 31306d
Packit Service 31306d
/* Program documentation. */
Packit Service 31306d
static char doc[] = "libssh -- a Secure Shell protocol implementation";
Packit Service 31306d
Packit Service 31306d
/* A description of the arguments we accept. */
Packit Service 31306d
static char args_doc[] = "BINDADDR";
Packit Service 31306d
Packit Service 31306d
/* The options we understand. */
Packit Service 31306d
static struct argp_option options[] = {
Packit Service 31306d
  {
Packit Service 31306d
    .name  = "port",
Packit Service 31306d
    .key   = 'p',
Packit Service 31306d
    .arg   = "PORT",
Packit Service 31306d
    .flags = 0,
Packit Service 31306d
    .doc   = "Set the port to bind.",
Packit Service 31306d
    .group = 0
Packit Service 31306d
  },
Packit Service 31306d
  {
Packit Service 31306d
    .name  = "hostkey",
Packit Service 31306d
    .key   = 'k',
Packit Service 31306d
    .arg   = "FILE",
Packit Service 31306d
    .flags = 0,
Packit Service 31306d
    .doc   = "Set the host key.",
Packit Service 31306d
    .group = 0
Packit Service 31306d
  },
Packit Service 31306d
  {
Packit Service 31306d
    .name  = "dsakey",
Packit Service 31306d
    .key   = 'd',
Packit Service 31306d
    .arg   = "FILE",
Packit Service 31306d
    .flags = 0,
Packit Service 31306d
    .doc   = "Set the dsa key.",
Packit Service 31306d
    .group = 0
Packit Service 31306d
  },
Packit Service 31306d
  {
Packit Service 31306d
    .name  = "rsakey",
Packit Service 31306d
    .key   = 'r',
Packit Service 31306d
    .arg   = "FILE",
Packit Service 31306d
    .flags = 0,
Packit Service 31306d
    .doc   = "Set the rsa key.",
Packit Service 31306d
    .group = 0
Packit Service 31306d
  },
Packit Service 31306d
  {
Packit Service 31306d
    .name  = "verbose",
Packit Service 31306d
    .key   = 'v',
Packit Service 31306d
    .arg   = NULL,
Packit Service 31306d
    .flags = 0,
Packit Service 31306d
    .doc   = "Get verbose output.",
Packit Service 31306d
    .group = 0
Packit Service 31306d
  },
Packit Service 31306d
  {NULL, 0, 0, 0, NULL, 0}
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
/* Parse a single option. */
Packit Service 31306d
static error_t parse_opt (int key, char *arg, struct argp_state *state) {
Packit Service 31306d
  /* Get the input argument from argp_parse, which we
Packit Service 31306d
   * know is a pointer to our arguments structure.
Packit Service 31306d
   */
Packit Service 31306d
  ssh_bind sshbind = state->input;
Packit Service 31306d
Packit Service 31306d
  switch (key) {
Packit Service 31306d
    case 'p':
Packit Service 31306d
      ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
Packit Service 31306d
      port = atoi(arg);
Packit Service 31306d
      break;
Packit Service 31306d
    case 'd':
Packit Service 31306d
      ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg);
Packit Service 31306d
      break;
Packit Service 31306d
    case 'k':
Packit Service 31306d
      ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
Packit Service 31306d
      break;
Packit Service 31306d
    case 'r':
Packit Service 31306d
      ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg);
Packit Service 31306d
      break;
Packit Service 31306d
    case 'v':
Packit Service 31306d
      ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3");
Packit Service 31306d
      break;
Packit Service 31306d
    case ARGP_KEY_ARG:
Packit Service 31306d
      if (state->arg_num >= 1) {
Packit Service 31306d
        /* Too many arguments. */
Packit Service 31306d
        argp_usage (state);
Packit Service 31306d
      }
Packit Service 31306d
      ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, arg);
Packit Service 31306d
      break;
Packit Service 31306d
    case ARGP_KEY_END:
Packit Service 31306d
      if (state->arg_num < 1) {
Packit Service 31306d
        /* Not enough arguments. */
Packit Service 31306d
        argp_usage (state);
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    default:
Packit Service 31306d
      return ARGP_ERR_UNKNOWN;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/* Our argp parser. */
Packit Service 31306d
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
Packit Service 31306d
#endif /* HAVE_ARGP_H */
Packit Service 31306d
Packit Service 31306d
static const char *name;
Packit Service 31306d
static const char *instruction;
Packit Service 31306d
static const char *prompts[2];
Packit Service 31306d
static char echo[] = { 1, 0 };
Packit Service 31306d
Packit Service 31306d
static int kbdint_check_response(ssh_session session) {
Packit Service 31306d
    int count;
Packit Service 31306d
Packit Service 31306d
    count = ssh_userauth_kbdint_getnanswers(session);
Packit Service 31306d
    if(count != 2) {
Packit Service 31306d
        instruction = "Something weird happened :(";
Packit Service 31306d
        return 0;
Packit Service 31306d
    }
Packit Service 31306d
    if(strcasecmp("Arthur Dent",
Packit Service 31306d
                        ssh_userauth_kbdint_getanswer(session, 0)) != 0) {
Packit Service 31306d
        instruction = "OK, this is not YOUR name, "
Packit Service 31306d
                                        "but it's a reference to the HGTG...";
Packit Service 31306d
        prompts[0] = "The main character's full name: ";
Packit Service 31306d
        return 0;
Packit Service 31306d
    }
Packit Service 31306d
    if(strcmp("42", ssh_userauth_kbdint_getanswer(session, 1)) != 0) {
Packit Service 31306d
        instruction = "Make an effort !!! What is the Answer to the Ultimate "
Packit Service 31306d
                            "Question of Life, the Universe, and Everything ?";
Packit Service 31306d
        prompts[1] = "Answer to the Ultimate Question of Life, the Universe, "
Packit Service 31306d
                            "and Everything: ";
Packit Service 31306d
        return 0;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    authenticated = true;
Packit Service 31306d
    return 1;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int authenticate(ssh_session session) {
Packit Service 31306d
    ssh_message message;
Packit Service 31306d
Packit Service 31306d
    name = "\n\nKeyboard-Interactive Fancy Authentication\n";
Packit Service 31306d
    instruction = "Please enter your real name and your password";
Packit Service 31306d
    prompts[0] = "Real name: ";
Packit Service 31306d
    prompts[1] = "Password: ";
Packit Service 31306d
Packit Service 31306d
    do {
Packit Service 31306d
        message=ssh_message_get(session);
Packit Service 31306d
        if(!message)
Packit Service 31306d
            break;
Packit Service 31306d
        switch(ssh_message_type(message)){
Packit Service 31306d
            case SSH_REQUEST_AUTH:
Packit Service 31306d
                switch(ssh_message_subtype(message)){
Packit Service 31306d
                    case SSH_AUTH_METHOD_PASSWORD:
Packit Service 31306d
                        printf("User %s wants to auth with pass %s\n",
Packit Service 31306d
                               ssh_message_auth_user(message),
Packit Service 31306d
                               ssh_message_auth_password(message));
Packit Service 31306d
                        if(auth_password(ssh_message_auth_user(message),
Packit Service 31306d
                           ssh_message_auth_password(message))){
Packit Service 31306d
                               ssh_message_auth_reply_success(message,0);
Packit Service 31306d
                               ssh_message_free(message);
Packit Service 31306d
                               return 1;
Packit Service 31306d
                           }
Packit Service 31306d
                        ssh_message_auth_set_methods(message,
Packit Service 31306d
                                                SSH_AUTH_METHOD_PASSWORD |
Packit Service 31306d
                                                SSH_AUTH_METHOD_INTERACTIVE);
Packit Service 31306d
                        // not authenticated, send default message
Packit Service 31306d
                        ssh_message_reply_default(message);
Packit Service 31306d
                        break;
Packit Service 31306d
Packit Service 31306d
                    case SSH_AUTH_METHOD_INTERACTIVE:
Packit Service 31306d
                        if(!ssh_message_auth_kbdint_is_response(message)) {
Packit Service 31306d
                            printf("User %s wants to auth with kbdint\n",
Packit Service 31306d
                                   ssh_message_auth_user(message));
Packit Service 31306d
                            ssh_message_auth_interactive_request(message, name,
Packit Service 31306d
                                                    instruction, 2, prompts, echo);
Packit Service 31306d
                        } else {
Packit Service 31306d
                            if(kbdint_check_response(session)) {
Packit Service 31306d
                                ssh_message_auth_reply_success(message,0);
Packit Service 31306d
                                ssh_message_free(message);
Packit Service 31306d
                                return 1;
Packit Service 31306d
                            }
Packit Service 31306d
                            ssh_message_auth_set_methods(message,
Packit Service 31306d
                                                    SSH_AUTH_METHOD_PASSWORD |
Packit Service 31306d
                                                    SSH_AUTH_METHOD_INTERACTIVE);
Packit Service 31306d
                            ssh_message_reply_default(message);
Packit Service 31306d
                        }
Packit Service 31306d
                        break;
Packit Service 31306d
                    case SSH_AUTH_METHOD_NONE:
Packit Service 31306d
                    default:
Packit Service 31306d
                        printf("User %s wants to auth with unknown auth %d\n",
Packit Service 31306d
                               ssh_message_auth_user(message),
Packit Service 31306d
                               ssh_message_subtype(message));
Packit Service 31306d
                        ssh_message_auth_set_methods(message,
Packit Service 31306d
                                                SSH_AUTH_METHOD_PASSWORD |
Packit Service 31306d
                                                SSH_AUTH_METHOD_INTERACTIVE);
Packit Service 31306d
                        ssh_message_reply_default(message);
Packit Service 31306d
                        break;
Packit Service 31306d
                }
Packit Service 31306d
                break;
Packit Service 31306d
            default:
Packit Service 31306d
                ssh_message_auth_set_methods(message,
Packit Service 31306d
                                                SSH_AUTH_METHOD_PASSWORD |
Packit Service 31306d
                                                SSH_AUTH_METHOD_INTERACTIVE);
Packit Service 31306d
                ssh_message_reply_default(message);
Packit Service 31306d
        }
Packit Service 31306d
        ssh_message_free(message);
Packit Service 31306d
    } while (1);
Packit Service 31306d
    return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int main(int argc, char **argv){
Packit Service 31306d
    ssh_session session;
Packit Service 31306d
    ssh_bind sshbind;
Packit Service 31306d
    ssh_message message;
Packit Service 31306d
    ssh_channel chan=0;
Packit Service 31306d
    char buf[2048];
Packit Service 31306d
    int auth=0;
Packit Service 31306d
    int shell=0;
Packit Service 31306d
    int i;
Packit Service 31306d
    int r;
Packit Service 31306d
Packit Service 31306d
    sshbind=ssh_bind_new();
Packit Service 31306d
    session=ssh_new();
Packit Service 31306d
Packit Service 31306d
    ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY,
Packit Service 31306d
                                            KEYS_FOLDER "ssh_host_dsa_key");
Packit Service 31306d
    ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY,
Packit Service 31306d
                                            KEYS_FOLDER "ssh_host_rsa_key");
Packit Service 31306d
Packit Service 31306d
#ifdef HAVE_ARGP_H
Packit Service 31306d
    /*
Packit Service 31306d
     * Parse our arguments; every option seen by parse_opt will
Packit Service 31306d
     * be reflected in arguments.
Packit Service 31306d
     */
Packit Service 31306d
    argp_parse (&argp, argc, argv, 0, 0, sshbind);
Packit Service 31306d
#else
Packit Service 31306d
    (void) argc;
Packit Service 31306d
    (void) argv;
Packit Service 31306d
#endif
Packit Service 31306d
#ifdef WITH_PCAP
Packit Service 31306d
    set_pcap(session);
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
    if(ssh_bind_listen(sshbind)<0){
Packit Service 31306d
        printf("Error listening to socket: %s\n", ssh_get_error(sshbind));
Packit Service 31306d
        return 1;
Packit Service 31306d
    }
Packit Service 31306d
    printf("Started sample libssh sshd on port %d\n", port);
Packit Service 31306d
    printf("You can login as the user %s with the password %s\n", SSHD_USER,
Packit Service 31306d
                                                            SSHD_PASSWORD);
Packit Service 31306d
    r = ssh_bind_accept(sshbind, session);
Packit Service 31306d
    if(r==SSH_ERROR){
Packit Service 31306d
      printf("Error accepting a connection: %s\n", ssh_get_error(sshbind));
Packit Service 31306d
      return 1;
Packit Service 31306d
    }
Packit Service 31306d
    if (ssh_handle_key_exchange(session)) {
Packit Service 31306d
        printf("ssh_handle_key_exchange: %s\n", ssh_get_error(session));
Packit Service 31306d
        return 1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* proceed to authentication */
Packit Service 31306d
    auth = authenticate(session);
Packit Service 31306d
    if (!auth || !authenticated) {
Packit Service 31306d
        printf("Authentication error: %s\n", ssh_get_error(session));
Packit Service 31306d
        ssh_disconnect(session);
Packit Service 31306d
        return 1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
    /* wait for a channel session */
Packit Service 31306d
    do {
Packit Service 31306d
        message = ssh_message_get(session);
Packit Service 31306d
        if(message){
Packit Service 31306d
            if(ssh_message_type(message) == SSH_REQUEST_CHANNEL_OPEN &&
Packit Service 31306d
                    ssh_message_subtype(message) == SSH_CHANNEL_SESSION) {
Packit Service 31306d
                chan = ssh_message_channel_request_open_reply_accept(message);
Packit Service 31306d
                ssh_message_free(message);
Packit Service 31306d
                break;
Packit Service 31306d
            } else {
Packit Service 31306d
                ssh_message_reply_default(message);
Packit Service 31306d
                ssh_message_free(message);
Packit Service 31306d
            }
Packit Service 31306d
        } else {
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
    } while(!chan);
Packit Service 31306d
Packit Service 31306d
    if(!chan) {
Packit Service 31306d
        printf("Error: cleint did not ask for a channel session (%s)\n",
Packit Service 31306d
                                                    ssh_get_error(session));
Packit Service 31306d
        ssh_finalize();
Packit Service 31306d
        return 1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
    /* wait for a shell */
Packit Service 31306d
    do {
Packit Service 31306d
        message = ssh_message_get(session);
Packit Service 31306d
        if(message != NULL) {
Packit Service 31306d
            if(ssh_message_type(message) == SSH_REQUEST_CHANNEL &&
Packit Service 31306d
                    ssh_message_subtype(message) == SSH_CHANNEL_REQUEST_SHELL) {
Packit Service 31306d
                shell = 1;
Packit Service 31306d
                ssh_message_channel_request_reply_success(message);
Packit Service 31306d
                ssh_message_free(message);
Packit Service 31306d
                break;
Packit Service 31306d
            }
Packit Service 31306d
            ssh_message_reply_default(message);
Packit Service 31306d
            ssh_message_free(message);
Packit Service 31306d
        } else {
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
    } while(!shell);
Packit Service 31306d
Packit Service 31306d
    if(!shell) {
Packit Service 31306d
        printf("Error: No shell requested (%s)\n", ssh_get_error(session));
Packit Service 31306d
        return 1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
    printf("it works !\n");
Packit Service 31306d
    do{
Packit Service 31306d
        i=ssh_channel_read(chan,buf, 2048, 0);
Packit Service 31306d
        if(i>0) {
Packit Service 31306d
            if(*buf == '?' || *buf == '?')
Packit Service 31306d
                    break;
Packit Service 31306d
            if(i == 1 && *buf == '\r')
Packit Service 31306d
                ssh_channel_write(chan, "\r\n", 2);
Packit Service 31306d
            else
Packit Service 31306d
                ssh_channel_write(chan, buf, i);
Packit Service 31306d
            if (write(1,buf,i) < 0) {
Packit Service 31306d
                printf("error writing to buffer\n");
Packit Service 31306d
                return 1;
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
    } while (i>0);
Packit Service 31306d
    ssh_channel_close(chan);
Packit Service 31306d
    ssh_disconnect(session);
Packit Service 31306d
    ssh_bind_free(sshbind);
Packit Service 31306d
#ifdef WITH_PCAP
Packit Service 31306d
    cleanup_pcap();
Packit Service 31306d
#endif
Packit Service 31306d
    ssh_finalize();
Packit Service 31306d
    return 0;
Packit Service 31306d
}
Packit Service 31306d