diff options
Diffstat (limited to 'libssh/connect.c')
-rw-r--r-- | libssh/connect.c | 600 |
1 files changed, 0 insertions, 600 deletions
diff --git a/libssh/connect.c b/libssh/connect.c deleted file mode 100644 index d877982c..00000000 --- a/libssh/connect.c +++ /dev/null @@ -1,600 +0,0 @@ -/* - * connect.c - handles connections to ssh servers - * - * This file is part of the SSH Library - * - * Copyright (c) 2003-2009 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 <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#ifdef _WIN32 -/* - * Only use Windows API functions available on Windows 2000 SP4 or later. - * The available constants are in <sdkddkver.h>. - * http://msdn.microsoft.com/en-us/library/aa383745.aspx - * http://blogs.msdn.com/oldnewthing/archive/2007/04/11/2079137.aspx - */ -#undef _WIN32_WINNT -#ifdef HAVE_WSPIAPI_H -#define _WIN32_WINNT 0x0500 /* _WIN32_WINNT_WIN2K */ -#undef NTDDI_VERSION -#define NTDDI_VERSION 0x05000400 /* NTDDI_WIN2KSP4 */ -#else -#define _WIN32_WINNT 0x0501 /* _WIN32_WINNT_WINXP */ -#undef NTDDI_VERSION -#define NTDDI_VERSION 0x05010000 /* NTDDI_WINXP */ -#endif - -#if _MSC_VER >= 1400 -#include <io.h> -#undef close -#define close _close -#endif /* _MSC_VER */ -#include <winsock2.h> -#include <ws2tcpip.h> - -/* <wspiapi.h> is necessary for getaddrinfo before Windows XP, but it isn't - * available on some platforms like MinGW. */ -#ifdef HAVE_WSPIAPI_H -#include <wspiapi.h> -#endif - -#else /* _WIN32 */ - -#include <netdb.h> -#include <sys/socket.h> -#include <sys/select.h> -#include <netinet/in.h> - -#endif /* _WIN32 */ - -#include "libssh/priv.h" -#include "libssh/socket.h" -#include "libssh/channels.h" -#include "libssh/session.h" - -#ifndef HAVE_SELECT -#error "Your system must have select()" -#endif - -#ifndef HAVE_GETADDRINFO -#error "Your system must have getaddrinfo()" -#endif - -#ifdef HAVE_REGCOMP -/* don't declare gnu extended regexp's */ -#ifndef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE -#endif -#include <regex.h> -#endif /* HAVE_REGCOMP */ - -#ifdef _WIN32 -void ssh_sock_set_nonblocking(socket_t sock) { - u_long nonblocking = 1; - ioctlsocket(sock, FIONBIO, &nonblocking); -} - -void ssh_sock_set_blocking(socket_t sock) { - u_long nonblocking = 0; - ioctlsocket(sock, FIONBIO, &nonblocking); -} - -#ifndef gai_strerror -char WSAAPI *gai_strerrorA(int code) { - static char buf[256]; - - snprintf(buf, sizeof(buf), "Undetermined error code (%d)", code); - - return buf; -} -#endif /* gai_strerror */ - -#else /* _WIN32 */ -void ssh_sock_set_nonblocking(socket_t sock) { - fcntl(sock, F_SETFL, O_NONBLOCK); -} - -void ssh_sock_set_blocking(socket_t sock) { - fcntl(sock, F_SETFL, 0); -} - -#endif /* _WIN32 */ - -#ifdef HAVE_REGCOMP -static regex_t *ip_regex = NULL; - -/** @internal - * @brief initializes and compile the regexp to be used for IP matching - * @returns -1 on error (and error message is set) - * @returns 0 on success - */ -int ssh_regex_init(){ - if(ip_regex==NULL){ - int err; - regex_t *regex=malloc(sizeof (regex_t)); - ZERO_STRUCTP(regex); - err=regcomp(regex,"^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$",REG_EXTENDED | REG_NOSUB); - if(err != 0){ - char buffer[128]; - regerror(err,regex,buffer,sizeof(buffer)); - fprintf(stderr,"Error while compiling regular expression : %s\n",buffer); - SAFE_FREE(regex); - return -1; - } - ip_regex=regex; - } - return 0; -} - -/** @internal - * @brief clean up the IP regexp - */ -void ssh_regex_finalize(){ - if(ip_regex){ - regfree(ip_regex); - SAFE_FREE(ip_regex); - } -} - -#else /* HAVE_REGCOMP */ -int ssh_regex_init(){ - return 0; -} -void ssh_regex_finalize(){ -} -#endif - - -static int ssh_connect_socket_close(socket_t s){ -#ifdef _WIN32 - return closesocket(s); -#else - return close(s); -#endif -} - - -static int getai(ssh_session session, const char *host, int port, struct addrinfo **ai) { - const char *service = NULL; - struct addrinfo hints; - char s_port[10]; - - ZERO_STRUCT(hints); - - hints.ai_protocol = IPPROTO_TCP; - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - - if (port == 0) { - hints.ai_flags = AI_PASSIVE; - } else { - snprintf(s_port, sizeof(s_port), "%hu", (unsigned short)port); - service = s_port; -#ifdef AI_NUMERICSERV - hints.ai_flags=AI_NUMERICSERV; -#endif - } -#ifdef HAVE_REGCOMP - if(regexec(ip_regex,host,0,NULL,0) == 0){ - /* this is an IP address */ - ssh_log(session,SSH_LOG_PACKET,"host %s matches an IP address",host); - hints.ai_flags |= AI_NUMERICHOST; - } -#endif - return getaddrinfo(host, service, &hints, ai); -} - -static int ssh_connect_ai_timeout(ssh_session session, const char *host, - int port, struct addrinfo *ai, long timeout, long usec, socket_t s) { - struct timeval to; - fd_set set; - int rc = 0; - unsigned int len = sizeof(rc); - - enter_function(); - - to.tv_sec = timeout; - to.tv_usec = usec; - - ssh_sock_set_nonblocking(s); - - ssh_log(session, SSH_LOG_RARE, "Trying to connect to host: %s:%d with " - "timeout %ld.%ld", host, port, timeout, usec); - - /* The return value is checked later */ - connect(s, ai->ai_addr, ai->ai_addrlen); - freeaddrinfo(ai); - - FD_ZERO(&set); - FD_SET(s, &set); - - rc = select(s + 1, NULL, &set, NULL, &to); - if (rc == 0) { - /* timeout */ - ssh_set_error(session, SSH_FATAL, - "Timeout while connecting to %s:%d", host, port); - ssh_connect_socket_close(s); - leave_function(); - return -1; - } - - if (rc < 0) { - ssh_set_error(session, SSH_FATAL, - "Select error: %s", strerror(errno)); - ssh_connect_socket_close(s); - leave_function(); - return -1; - } - rc = 0; - - /* Get connect(2) return code. Zero means no error */ - getsockopt(s, SOL_SOCKET, SO_ERROR,(char *) &rc, &len); - if (rc != 0) { - ssh_set_error(session, SSH_FATAL, - "Connect to %s:%d failed: %s", host, port, strerror(rc)); - ssh_connect_socket_close(s); - leave_function(); - return -1; - } - - /* s is connected ? */ - ssh_log(session, SSH_LOG_PACKET, "Socket connected with timeout\n"); - ssh_sock_set_blocking(s); - - leave_function(); - return s; -} - -/** - * @internal - * - * @brief Connect to an IPv4 or IPv6 host specified by its IP address or - * hostname. - * - * @returns A file descriptor, < 0 on error. - */ -socket_t ssh_connect_host(ssh_session session, const char *host, - const char *bind_addr, int port, long timeout, long usec) { - socket_t s = -1; - int rc; - struct addrinfo *ai; - struct addrinfo *itr; - - enter_function(); - - rc = getai(session,host, port, &ai); - if (rc != 0) { - ssh_set_error(session, SSH_FATAL, - "Failed to resolve hostname %s (%s)", host, gai_strerror(rc)); - leave_function(); - return -1; - } - - for (itr = ai; itr != NULL; itr = itr->ai_next){ - /* create socket */ - s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol); - if (s < 0) { - ssh_set_error(session, SSH_FATAL, - "Socket create failed: %s", strerror(errno)); - continue; - } - - if (bind_addr) { - struct addrinfo *bind_ai; - struct addrinfo *bind_itr; - - ssh_log(session, SSH_LOG_PACKET, "Resolving %s\n", bind_addr); - - rc = getai(session,bind_addr, 0, &bind_ai); - if (rc != 0) { - ssh_set_error(session, SSH_FATAL, - "Failed to resolve bind address %s (%s)", - bind_addr, - gai_strerror(rc)); - leave_function(); - return -1; - } - - for (bind_itr = bind_ai; bind_itr != NULL; bind_itr = bind_itr->ai_next) { - if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) { - ssh_set_error(session, SSH_FATAL, - "Binding local address: %s", strerror(errno)); - continue; - } else { - break; - } - } - freeaddrinfo(bind_ai); - - /* Cannot bind to any local addresses */ - if (bind_itr == NULL) { - ssh_connect_socket_close(s); - s = -1; - continue; - } - } - - if (timeout || usec) { - socket_t ret = ssh_connect_ai_timeout(session, host, port, itr, - timeout, usec, s); - leave_function(); - return ret; - } - - if (connect(s, itr->ai_addr, itr->ai_addrlen) < 0) { - ssh_set_error(session, SSH_FATAL, "Connect failed: %s", strerror(errno)); - ssh_connect_socket_close(s); - s = -1; - leave_function(); - continue; - } else { - /* We are connected */ - break; - } - } - - freeaddrinfo(ai); - leave_function(); - - return s; -} - -/** - * @internal - * - * @brief Launches a nonblocking connect to an IPv4 or IPv6 host - * specified by its IP address or hostname. - * - * @returns A file descriptor, < 0 on error. - * @warning very ugly !!! - */ -socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host, - const char *bind_addr, int port) { - socket_t s = -1; - int rc; - struct addrinfo *ai; - struct addrinfo *itr; - - enter_function(); - - rc = getai(session,host, port, &ai); - if (rc != 0) { - ssh_set_error(session, SSH_FATAL, - "Failed to resolve hostname %s (%s)", host, gai_strerror(rc)); - leave_function(); - return -1; - } - - for (itr = ai; itr != NULL; itr = itr->ai_next){ - /* create socket */ - s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol); - if (s < 0) { - ssh_set_error(session, SSH_FATAL, - "Socket create failed: %s", strerror(errno)); - continue; - } - - if (bind_addr) { - struct addrinfo *bind_ai; - struct addrinfo *bind_itr; - - ssh_log(session, SSH_LOG_PACKET, "Resolving %s\n", bind_addr); - - rc = getai(session,bind_addr, 0, &bind_ai); - if (rc != 0) { - ssh_set_error(session, SSH_FATAL, - "Failed to resolve bind address %s (%s)", - bind_addr, - gai_strerror(rc)); - close(s); - s=-1; - break; - } - - for (bind_itr = bind_ai; bind_itr != NULL; bind_itr = bind_itr->ai_next) { - if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) { - ssh_set_error(session, SSH_FATAL, - "Binding local address: %s", strerror(errno)); - continue; - } else { - break; - } - } - freeaddrinfo(bind_ai); - - /* Cannot bind to any local addresses */ - if (bind_itr == NULL) { - ssh_connect_socket_close(s); - s = -1; - continue; - } - } - ssh_sock_set_nonblocking(s); - - connect(s, itr->ai_addr, itr->ai_addrlen); - break; - } - - freeaddrinfo(ai); - leave_function(); - - return s; -} - -/** - * @addtogroup libssh_session - * - * @{ - */ - -/** - * @brief A wrapper for the select syscall - * - * This functions acts more or less like the select(2) syscall.\n - * There is no support for writing or exceptions.\n - * - * @param[in] channels Arrays of channels pointers terminated by a NULL. - * It is never rewritten. - * - * @param[out] outchannels Arrays of same size that "channels", there is no need - * to initialize it. - * - * @param[in] maxfd Maximum +1 file descriptor from readfds. - * - * @param[in] readfds A fd_set of file descriptors to be select'ed for - * reading. - * - * @param[in] timeout A timeout for the select. - * - * @return -1 if an error occured. E_INTR if it was interrupted, in - * that case, just restart it. - * - * @warning libssh is not threadsafe here. That means that if a signal is caught - * during the processing of this function, you cannot call ssh - * functions on sessions that are busy with ssh_select(). - * - * @see select(2) - */ -int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd, - fd_set *readfds, struct timeval *timeout) { - struct timeval zerotime; - fd_set localset, localset2; - socket_t f; - int rep; - int set; - int i; - int j; - - zerotime.tv_sec = 0; - zerotime.tv_usec = 0; - - /* - * First, poll the maxfd file descriptors from the user with a zero-second - * timeout. They have the bigger priority. - */ - if (maxfd > 0) { - memcpy(&localset, readfds, sizeof(fd_set)); - rep = select(maxfd, &localset, NULL, NULL, &zerotime); - /* catch the eventual errors */ - if (rep==-1) { - return -1; - } - } - - /* Poll every channel */ - j = 0; - for (i = 0; channels[i]; i++) { - if (channels[i]->session->alive) { - if(ssh_channel_poll(channels[i], 0) > 0) { - outchannels[j] = channels[i]; - j++; - } else { - if(ssh_channel_poll(channels[i], 1) > 0) { - outchannels[j] = channels[i]; - j++; - } - } - } - } - outchannels[j] = NULL; - - /* Look into the localset for active fd */ - set = 0; - for (f = 0; (f < maxfd) && !set; f++) { - if (FD_ISSET(f, &localset)) { - set = 1; - } - } - - /* j != 0 means a channel has data */ - if( (j != 0) || (set != 0)) { - if(maxfd > 0) { - memcpy(readfds, &localset, sizeof(fd_set)); - } - return 0; - } - - /* - * At this point, not any channel had any data ready for reading, nor any fd - * had data for reading. - */ - memcpy(&localset, readfds, sizeof(fd_set)); - for (i = 0; channels[i]; i++) { - if (channels[i]->session->alive) { - ssh_socket_fd_set(channels[i]->session->socket, &localset, &maxfd); - } - } - - rep = select(maxfd, &localset, NULL, NULL, timeout); - if (rep == -1 && errno == EINTR) { - /* Interrupted by a signal */ - return SSH_EINTR; - } - - if (rep == -1) { - /* - * Was the error due to a libssh's channel or from a closed descriptor from - * the user? User closed descriptors have been caught in the first select - * and not closed since that moment. That case shouldn't occur at all - */ - return -1; - } - - /* Set the data_to_read flag on each session */ - for (i = 0; channels[i]; i++) { - if (channels[i]->session->alive && - ssh_socket_fd_isset(channels[i]->session->socket,&localset)) { - ssh_socket_set_toread(channels[i]->session->socket); - } - } - - /* Now, test each channel */ - j = 0; - for (i = 0; channels[i]; i++) { - if (channels[i]->session->alive && - ssh_socket_fd_isset(channels[i]->session->socket,&localset)) { - if ((ssh_channel_poll(channels[i],0) > 0) || - (ssh_channel_poll(channels[i], 1) > 0)) { - outchannels[j] = channels[i]; - j++; - } - } - } - outchannels[j] = NULL; - - FD_ZERO(&localset2); - for (f = 0; f < maxfd; f++) { - if (FD_ISSET(f, readfds) && FD_ISSET(f, &localset)) { - FD_SET(f, &localset2); - } - } - - memcpy(readfds, &localset2, sizeof(fd_set)); - - return 0; -} - -/** @} */ - -/* vim: set ts=4 sw=4 et cindent: */ |