1 /* connect.c */ 2 /* it handles connections to ssh servers */ 3 /* 4 Copyright 2003 Aris Adamantiadis 5 6 This file is part of the SSH Library 7 8 The SSH Library is free software; you can redistribute it and/or modify 9 it under the terms of the GNU Lesser General Public License as published by 10 the Free Software Foundation; either version 2.1 of the License, or (at your 11 option) any later version. 12 13 The SSH Library is distributed in the hope that it will be useful, but 14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 16 License for more details. 17 18 You should have received a copy of the GNU Lesser General Public License 19 along with the SSH Library; see the file COPYING. If not, write to 20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, 21 MA 02111-1307, USA. */ 22 23 #include "libssh/priv.h" 24 25 #ifdef HAVE_NETDB_H 26 #include <netdb.h> 27 #endif 28 #include <string.h> 29 #include <unistd.h> 30 #include <stdlib.h> 31 #include <errno.h> 32 #include <sys/types.h> 33 #ifdef HAVE_SYS_SOCKET_H 34 #include <sys/socket.h> 35 #endif 36 #ifdef HAVE_SYS_SELECT_H 37 #include <sys/select.h> 38 #endif 39 #include <sys/time.h> 40 #ifdef HAVE_NETINET_IN_H 41 #include <netinet/in.h> 42 #endif 43 #include <fcntl.h> 44 #ifdef HAVE_SYS_POLL_H 45 #include <sys/poll.h> 46 #endif 47 48 #define FIRST_CHANNEL 42 49 static void sock_set_nonblocking(int sock) { 50 #if defined(F_SETFL) && defined(O_NONBLOCK) 51 fcntl(sock,F_SETFL,O_NONBLOCK); 52 #endif 53 } 54 static void sock_set_blocking(int sock){ 55 #ifdef F_SETFL 56 fcntl(sock,F_SETFL,0); 57 #endif 58 } 59 60 int ssh_net_init(void) { 61 #ifdef __WIN32__ 62 static int called = 0; 63 WSADATA wsaData; 64 65 if (called) { 66 return(0); 67 } 68 69 if (WSAStartup(MAKEWORD(2, 0), &wsaData)!=0) { 70 return(-1); 71 } 72 if (wsaData.wVersion!=MAKEWORD(2, 0)) { 73 /* Cleanup Winsock stuff */ 74 WSACleanup(); 75 return(-1); 76 } 77 78 called = 1; 79 #endif 80 return(0); 81 } 82 83 /* connect_host connects to an IPv4 (or IPv6) host */ 84 /* specified by its IP address or hostname. */ 85 /* output is the file descriptor, <0 if failed. */ 86 87 int ssh_connect_host(const char *host, const char *bind_addr, int port,long timeout, long usec){ 88 struct sockaddr_in sa; 89 struct sockaddr_in bindsa; 90 struct hostent *hp=NULL; 91 static int count=0; /* for reentrencity */ 92 int s; 93 94 ssh_net_init(); 95 96 while(++count>1) 97 --count; 98 99 100 sa.sin_family = AF_INET; 101 102 #ifdef HAVE_INET_ATON 103 if (!inet_aton(host,&sa.sin_addr)) { 104 #else 105 #ifdef HAVE_INET_ADDR 106 if ( (sa.sin_addr.s_addr=inet_addr(host) )==-1) { 107 #else 108 { 109 #endif 110 #endif 111 hp = gethostbyname(host); 112 113 if(!hp) { 114 --count; 115 #ifdef HAVE_HSTRERROR 116 ssh_set_error(NULL,SSH_FATAL,"Failed to resolve hostname %s (%s)",host,hstrerror(h_errno)); 117 #else 118 ssh_set_error(NULL,SSH_FATAL,"Failed to resolve hostname %s (%s)",host,strerror(h_errno)); 119 #endif 120 return -1; 121 } 122 123 memcpy(&sa.sin_addr.s_addr,hp->h_addr_list[0],hp->h_length); 124 sa.sin_family=hp->h_addrtype; 125 } 126 sa.sin_port=htons((unsigned short)port); 127 --count; 128 129 if(bind_addr){ 130 ssh_say(2,"resolving %s\n",bind_addr); 131 hp=NULL; 132 while(++count>1) 133 --count; 134 #ifdef HAVE_GETHOSTBYADDR 135 hp=gethostbyaddr(bind_addr,4,AF_INET); 136 #endif 137 #ifdef HAVE_GETHOSTBYNAME 138 if(!hp) 139 hp=gethostbyname(bind_addr); 140 #endif 141 if(!hp){ 142 --count; 143 #ifdef HAVE_HSTRERROR 144 ssh_set_error(NULL,SSH_FATAL,"Failed to resolve bind address %s (%s)",bind_addr,hstrerror(h_errno)); 145 #else 146 ssh_set_error(NULL,SSH_FATAL,"Failed to resolve bind address %s (%s)",bind_addr,strerror(h_errno)); 147 #endif 148 return -1; 149 } 150 } 151 memset(&bindsa,0,sizeof(bindsa)); 152 /* create socket */ 153 s=socket(sa.sin_family,SOCK_STREAM,0); 154 if(s<0){ 155 if(bind_addr) 156 --count; 157 ssh_set_error(NULL,SSH_FATAL,"socket : %s",strerror(errno)); 158 return s; 159 } 160 161 if(bind_addr){ 162 memcpy(&bindsa.sin_addr,hp->h_addr,hp->h_length); 163 bindsa.sin_family=hp->h_addrtype; 164 --count; 165 if(bind(s,(struct sockaddr *)&bindsa,sizeof(bindsa))<0){ 166 ssh_set_error(NULL,SSH_FATAL,"Binding local address : %s",strerror(errno)); 167 close(s); 168 return -1; 169 } 170 } 171 if(timeout){ 172 struct timeval to; 173 fd_set set; 174 int ret=0; 175 int len=sizeof(ret); 176 to.tv_sec=timeout; 177 to.tv_usec=usec; 178 sock_set_nonblocking(s); 179 connect(s,(struct sockaddr* )&sa,sizeof(sa)); 180 FD_ZERO(&set); 181 FD_SET(s,&set); 182 ret=select(s+1,NULL,&set,NULL,&to); 183 if(ret==0){ 184 /* timeout */ 185 ssh_set_error(NULL,SSH_FATAL,"Timeout while connecting to %s:%d",host,port); 186 close(s); 187 return -1; 188 } 189 if(ret<0){ 190 ssh_set_error(NULL,SSH_FATAL,"Select error : %s",strerror(errno)); 191 close(s); 192 return -1; 193 } 194 /* get connect(2) return code. zero means no error */ 195 getsockopt(s,SOL_SOCKET,SO_ERROR,&ret,&len); 196 if (ret!=0){ 197 ssh_set_error(NULL,SSH_FATAL,"Connecting : %s",strerror(ret)); 198 close(s); 199 return -1; 200 } 201 /* s is connected ? */ 202 ssh_say(3,"socket connected with timeout\n"); 203 sock_set_blocking(s); 204 return s; 205 } 206 if(connect(s,(struct sockaddr *)&sa,sizeof(sa))< 0){ 207 close(s); 208 ssh_set_error(NULL,SSH_FATAL,"connect: %s",strerror(errno)); 209 return -1; 210 } 211 return s; 212 } 213 214 /* connection_new() returns a newly allocated SSH_SESSION structure pointer */ 215 SSH_SESSION *ssh_session_new() { 216 SSH_SESSION *conn=malloc(sizeof (SSH_SESSION)); 217 memset(conn,0,sizeof(SSH_SESSION)); 218 conn->next_crypto=crypto_new(); 219 conn->maxchannel=FIRST_CHANNEL; 220 return conn; 221 } 222 223 224 /* returns 1 if bytes are available on the stream, 0 instead */ 225 int ssh_fd_poll(SSH_SESSION *session){ 226 #ifdef HAVE_POLL 227 struct pollfd fdset; 228 #else 229 struct timeval sometime; 230 fd_set descriptor; 231 #endif 232 if(session->datatoread) 233 return(session->datatoread); 234 #ifdef HAVE_POLL 235 fdset.fd=session->fd; 236 fdset.events=POLLHUP|POLLIN|POLLPRI; 237 fdset.revents=0; 238 if(poll(&fdset,1,0)==0) 239 return 0; 240 if(fdset.revents & (POLLHUP|POLLIN|POLLPRI)) 241 return (session->datatoread=1); 242 return 0; 243 #elif defined(HAVE_SELECT) 244 245 /* Set to return immediately (no blocking) */ 246 sometime.tv_sec = 0; 247 sometime.tv_usec = 0; 248 249 /* Set up descriptor */ 250 FD_ZERO(&descriptor); 251 FD_SET(session->fd, &descriptor); 252 253 /* Make the call, and listen for errors */ 254 if (select(session->fd + 1, &descriptor, NULL, NULL, &sometime) < 0) { 255 ssh_set_error(NULL,SSH_FATAL, "select: %s", strerror(errno)); 256 return -1; 257 } 258 session->datatoread=FD_ISSET(session->fd,&descriptor); 259 return session->datatoread; 260 #else 261 #error This system does not have poll() or select(), so ssh_fd_poll() will not work correctly 262 return 0; 263 #endif 264 } 265 266 /* this function is a complete wrapper for the select syscall. it does more than wrapping ... */ 267 int ssh_select(CHANNEL **channels, CHANNEL **outchannels, int maxfd, fd_set *readfds, struct timeval *timeout){ 268 struct timeval zerotime; 269 fd_set localset, localset2; 270 int rep = 0; 271 int i, j; 272 int set; 273 int getc_ret; 274 275 zerotime.tv_sec = 0; 276 zerotime.tv_usec = 1; 277 278 /* first, poll the maxfd file descriptors from the user with a zero-second timeout. they have the bigger priority */ 279 if (maxfd > 0) { 280 memcpy(&localset, readfds, sizeof(*readfds)); 281 rep = select(maxfd, &localset, NULL, NULL, &zerotime); 282 // catch the eventual errors 283 if (rep == -1) { 284 FD_ZERO(&localset); 285 if (FD_ISSET(fileno(stdin), readfds)) { 286 getc_ret = getc(stdin); 287 if (getc_ret != EOF) { 288 ungetc(getc_ret, stdin); 289 FD_SET(fileno(stdin), &localset); 290 } 291 } 292 } 293 } 294 295 /* polls every channel. */ 296 j = 0; 297 for (i = 0; channels[i]; i++) { 298 if (channel_poll(channels[i], 0) > 0) { 299 outchannels[j] = channels[i]; 300 j++; 301 } else if (channel_poll(channels[i], 1) > 0) { 302 outchannels[j] = channels[i]; 303 j++; 304 } 305 } 306 outchannels[j] = NULL; 307 308 /* look into the localset for active fd */ 309 set = 0; 310 for (i = 0; i < maxfd; i++) { 311 if (FD_ISSET(i, &localset)) { 312 set = 1; 313 break; 314 } 315 } 316 317 /* j!=0 means a channel has data */ 318 if ((j != 0) || (set != 0)) { 319 if (maxfd > 0) { 320 memcpy(readfds, &localset, sizeof(fd_set)); 321 } 322 return 0; 323 } 324 325 /* at this point, not any channel had any data ready for reading, nor any fd had data for reading */ 326 memcpy(&localset, readfds, sizeof(fd_set)); 327 for (i = 0; channels[i]; i++) { 328 if (channels[i]->session->alive) { 329 FD_SET(channels[i]->session->fd, &localset); 330 if (channels[i]->session->fd > (maxfd - 1)) { 331 maxfd = channels[i]->session->fd + 1; 332 } 333 } 334 } 335 336 rep = select(maxfd, &localset, NULL, NULL, timeout); 337 if (rep == -1 && errno == EINTR) { 338 return SSH_EINTR; /* interrupted by a signal */ 339 } 340 341 if (rep == -1) { 342 /* was the error due to a libssh's Channel or from a closed descriptor from the user ? user closed descriptors have been 343 caught in the first select and not closed since that moment. that case shouldn't occur at all */ 344 FD_ZERO(&localset); 345 if (FD_ISSET(fileno(stdin), readfds)) { 346 getc_ret = getc(stdin); 347 if (getc_ret != EOF) { 348 ungetc(getc_ret, stdin); 349 FD_SET(fileno(stdin), &localset); 350 } 351 } 352 } 353 354 /* set the data_to_read flag on each session */ 355 for (i = 0; channels[i]; i++) { 356 if (FD_ISSET(channels[i]->session->fd, &localset)) { 357 channels[i]->session->datatoread = 1; 358 } 359 } 360 361 /* now, test each channel */ 362 j = 0; 363 for (i = 0; channels[i]; i++) { 364 if (FD_ISSET(channels[i]->session->fd, &localset)) { 365 if ((channel_poll(channels[i], 0) > 0) || (channel_poll(channels[i], 1) > 0)) { 366 outchannels[j] = channels[i]; 367 j++; 368 } 369 } 370 } 371 372 outchannels[j] = NULL; 373 FD_ZERO(&localset2); 374 for (i = 0; i < maxfd; i++) { 375 if (FD_ISSET(i, readfds) && FD_ISSET(i, &localset)) { 376 FD_SET(i, &localset2); 377 } 378 } 379 380 memcpy(readfds, &localset2, sizeof(fd_set)); 381 return 0; 382 } |