samplesshd.c | samplesshd.c | |||
---|---|---|---|---|
/* sshd.c */ | /* This is a sample implementation of a libssh based SSH server */ | |||
/* yet another ssh daemon (Yawn!) */ | ||||
/* | /* | |||
Copyright 2004 Aris Adamantiadis | Copyright 2003-2009 Aris Adamantiadis | |||
This file is part of the SSH Library | This file is part of the SSH Library | |||
The SSH Library is free software; you can redistribute it and/or modify | You are free to copy this file, modify it in any way, consider it being pub | |||
it under the terms of the GNU Lesser General Public License as published by | lic | |||
the Free Software Foundation; either version 2.1 of the License, or (at you | domain. This does not apply to the rest of the library though, but it is | |||
r | allowed to cut-and-paste working code from this file to any license of | |||
option) any later version. | program. | |||
The goal is to show the API in action. It's not a reference on how terminal | ||||
The SSH Library is distributed in the hope that it will be useful, but | clients must be made or how a client should react. | |||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | */ | |||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||||
License for more details. | #include "config.h" | |||
You should have received a copy of the GNU Lesser General Public License | ||||
along with the SSH Library; see the file COPYING. If not, write to | ||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | ||||
MA 02111-1307, USA. */ | ||||
#include <libssh/libssh.h> | #include <libssh/libssh.h> | |||
#include <libssh/server.h> | #include <libssh/server.h> | |||
#include <unistd.h> | ||||
#ifdef HAVE_ARGP_H | ||||
#include <argp.h> | ||||
#endif | ||||
#include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | |||
#include <stdio.h> | #include <stdio.h> | |||
#include <unistd.h> | ||||
#ifndef KEYS_FOLDER | ||||
#ifdef _WIN32 | #ifdef _WIN32 | |||
#define KEYS_FOLDER | #define KEYS_FOLDER | |||
#else | #else | |||
#define KEYS_FOLDER "/etc/ssh/" | #define KEYS_FOLDER "/etc/ssh/" | |||
#endif | #endif | |||
#endif | ||||
static int auth_password(char *user, char *password){ | static int auth_password(char *user, char *password){ | |||
if(strcmp(user,"aris")) | if(strcmp(user,"aris")) | |||
return 0; | return 0; | |||
if(strcmp(password,"lala")) | if(strcmp(password,"lala")) | |||
return 0; | return 0; | |||
return 1; // authenticated | return 1; // authenticated | |||
} | } | |||
#ifdef HAVE_ARGP_H | ||||
const char *argp_program_version = "libssh server example " | ||||
SSH_STRINGIFY(LIBSSH_VERSION); | ||||
const char *argp_program_bug_address = "<libssh@libssh.org>"; | ||||
/* Program documentation. */ | ||||
static char doc[] = "libssh -- a Secure Shell protocol implementation"; | ||||
/* A description of the arguments we accept. */ | ||||
static char args_doc[] = "BINDADDR"; | ||||
/* The options we understand. */ | ||||
static struct argp_option options[] = { | ||||
{ | ||||
.name = "port", | ||||
.key = 'p', | ||||
.arg = "PORT", | ||||
.flags = 0, | ||||
.doc = "Set the port to bind.", | ||||
.group = 0 | ||||
}, | ||||
{ | ||||
.name = "hostkey", | ||||
.key = 'k', | ||||
.arg = "FILE", | ||||
.flags = 0, | ||||
.doc = "Set the host key.", | ||||
.group = 0 | ||||
}, | ||||
{ | ||||
.name = "dsakey", | ||||
.key = 'd', | ||||
.arg = "FILE", | ||||
.flags = 0, | ||||
.doc = "Set the dsa key.", | ||||
.group = 0 | ||||
}, | ||||
{ | ||||
.name = "rsakey", | ||||
.key = 'r', | ||||
.arg = "FILE", | ||||
.flags = 0, | ||||
.doc = "Set the rsa key.", | ||||
.group = 0 | ||||
}, | ||||
{ | ||||
.name = "verbose", | ||||
.key = 'v', | ||||
.arg = NULL, | ||||
.flags = 0, | ||||
.doc = "Get verbose output.", | ||||
.group = 0 | ||||
}, | ||||
{NULL, 0, 0, 0, NULL, 0} | ||||
}; | ||||
/* Parse a single option. */ | ||||
static error_t parse_opt (int key, char *arg, struct argp_state *state) { | ||||
/* Get the input argument from argp_parse, which we | ||||
* know is a pointer to our arguments structure. | ||||
*/ | ||||
ssh_bind sshbind = state->input; | ||||
switch (key) { | ||||
case 'p': | ||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg); | ||||
break; | ||||
case 'd': | ||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg); | ||||
break; | ||||
case 'k': | ||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg); | ||||
break; | ||||
case 'r': | ||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg); | ||||
break; | ||||
case 'v': | ||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3" | ||||
); | ||||
break; | ||||
case ARGP_KEY_ARG: | ||||
if (state->arg_num >= 1) { | ||||
/* Too many arguments. */ | ||||
argp_usage (state); | ||||
} | ||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, arg); | ||||
break; | ||||
case ARGP_KEY_END: | ||||
if (state->arg_num < 1) { | ||||
/* Not enough arguments. */ | ||||
argp_usage (state); | ||||
} | ||||
break; | ||||
default: | ||||
return ARGP_ERR_UNKNOWN; | ||||
} | ||||
return 0; | ||||
} | ||||
/* Our argp parser. */ | ||||
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, N | ||||
ULL}; | ||||
#endif /* HAVE_ARGP_H */ | ||||
int main(int argc, char **argv){ | int main(int argc, char **argv){ | |||
SSH_OPTIONS *options=ssh_options_new(); | ssh_session session; | |||
SSH_SESSION *session; | ssh_bind sshbind; | |||
SSH_BIND *ssh_bind; | ssh_message message; | |||
SSH_MESSAGE *message; | ssh_channel chan=0; | |||
CHANNEL *chan=0; | ssh_buffer buf; | |||
BUFFER *buf; | ||||
int auth=0; | int auth=0; | |||
int sftp=0; | int sftp=0; | |||
int i; | int i; | |||
ssh_options_getopt(options,&argc,argv); | int r; | |||
ssh_options_set_dsa_server_key(options, KEYS_FOLDER "ssh_host_dsa_key") | ||||
; | sshbind=ssh_bind_new(); | |||
ssh_options_set_rsa_server_key(options, KEYS_FOLDER "ssh_host_rsa_key") | session=ssh_new(); | |||
; | ||||
ssh_bind=ssh_bind_new(); | ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, KEYS_FOLDER "ssh | |||
ssh_bind_set_options(ssh_bind,options); | _host_dsa_key"); | |||
if(ssh_bind_listen(ssh_bind)<0){ | ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, KEYS_FOLDER "ssh | |||
printf("Error listening to socket: %s\n",ssh_get_error(ssh_bind)); | _host_rsa_key"); | |||
#ifdef HAVE_ARGP_H | ||||
/* | ||||
* Parse our arguments; every option seen by parse_opt will | ||||
* be reflected in arguments. | ||||
*/ | ||||
argp_parse (&argp, argc, argv, 0, 0, sshbind); | ||||
#endif | ||||
if(ssh_bind_listen(sshbind)<0){ | ||||
printf("Error listening to socket: %s\n",ssh_get_error(sshbind)); | ||||
return 1; | return 1; | |||
} | } | |||
session=ssh_bind_accept(ssh_bind); | r=ssh_bind_accept(sshbind,session); | |||
if(!session){ | if(r==SSH_ERROR){ | |||
printf("error accepting a connection : %s\n",ssh_get_error(ssh_bind)) | printf("error accepting a connection : %s\n",ssh_get_error(sshbind)); | |||
; | ||||
return 1; | return 1; | |||
} | } | |||
printf("Socket connected: fd = %d\n", ssh_get_fd(session)); | ||||
if(ssh_accept(session)){ | if(ssh_accept(session)){ | |||
printf("ssh_accept: %s\n",ssh_get_error(session)); | printf("ssh_accept: %s\n",ssh_get_error(session)); | |||
return 1; | return 1; | |||
} | } | |||
do { | do { | |||
message=ssh_message_get(session); | message=ssh_message_get(session); | |||
if(!message) | if(!message) | |||
break; | break; | |||
switch(ssh_message_type(message)){ | switch(ssh_message_type(message)){ | |||
case SSH_AUTH_REQUEST: | case SSH_REQUEST_AUTH: | |||
switch(ssh_message_subtype(message)){ | switch(ssh_message_subtype(message)){ | |||
case SSH_AUTH_PASSWORD: | case SSH_AUTH_METHOD_PASSWORD: | |||
printf("User %s wants to auth with pass %s\n", | printf("User %s wants to auth with pass %s\n", | |||
ssh_message_auth_user(message), | ssh_message_auth_user(message), | |||
ssh_message_auth_password(message)); | ssh_message_auth_password(message)); | |||
if(auth_password(ssh_message_auth_user(message), | if(auth_password(ssh_message_auth_user(message), | |||
ssh_message_auth_password(message))){ | ssh_message_auth_password(message))){ | |||
auth=1; | auth=1; | |||
ssh_message_auth_reply_success(message,0); | ssh_message_auth_reply_success(message,0); | |||
break; | break; | |||
} | } | |||
// not authenticated, send default message | // not authenticated, send default message | |||
case SSH_AUTH_NONE: | case SSH_AUTH_METHOD_NONE: | |||
default: | default: | |||
ssh_message_auth_set_methods(message,SSH_AUTH_PASSW ORD); | ssh_message_auth_set_methods(message,SSH_AUTH_METHO D_PASSWORD); | |||
ssh_message_reply_default(message); | ssh_message_reply_default(message); | |||
break; | break; | |||
} | } | |||
break; | break; | |||
default: | default: | |||
ssh_message_reply_default(message); | ssh_message_reply_default(message); | |||
} | } | |||
ssh_message_free(message); | ssh_message_free(message); | |||
} while (!auth); | } while (!auth); | |||
if(!auth){ | if(!auth){ | |||
printf("auth error: %s\n",ssh_get_error(session)); | printf("auth error: %s\n",ssh_get_error(session)); | |||
ssh_finalize(); | ssh_disconnect(session); | |||
return 1; | return 1; | |||
} | } | |||
do { | do { | |||
message=ssh_message_get(session); | message=ssh_message_get(session); | |||
if(message){ | if(message){ | |||
switch(ssh_message_type(message)){ | switch(ssh_message_type(message)){ | |||
case SSH_CHANNEL_REQUEST_OPEN: | case SSH_REQUEST_CHANNEL_OPEN: | |||
if(ssh_message_subtype(message)==SSH_CHANNEL_SESSION){ | if(ssh_message_subtype(message)==SSH_CHANNEL_SESSION){ | |||
chan=ssh_message_channel_request_open_reply_accept( message); | chan=ssh_message_channel_request_open_reply_accept( message); | |||
break; | break; | |||
} | } | |||
default: | default: | |||
ssh_message_reply_default(message); | ssh_message_reply_default(message); | |||
} | } | |||
ssh_message_free(message); | ssh_message_free(message); | |||
} | } | |||
} while(message && !chan); | } while(message && !chan); | |||
if(!chan){ | if(!chan){ | |||
printf("error : %s\n",ssh_get_error(session)); | printf("error : %s\n",ssh_get_error(session)); | |||
ssh_finalize(); | ssh_finalize(); | |||
return 1; | return 1; | |||
} | } | |||
do { | do { | |||
message=ssh_message_get(session); | message=ssh_message_get(session); | |||
if(message && ssh_message_type(message)==SSH_CHANNEL_REQUEST && | if(message && ssh_message_type(message)==SSH_REQUEST_CHANNEL && | |||
ssh_message_subtype(message)==SSH_CHANNEL_REQUEST_SHELL){ | ssh_message_subtype(message)==SSH_CHANNEL_REQUEST_SHELL){ | |||
// if(!strcmp(ssh_message_channel_request_subsystem(message),"sf tp")){ | // if(!strcmp(ssh_message_channel_request_subsystem(message),"sf tp")){ | |||
sftp=1; | sftp=1; | |||
ssh_message_channel_request_reply_success(message); | ssh_message_channel_request_reply_success(message); | |||
break; | break; | |||
// } | // } | |||
} | } | |||
if(!sftp){ | if(!sftp){ | |||
ssh_message_reply_default(message); | ssh_message_reply_default(message); | |||
} | } | |||
skipping to change at line 154 | skipping to change at line 265 | |||
} | } | |||
printf("it works !\n"); | printf("it works !\n"); | |||
buf=buffer_new(); | buf=buffer_new(); | |||
do{ | do{ | |||
i=channel_read_buffer(chan,buf,0,0); | i=channel_read_buffer(chan,buf,0,0); | |||
if(i>0) | if(i>0) | |||
write(1,buffer_get(buf),buffer_get_len(buf)); | write(1,buffer_get(buf),buffer_get_len(buf)); | |||
} while (i>0); | } while (i>0); | |||
buffer_free(buf); | buffer_free(buf); | |||
ssh_disconnect(session); | ssh_disconnect(session); | |||
ssh_bind_free(ssh_bind); | ssh_bind_free(sshbind); | |||
ssh_finalize(); | ssh_finalize(); | |||
return 0; | return 0; | |||
} | } | |||
End of changes. 19 change blocks. | ||||
47 lines changed or deleted | 159 lines changed or added | |||
This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ |