aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/bind.c372
-rw-r--r--src/server.c322
3 files changed, 373 insertions, 322 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 83aaf45a..48b05017 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -138,6 +138,7 @@ if (WITH_SERVER)
set(libssh_SRCS
${libssh_SRCS}
server.c
+ bind.c
)
endif (WITH_SERVER)
diff --git a/src/bind.c b/src/bind.c
new file mode 100644
index 00000000..27ad6b55
--- /dev/null
+++ b/src/bind.c
@@ -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;
+}
+
+
+/**
+ * @}
+ */
diff --git a/src/server.c b/src/server.c
index 10239773..55b677f6 100644
--- a/src/server.c
+++ b/src/server.c
@@ -43,8 +43,6 @@
#include "libssh/keys.h"
#include "libssh/dh.h"
#include "libssh/messages.h"
-#include "libssh/misc.h"
-#include "libssh/poll.h"
#define set_status(session, status) do {\
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[];
/** @internal
* 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;
}
-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 */
int ssh_handle_key_exchange(ssh_session session) {
int rc;