mirror of
https://git.libssh.org/projects/libssh.git
synced 2025-11-29 01:03:57 +03:00
Split ssh_bind functions in a new .c file
This commit is contained in:
@@ -138,6 +138,7 @@ if (WITH_SERVER)
|
|||||||
set(libssh_SRCS
|
set(libssh_SRCS
|
||||||
${libssh_SRCS}
|
${libssh_SRCS}
|
||||||
server.c
|
server.c
|
||||||
|
bind.c
|
||||||
)
|
)
|
||||||
endif (WITH_SERVER)
|
endif (WITH_SERVER)
|
||||||
|
|
||||||
|
|||||||
372
src/bind.c
Normal file
372
src/bind.c
Normal file
@@ -0,0 +1,372 @@
|
|||||||
|
/*
|
||||||
|
* bind.c : all ssh_bind functions
|
||||||
|
*
|
||||||
|
* This file is part of the SSH Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004-2005 by Aris Adamantiadis
|
||||||
|
*
|
||||||
|
* The SSH Library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* The SSH Library is distributed in the hope that it will be useful, but
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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 "config.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "libssh/priv.h"
|
||||||
|
#include "libssh/libssh.h"
|
||||||
|
#include "libssh/server.h"
|
||||||
|
#include "libssh/keyfiles.h"
|
||||||
|
#include "libssh/buffer.h"
|
||||||
|
#include "libssh/socket.h"
|
||||||
|
#include "libssh/session.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup libssh_server
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#include <winsock2.h>
|
||||||
|
#define SOCKOPT_TYPE_ARG4 char
|
||||||
|
|
||||||
|
/* We need to provide hstrerror. Not we can't call the parameter h_errno because it's #defined */
|
||||||
|
static char *hstrerror(int h_errno_val) {
|
||||||
|
static char text[50] = {0};
|
||||||
|
|
||||||
|
snprintf(text, sizeof(text), "gethostbyname error %d\n", h_errno_val);
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
#else /* _WIN32 */
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#define SOCKOPT_TYPE_ARG4 int
|
||||||
|
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
/* TODO FIXME: must use getaddrinfo */
|
||||||
|
static socket_t bind_socket(ssh_bind sshbind, const char *hostname,
|
||||||
|
int port) {
|
||||||
|
struct sockaddr_in myaddr;
|
||||||
|
struct hostent *hp=NULL;
|
||||||
|
socket_t s;
|
||||||
|
int opt = 1;
|
||||||
|
|
||||||
|
s = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
|
if (s < 0) {
|
||||||
|
ssh_set_error(sshbind, SSH_FATAL, "%s", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_GETHOSTBYNAME
|
||||||
|
hp = gethostbyname(hostname);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (hp == NULL) {
|
||||||
|
ssh_set_error(sshbind, SSH_FATAL,
|
||||||
|
"Resolving %s: %s", hostname, hstrerror(h_errno));
|
||||||
|
close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&myaddr, 0, sizeof(myaddr));
|
||||||
|
memcpy(&myaddr.sin_addr, hp->h_addr, hp->h_length);
|
||||||
|
myaddr.sin_family = hp->h_addrtype;
|
||||||
|
myaddr.sin_port = htons(port);
|
||||||
|
|
||||||
|
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0) {
|
||||||
|
ssh_set_error(sshbind, SSH_FATAL,
|
||||||
|
"Setting socket options failed: %s", hstrerror(h_errno));
|
||||||
|
close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind(s, (struct sockaddr *) &myaddr, sizeof(myaddr)) < 0) {
|
||||||
|
ssh_set_error(sshbind, SSH_FATAL, "Binding to %s:%d: %s",
|
||||||
|
hostname,
|
||||||
|
port,
|
||||||
|
strerror(errno));
|
||||||
|
close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_bind ssh_bind_new(void) {
|
||||||
|
ssh_bind ptr;
|
||||||
|
|
||||||
|
ptr = malloc(sizeof(struct ssh_bind_struct));
|
||||||
|
if (ptr == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ZERO_STRUCTP(ptr);
|
||||||
|
ptr->bindfd = SSH_INVALID_SOCKET;
|
||||||
|
ptr->bindport= 22;
|
||||||
|
ptr->log_verbosity = 0;
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ssh_bind_listen(ssh_bind sshbind) {
|
||||||
|
const char *host;
|
||||||
|
socket_t fd;
|
||||||
|
|
||||||
|
if (ssh_init() < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
host = sshbind->bindaddr;
|
||||||
|
if (host == NULL) {
|
||||||
|
host = "0.0.0.0";
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = bind_socket(sshbind, host, sshbind->bindport);
|
||||||
|
if (fd == SSH_INVALID_SOCKET) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sshbind->bindfd = fd;
|
||||||
|
|
||||||
|
if (listen(fd, 10) < 0) {
|
||||||
|
ssh_set_error(sshbind, SSH_FATAL,
|
||||||
|
"Listening to socket %d: %s",
|
||||||
|
fd, strerror(errno));
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set the bind callbacks for ssh_bind
|
||||||
|
* @code
|
||||||
|
* struct ssh_callbacks_struct cb = {
|
||||||
|
* .userdata = data,
|
||||||
|
* .auth_function = my_auth_function
|
||||||
|
* };
|
||||||
|
* ssh_callbacks_init(&cb);
|
||||||
|
* ssh_set_callbacks(session, &cb);
|
||||||
|
* @endcode
|
||||||
|
* @param sshbind the ssh_bind structure to set
|
||||||
|
* @param callbacks a ssh_bind_callbacks instance already set up. Do
|
||||||
|
* use ssh_callbacks_init() to initialize it.
|
||||||
|
* @param userdata userdata to be used with each callback called
|
||||||
|
* within callbacks.
|
||||||
|
* @returns SSH_OK on success,
|
||||||
|
* SSH_ERROR on error.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ssh_bind_set_callbacks(ssh_bind sshbind, ssh_bind_callbacks callbacks,
|
||||||
|
void *userdata){
|
||||||
|
if (sshbind == NULL || callbacks == NULL) {
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
if(callbacks->size <= 0 || callbacks->size > 1024 * sizeof(void *)){
|
||||||
|
ssh_set_error(sshbind,SSH_FATAL,
|
||||||
|
"Invalid callback passed in (badly initialized)");
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
sshbind->bind_callbacks = callbacks;
|
||||||
|
sshbind->bind_callbacks_userdata=userdata;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @internal
|
||||||
|
* @brief callback being called by poll when an event happens
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static int ssh_bind_poll_callback(ssh_poll_handle sshpoll,
|
||||||
|
socket_t fd, int revents, void *user){
|
||||||
|
ssh_bind sshbind=(ssh_bind)user;
|
||||||
|
(void)sshpoll;
|
||||||
|
(void)fd;
|
||||||
|
|
||||||
|
if(revents & POLLIN){
|
||||||
|
/* new incoming connection */
|
||||||
|
if(ssh_callbacks_exists(sshbind->bind_callbacks,incoming_connection)){
|
||||||
|
sshbind->bind_callbacks->incoming_connection(sshbind,
|
||||||
|
sshbind->bind_callbacks_userdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @internal
|
||||||
|
* @brief returns the current poll handle, or create it
|
||||||
|
* @param sshbind the ssh_bind object
|
||||||
|
* @returns a ssh_poll handle suitable for operation
|
||||||
|
*/
|
||||||
|
ssh_poll_handle ssh_bind_get_poll(ssh_bind sshbind){
|
||||||
|
if(sshbind->poll)
|
||||||
|
return sshbind->poll;
|
||||||
|
sshbind->poll=ssh_poll_new(sshbind->bindfd,POLLIN,
|
||||||
|
ssh_bind_poll_callback,sshbind);
|
||||||
|
return sshbind->poll;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssh_bind_set_blocking(ssh_bind sshbind, int blocking) {
|
||||||
|
sshbind->blocking = blocking ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket_t ssh_bind_get_fd(ssh_bind sshbind) {
|
||||||
|
return sshbind->bindfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssh_bind_set_fd(ssh_bind sshbind, socket_t fd) {
|
||||||
|
sshbind->bindfd = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssh_bind_fd_toaccept(ssh_bind sshbind) {
|
||||||
|
sshbind->toaccept = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssh_bind_free(ssh_bind sshbind){
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (sshbind == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sshbind->bindfd >= 0) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
closesocket(sshbind->bindfd);
|
||||||
|
#else
|
||||||
|
close(sshbind->bindfd);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
sshbind->bindfd = SSH_INVALID_SOCKET;
|
||||||
|
|
||||||
|
/* options */
|
||||||
|
SAFE_FREE(sshbind->banner);
|
||||||
|
SAFE_FREE(sshbind->dsakey);
|
||||||
|
SAFE_FREE(sshbind->rsakey);
|
||||||
|
SAFE_FREE(sshbind->bindaddr);
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
if (sshbind->wanted_methods[i]) {
|
||||||
|
SAFE_FREE(sshbind->wanted_methods[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SAFE_FREE(sshbind);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ssh_bind_accept(ssh_bind sshbind, ssh_session session) {
|
||||||
|
ssh_private_key dsa = NULL;
|
||||||
|
ssh_private_key rsa = NULL;
|
||||||
|
socket_t fd = SSH_INVALID_SOCKET;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (sshbind->bindfd == SSH_INVALID_SOCKET) {
|
||||||
|
ssh_set_error(sshbind, SSH_FATAL,
|
||||||
|
"Can't accept new clients on a not bound socket.");
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
if(session == NULL){
|
||||||
|
ssh_set_error(sshbind, SSH_FATAL,"session is null");
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
if (sshbind->dsakey == NULL && sshbind->rsakey == NULL) {
|
||||||
|
ssh_set_error(sshbind, SSH_FATAL,
|
||||||
|
"DSA or RSA host key file must be set before accept()");
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sshbind->dsakey) {
|
||||||
|
dsa = _privatekey_from_file(sshbind, sshbind->dsakey, SSH_KEYTYPE_DSS);
|
||||||
|
if (dsa == NULL) {
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sshbind->rsakey) {
|
||||||
|
rsa = _privatekey_from_file(sshbind, sshbind->rsakey, SSH_KEYTYPE_RSA);
|
||||||
|
if (rsa == NULL) {
|
||||||
|
privatekey_free(dsa);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = accept(sshbind->bindfd, NULL, NULL);
|
||||||
|
if (fd == SSH_INVALID_SOCKET) {
|
||||||
|
ssh_set_error(sshbind, SSH_FATAL,
|
||||||
|
"Accepting a new connection: %s",
|
||||||
|
strerror(errno));
|
||||||
|
privatekey_free(dsa);
|
||||||
|
privatekey_free(rsa);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
session->server = 1;
|
||||||
|
session->version = 2;
|
||||||
|
|
||||||
|
/* copy options */
|
||||||
|
for (i = 0; i < 10; ++i) {
|
||||||
|
if (sshbind->wanted_methods[i]) {
|
||||||
|
session->wanted_methods[i] = strdup(sshbind->wanted_methods[i]);
|
||||||
|
if (session->wanted_methods[i] == NULL) {
|
||||||
|
privatekey_free(dsa);
|
||||||
|
privatekey_free(rsa);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sshbind->bindaddr == NULL)
|
||||||
|
session->bindaddr = NULL;
|
||||||
|
else {
|
||||||
|
SAFE_FREE(session->bindaddr);
|
||||||
|
session->bindaddr = strdup(sshbind->bindaddr);
|
||||||
|
if (session->bindaddr == NULL) {
|
||||||
|
privatekey_free(dsa);
|
||||||
|
privatekey_free(rsa);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
session->log_verbosity = sshbind->log_verbosity;
|
||||||
|
|
||||||
|
ssh_socket_free(session->socket);
|
||||||
|
session->socket = ssh_socket_new(session);
|
||||||
|
if (session->socket == NULL) {
|
||||||
|
privatekey_free(dsa);
|
||||||
|
privatekey_free(rsa);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
ssh_socket_set_fd(session->socket, fd);
|
||||||
|
ssh_socket_get_poll_handle_out(session->socket);
|
||||||
|
session->dsa_key = dsa;
|
||||||
|
session->rsa_key = rsa;
|
||||||
|
|
||||||
|
return SSH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
322
src/server.c
322
src/server.c
@@ -43,8 +43,6 @@
|
|||||||
#include "libssh/keys.h"
|
#include "libssh/keys.h"
|
||||||
#include "libssh/dh.h"
|
#include "libssh/dh.h"
|
||||||
#include "libssh/messages.h"
|
#include "libssh/messages.h"
|
||||||
#include "libssh/misc.h"
|
|
||||||
#include "libssh/poll.h"
|
|
||||||
|
|
||||||
#define set_status(session, status) do {\
|
#define set_status(session, status) do {\
|
||||||
if (session->callbacks && session->callbacks->connect_status_function) \
|
if (session->callbacks && session->callbacks->connect_status_function) \
|
||||||
@@ -60,236 +58,6 @@ static int dh_handshake_server(ssh_session session);
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
|
|
||||||
#include <winsock2.h>
|
|
||||||
#define SOCKOPT_TYPE_ARG4 char
|
|
||||||
|
|
||||||
/* We need to provide hstrerror. Not we can't call the parameter h_errno because it's #defined */
|
|
||||||
static char *hstrerror(int h_errno_val) {
|
|
||||||
static char text[50] = {0};
|
|
||||||
|
|
||||||
snprintf(text, sizeof(text), "gethostbyname error %d\n", h_errno_val);
|
|
||||||
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
#else /* _WIN32 */
|
|
||||||
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#define SOCKOPT_TYPE_ARG4 int
|
|
||||||
|
|
||||||
#endif /* _WIN32 */
|
|
||||||
|
|
||||||
/* TODO FIXME: must use getaddrinfo */
|
|
||||||
static socket_t bind_socket(ssh_bind sshbind, const char *hostname,
|
|
||||||
int port) {
|
|
||||||
struct sockaddr_in myaddr;
|
|
||||||
struct hostent *hp=NULL;
|
|
||||||
socket_t s;
|
|
||||||
int opt = 1;
|
|
||||||
|
|
||||||
s = socket(PF_INET, SOCK_STREAM, 0);
|
|
||||||
if (s < 0) {
|
|
||||||
ssh_set_error(sshbind, SSH_FATAL, "%s", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_GETHOSTBYNAME
|
|
||||||
hp = gethostbyname(hostname);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (hp == NULL) {
|
|
||||||
ssh_set_error(sshbind, SSH_FATAL,
|
|
||||||
"Resolving %s: %s", hostname, hstrerror(h_errno));
|
|
||||||
close(s);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&myaddr, 0, sizeof(myaddr));
|
|
||||||
memcpy(&myaddr.sin_addr, hp->h_addr, hp->h_length);
|
|
||||||
myaddr.sin_family = hp->h_addrtype;
|
|
||||||
myaddr.sin_port = htons(port);
|
|
||||||
|
|
||||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0) {
|
|
||||||
ssh_set_error(sshbind, SSH_FATAL,
|
|
||||||
"Setting socket options failed: %s", hstrerror(h_errno));
|
|
||||||
close(s);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bind(s, (struct sockaddr *) &myaddr, sizeof(myaddr)) < 0) {
|
|
||||||
ssh_set_error(sshbind, SSH_FATAL, "Binding to %s:%d: %s",
|
|
||||||
hostname,
|
|
||||||
port,
|
|
||||||
strerror(errno));
|
|
||||||
close(s);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh_bind ssh_bind_new(void) {
|
|
||||||
ssh_bind ptr;
|
|
||||||
|
|
||||||
ptr = malloc(sizeof(struct ssh_bind_struct));
|
|
||||||
if (ptr == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
ZERO_STRUCTP(ptr);
|
|
||||||
ptr->bindfd = SSH_INVALID_SOCKET;
|
|
||||||
ptr->bindport= 22;
|
|
||||||
ptr->log_verbosity = 0;
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ssh_bind_listen(ssh_bind sshbind) {
|
|
||||||
const char *host;
|
|
||||||
socket_t fd;
|
|
||||||
|
|
||||||
if (ssh_init() < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
host = sshbind->bindaddr;
|
|
||||||
if (host == NULL) {
|
|
||||||
host = "0.0.0.0";
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = bind_socket(sshbind, host, sshbind->bindport);
|
|
||||||
if (fd == SSH_INVALID_SOCKET) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
sshbind->bindfd = fd;
|
|
||||||
|
|
||||||
if (listen(fd, 10) < 0) {
|
|
||||||
ssh_set_error(sshbind, SSH_FATAL,
|
|
||||||
"Listening to socket %d: %s",
|
|
||||||
fd, strerror(errno));
|
|
||||||
close(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief set the bind callbacks for ssh_bind
|
|
||||||
* @code
|
|
||||||
* struct ssh_callbacks_struct cb = {
|
|
||||||
* .userdata = data,
|
|
||||||
* .auth_function = my_auth_function
|
|
||||||
* };
|
|
||||||
* ssh_callbacks_init(&cb);
|
|
||||||
* ssh_set_callbacks(session, &cb);
|
|
||||||
* @endcode
|
|
||||||
* @param sshbind the ssh_bind structure to set
|
|
||||||
* @param callbacks a ssh_bind_callbacks instance already set up. Do
|
|
||||||
* use ssh_callbacks_init() to initialize it.
|
|
||||||
* @param userdata userdata to be used with each callback called
|
|
||||||
* within callbacks.
|
|
||||||
* @returns SSH_OK on success,
|
|
||||||
* SSH_ERROR on error.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int ssh_bind_set_callbacks(ssh_bind sshbind, ssh_bind_callbacks callbacks,
|
|
||||||
void *userdata){
|
|
||||||
if (sshbind == NULL || callbacks == NULL) {
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
if(callbacks->size <= 0 || callbacks->size > 1024 * sizeof(void *)){
|
|
||||||
ssh_set_error(sshbind,SSH_FATAL,
|
|
||||||
"Invalid callback passed in (badly initialized)");
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
sshbind->bind_callbacks = callbacks;
|
|
||||||
sshbind->bind_callbacks_userdata=userdata;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @internal
|
|
||||||
* @brief callback being called by poll when an event happens
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static int ssh_bind_poll_callback(ssh_poll_handle sshpoll,
|
|
||||||
socket_t fd, int revents, void *user){
|
|
||||||
ssh_bind sshbind=(ssh_bind)user;
|
|
||||||
(void)sshpoll;
|
|
||||||
(void)fd;
|
|
||||||
|
|
||||||
if(revents & POLLIN){
|
|
||||||
/* new incoming connection */
|
|
||||||
if(ssh_callbacks_exists(sshbind->bind_callbacks,incoming_connection)){
|
|
||||||
sshbind->bind_callbacks->incoming_connection(sshbind,
|
|
||||||
sshbind->bind_callbacks_userdata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @internal
|
|
||||||
* @brief returns the current poll handle, or create it
|
|
||||||
* @param sshbind the ssh_bind object
|
|
||||||
* @returns a ssh_poll handle suitable for operation
|
|
||||||
*/
|
|
||||||
ssh_poll_handle ssh_bind_get_poll(ssh_bind sshbind){
|
|
||||||
if(sshbind->poll)
|
|
||||||
return sshbind->poll;
|
|
||||||
sshbind->poll=ssh_poll_new(sshbind->bindfd,POLLIN,
|
|
||||||
ssh_bind_poll_callback,sshbind);
|
|
||||||
return sshbind->poll;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ssh_bind_set_blocking(ssh_bind sshbind, int blocking) {
|
|
||||||
sshbind->blocking = blocking ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
socket_t ssh_bind_get_fd(ssh_bind sshbind) {
|
|
||||||
return sshbind->bindfd;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ssh_bind_set_fd(ssh_bind sshbind, socket_t fd) {
|
|
||||||
sshbind->bindfd = fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ssh_bind_fd_toaccept(ssh_bind sshbind) {
|
|
||||||
sshbind->toaccept = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ssh_bind_free(ssh_bind sshbind){
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (sshbind == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sshbind->bindfd >= 0) {
|
|
||||||
#ifdef _WIN32
|
|
||||||
closesocket(sshbind->bindfd);
|
|
||||||
#else
|
|
||||||
close(sshbind->bindfd);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
sshbind->bindfd = SSH_INVALID_SOCKET;
|
|
||||||
|
|
||||||
/* options */
|
|
||||||
SAFE_FREE(sshbind->banner);
|
|
||||||
SAFE_FREE(sshbind->dsakey);
|
|
||||||
SAFE_FREE(sshbind->rsakey);
|
|
||||||
SAFE_FREE(sshbind->bindaddr);
|
|
||||||
|
|
||||||
for (i = 0; i < 10; i++) {
|
|
||||||
if (sshbind->wanted_methods[i]) {
|
|
||||||
SAFE_FREE(sshbind->wanted_methods[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SAFE_FREE(sshbind);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern char *supported_methods[];
|
extern char *supported_methods[];
|
||||||
/** @internal
|
/** @internal
|
||||||
* This functions sets the Key Exchange protocols to be accepted
|
* This functions sets the Key Exchange protocols to be accepted
|
||||||
@@ -667,96 +435,6 @@ static int callback_receive_banner(const void *data, size_t len, void *user) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ssh_bind_accept(ssh_bind sshbind, ssh_session session) {
|
|
||||||
ssh_private_key dsa = NULL;
|
|
||||||
ssh_private_key rsa = NULL;
|
|
||||||
socket_t fd = SSH_INVALID_SOCKET;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (sshbind->bindfd == SSH_INVALID_SOCKET) {
|
|
||||||
ssh_set_error(sshbind, SSH_FATAL,
|
|
||||||
"Can't accept new clients on a not bound socket.");
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
if(session == NULL){
|
|
||||||
ssh_set_error(sshbind, SSH_FATAL,"session is null");
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
if (sshbind->dsakey == NULL && sshbind->rsakey == NULL) {
|
|
||||||
ssh_set_error(sshbind, SSH_FATAL,
|
|
||||||
"DSA or RSA host key file must be set before accept()");
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sshbind->dsakey) {
|
|
||||||
dsa = _privatekey_from_file(sshbind, sshbind->dsakey, SSH_KEYTYPE_DSS);
|
|
||||||
if (dsa == NULL) {
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sshbind->rsakey) {
|
|
||||||
rsa = _privatekey_from_file(sshbind, sshbind->rsakey, SSH_KEYTYPE_RSA);
|
|
||||||
if (rsa == NULL) {
|
|
||||||
privatekey_free(dsa);
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = accept(sshbind->bindfd, NULL, NULL);
|
|
||||||
if (fd == SSH_INVALID_SOCKET) {
|
|
||||||
ssh_set_error(sshbind, SSH_FATAL,
|
|
||||||
"Accepting a new connection: %s",
|
|
||||||
strerror(errno));
|
|
||||||
privatekey_free(dsa);
|
|
||||||
privatekey_free(rsa);
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
session->server = 1;
|
|
||||||
session->version = 2;
|
|
||||||
|
|
||||||
/* copy options */
|
|
||||||
for (i = 0; i < 10; ++i) {
|
|
||||||
if (sshbind->wanted_methods[i]) {
|
|
||||||
session->wanted_methods[i] = strdup(sshbind->wanted_methods[i]);
|
|
||||||
if (session->wanted_methods[i] == NULL) {
|
|
||||||
privatekey_free(dsa);
|
|
||||||
privatekey_free(rsa);
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sshbind->bindaddr == NULL)
|
|
||||||
session->bindaddr = NULL;
|
|
||||||
else {
|
|
||||||
SAFE_FREE(session->bindaddr);
|
|
||||||
session->bindaddr = strdup(sshbind->bindaddr);
|
|
||||||
if (session->bindaddr == NULL) {
|
|
||||||
privatekey_free(dsa);
|
|
||||||
privatekey_free(rsa);
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
session->log_verbosity = sshbind->log_verbosity;
|
|
||||||
|
|
||||||
ssh_socket_free(session->socket);
|
|
||||||
session->socket = ssh_socket_new(session);
|
|
||||||
if (session->socket == NULL) {
|
|
||||||
privatekey_free(dsa);
|
|
||||||
privatekey_free(rsa);
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
ssh_socket_set_fd(session->socket, fd);
|
|
||||||
ssh_socket_get_poll_handle_out(session->socket);
|
|
||||||
session->dsa_key = dsa;
|
|
||||||
session->rsa_key = rsa;
|
|
||||||
|
|
||||||
return SSH_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do the banner and key exchange */
|
/* Do the banner and key exchange */
|
||||||
int ssh_handle_key_exchange(ssh_session session) {
|
int ssh_handle_key_exchange(ssh_session session) {
|
||||||
int rc;
|
int rc;
|
||||||
|
|||||||
Reference in New Issue
Block a user