~ubuntu-branches/ubuntu/precise/libssh/precise

« back to all changes in this revision

Viewing changes to src/connect.c

  • Committer: Bazaar Package Importer
  • Author(s): Laurent Bigonville
  • Date: 2011-06-15 15:48:07 UTC
  • mfrom: (1.1.10 upstream) (4.1.12 sid)
  • Revision ID: james.westby@ubuntu.com-20110615154807-3muklcqfftr1vtch
Tags: 0.5.0-2
* debian/patches/0002-Check-for-NULL-pointers-in-string-c.patch:
  Consolidate patch (Should fix previous REJECT)
* Support multiarch spec

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * connect.c - handles connections to ssh servers
 
3
 *
 
4
 * This file is part of the SSH Library
 
5
 *
 
6
 * Copyright (c) 2003-2009 by Aris Adamantiadis
 
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
 
 
24
#include "config.h"
 
25
 
 
26
#include <errno.h>
 
27
#include <fcntl.h>
 
28
#include <stdio.h>
 
29
#include <stdlib.h>
 
30
#include <string.h>
 
31
 
 
32
#include "libssh/libssh.h"
 
33
#include "libssh/misc.h"
 
34
 
 
35
#ifdef _WIN32
 
36
/*
 
37
 * Only use Windows API functions available on Windows 2000 SP4 or later.
 
38
 * The available constants are in <sdkddkver.h>.
 
39
 *  http://msdn.microsoft.com/en-us/library/aa383745.aspx
 
40
 *  http://blogs.msdn.com/oldnewthing/archive/2007/04/11/2079137.aspx
 
41
 */
 
42
#undef _WIN32_WINNT
 
43
#ifdef HAVE_WSPIAPI_H
 
44
#define _WIN32_WINNT 0x0500 /* _WIN32_WINNT_WIN2K */
 
45
#undef NTDDI_VERSION
 
46
#define NTDDI_VERSION 0x05000400 /* NTDDI_WIN2KSP4 */
 
47
#else
 
48
#define _WIN32_WINNT 0x0501 /* _WIN32_WINNT_WINXP */
 
49
#undef NTDDI_VERSION
 
50
#define NTDDI_VERSION 0x05010000 /* NTDDI_WINXP */
 
51
#endif
 
52
 
 
53
#if _MSC_VER >= 1400
 
54
#include <io.h>
 
55
#undef close
 
56
#define close _close
 
57
#endif /* _MSC_VER */
 
58
#include <winsock2.h>
 
59
#include <ws2tcpip.h>
 
60
 
 
61
/* <wspiapi.h> is necessary for getaddrinfo before Windows XP, but it isn't
 
62
 * available on some platforms like MinGW. */
 
63
#ifdef HAVE_WSPIAPI_H
 
64
#include <wspiapi.h>
 
65
#endif
 
66
 
 
67
#else /* _WIN32 */
 
68
 
 
69
#include <netdb.h>
 
70
#include <sys/socket.h>
 
71
#include <sys/select.h>
 
72
#include <netinet/in.h>
 
73
 
 
74
#endif /* _WIN32 */
 
75
 
 
76
#include "libssh/priv.h"
 
77
#include "libssh/socket.h"
 
78
#include "libssh/channels.h"
 
79
#include "libssh/session.h"
 
80
#include "libssh/poll.h"
 
81
 
 
82
#ifndef HAVE_GETADDRINFO
 
83
#error "Your system must have getaddrinfo()"
 
84
#endif
 
85
 
 
86
#ifdef _WIN32
 
87
void ssh_sock_set_nonblocking(socket_t sock) {
 
88
  u_long nonblocking = 1;
 
89
  ioctlsocket(sock, FIONBIO, &nonblocking);
 
90
}
 
91
 
 
92
void ssh_sock_set_blocking(socket_t sock) {
 
93
  u_long nonblocking = 0;
 
94
  ioctlsocket(sock, FIONBIO, &nonblocking);
 
95
}
 
96
 
 
97
#ifndef gai_strerror
 
98
char WSAAPI *gai_strerrorA(int code) {
 
99
  static char buf[256];
 
100
 
 
101
  snprintf(buf, sizeof(buf), "Undetermined error code (%d)", code);
 
102
 
 
103
  return buf;
 
104
}
 
105
#endif /* gai_strerror */
 
106
 
 
107
#else /* _WIN32 */
 
108
void ssh_sock_set_nonblocking(socket_t sock) {
 
109
  fcntl(sock, F_SETFL, O_NONBLOCK);
 
110
}
 
111
 
 
112
void ssh_sock_set_blocking(socket_t sock) {
 
113
  fcntl(sock, F_SETFL, 0);
 
114
}
 
115
 
 
116
#endif /* _WIN32 */
 
117
 
 
118
static int ssh_connect_socket_close(socket_t s){
 
119
#ifdef _WIN32
 
120
  return closesocket(s);
 
121
#else
 
122
  return close(s);
 
123
#endif
 
124
}
 
125
 
 
126
 
 
127
static int getai(ssh_session session, const char *host, int port, struct addrinfo **ai) {
 
128
  const char *service = NULL;
 
129
  struct addrinfo hints;
 
130
  char s_port[10];
 
131
 
 
132
  ZERO_STRUCT(hints);
 
133
 
 
134
  hints.ai_protocol = IPPROTO_TCP;
 
135
  hints.ai_family = PF_UNSPEC;
 
136
  hints.ai_socktype = SOCK_STREAM;
 
137
 
 
138
  if (port == 0) {
 
139
    hints.ai_flags = AI_PASSIVE;
 
140
  } else {
 
141
    snprintf(s_port, sizeof(s_port), "%hu", (unsigned short)port);
 
142
    service = s_port;
 
143
#ifdef AI_NUMERICSERV
 
144
    hints.ai_flags=AI_NUMERICSERV;
 
145
#endif
 
146
  }
 
147
 
 
148
  if (ssh_is_ipaddr(host)) {
 
149
    /* this is an IP address */
 
150
    ssh_log(session,SSH_LOG_PACKET,"host %s matches an IP address",host);
 
151
    hints.ai_flags |= AI_NUMERICHOST;
 
152
  }
 
153
 
 
154
  return getaddrinfo(host, service, &hints, ai);
 
155
}
 
156
 
 
157
static int ssh_connect_ai_timeout(ssh_session session, const char *host,
 
158
    int port, struct addrinfo *ai, long timeout, long usec, socket_t s) {
 
159
  int timeout_ms;
 
160
  ssh_pollfd_t fds;
 
161
  int rc = 0;
 
162
  unsigned int len = sizeof(rc);
 
163
 
 
164
  enter_function();
 
165
 
 
166
  /* I know we're losing some precision. But it's not like poll-like family
 
167
   * type of mechanisms are precise up to the microsecond.
 
168
   */
 
169
  timeout_ms=timeout * 1000 + usec / 1000;
 
170
 
 
171
  ssh_sock_set_nonblocking(s);
 
172
 
 
173
  ssh_log(session, SSH_LOG_RARE, "Trying to connect to host: %s:%d with "
 
174
      "timeout %d ms", host, port, timeout_ms);
 
175
 
 
176
  /* The return value is checked later */
 
177
  connect(s, ai->ai_addr, ai->ai_addrlen);
 
178
  freeaddrinfo(ai);
 
179
 
 
180
  fds.fd=s;
 
181
  fds.revents=0;
 
182
  fds.events=POLLOUT;
 
183
#ifdef _WIN32
 
184
  fds.events |= POLLWRNORM;
 
185
#endif
 
186
  rc = ssh_poll(&fds,1,timeout_ms);
 
187
 
 
188
  if (rc == 0) {
 
189
    /* timeout */
 
190
    ssh_set_error(session, SSH_FATAL,
 
191
        "Timeout while connecting to %s:%d", host, port);
 
192
    ssh_connect_socket_close(s);
 
193
    leave_function();
 
194
    return -1;
 
195
  }
 
196
 
 
197
  if (rc < 0) {
 
198
    ssh_set_error(session, SSH_FATAL,
 
199
        "poll error: %s", strerror(errno));
 
200
    ssh_connect_socket_close(s);
 
201
    leave_function();
 
202
    return -1;
 
203
  }
 
204
  rc = 0;
 
205
 
 
206
  /* Get connect(2) return code. Zero means no error */
 
207
  getsockopt(s, SOL_SOCKET, SO_ERROR,(char *) &rc, &len);
 
208
  if (rc != 0) {
 
209
    ssh_set_error(session, SSH_FATAL,
 
210
        "Connect to %s:%d failed: %s", host, port, strerror(rc));
 
211
    ssh_connect_socket_close(s);
 
212
    leave_function();
 
213
    return -1;
 
214
  }
 
215
 
 
216
  /* s is connected ? */
 
217
  ssh_log(session, SSH_LOG_PACKET, "Socket connected with timeout\n");
 
218
  ssh_sock_set_blocking(s);
 
219
 
 
220
  leave_function();
 
221
  return s;
 
222
}
 
223
 
 
224
/**
 
225
 * @internal
 
226
 *
 
227
 * @brief Connect to an IPv4 or IPv6 host specified by its IP address or
 
228
 * hostname.
 
229
 *
 
230
 * @returns A file descriptor, < 0 on error.
 
231
 */
 
232
socket_t ssh_connect_host(ssh_session session, const char *host,
 
233
    const char *bind_addr, int port, long timeout, long usec) {
 
234
  socket_t s = -1;
 
235
  int rc;
 
236
  struct addrinfo *ai;
 
237
  struct addrinfo *itr;
 
238
 
 
239
  enter_function();
 
240
 
 
241
  rc = getai(session,host, port, &ai);
 
242
  if (rc != 0) {
 
243
    ssh_set_error(session, SSH_FATAL,
 
244
        "Failed to resolve hostname %s (%s)", host, gai_strerror(rc));
 
245
    leave_function();
 
246
    return -1;
 
247
  }
 
248
 
 
249
  for (itr = ai; itr != NULL; itr = itr->ai_next){
 
250
    /* create socket */
 
251
    s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
 
252
    if (s < 0) {
 
253
      ssh_set_error(session, SSH_FATAL,
 
254
          "Socket create failed: %s", strerror(errno));
 
255
      continue;
 
256
    }
 
257
 
 
258
    if (bind_addr) {
 
259
      struct addrinfo *bind_ai;
 
260
      struct addrinfo *bind_itr;
 
261
 
 
262
      ssh_log(session, SSH_LOG_PACKET, "Resolving %s\n", bind_addr);
 
263
 
 
264
      rc = getai(session,bind_addr, 0, &bind_ai);
 
265
      if (rc != 0) {
 
266
        ssh_set_error(session, SSH_FATAL,
 
267
            "Failed to resolve bind address %s (%s)",
 
268
            bind_addr,
 
269
            gai_strerror(rc));
 
270
        leave_function();
 
271
        return -1;
 
272
      }
 
273
 
 
274
      for (bind_itr = bind_ai; bind_itr != NULL; bind_itr = bind_itr->ai_next) {
 
275
        if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
 
276
          ssh_set_error(session, SSH_FATAL,
 
277
              "Binding local address: %s", strerror(errno));
 
278
          continue;
 
279
        } else {
 
280
          break;
 
281
        }
 
282
      }
 
283
      freeaddrinfo(bind_ai);
 
284
 
 
285
      /* Cannot bind to any local addresses */
 
286
      if (bind_itr == NULL) {
 
287
        ssh_connect_socket_close(s);
 
288
        s = -1;
 
289
        continue;
 
290
      }
 
291
    }
 
292
 
 
293
    if (timeout || usec) {
 
294
      socket_t ret = ssh_connect_ai_timeout(session, host, port, itr,
 
295
          timeout, usec, s);
 
296
      leave_function();
 
297
      return ret;
 
298
    }
 
299
 
 
300
    if (connect(s, itr->ai_addr, itr->ai_addrlen) < 0) {
 
301
      ssh_set_error(session, SSH_FATAL, "Connect failed: %s", strerror(errno));
 
302
      ssh_connect_socket_close(s);
 
303
      s = -1;
 
304
      leave_function();
 
305
      continue;
 
306
    } else {
 
307
      /* We are connected */
 
308
      break;
 
309
    }
 
310
  }
 
311
 
 
312
  freeaddrinfo(ai);
 
313
  leave_function();
 
314
 
 
315
  return s;
 
316
}
 
317
 
 
318
/**
 
319
 * @internal
 
320
 *
 
321
 * @brief Launches a nonblocking connect to an IPv4 or IPv6 host
 
322
 * specified by its IP address or hostname.
 
323
 *
 
324
 * @returns A file descriptor, < 0 on error.
 
325
 * @warning very ugly !!!
 
326
 */
 
327
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
 
328
    const char *bind_addr, int port) {
 
329
  socket_t s = -1;
 
330
  int rc;
 
331
  struct addrinfo *ai;
 
332
  struct addrinfo *itr;
 
333
 
 
334
  enter_function();
 
335
 
 
336
  rc = getai(session,host, port, &ai);
 
337
  if (rc != 0) {
 
338
    ssh_set_error(session, SSH_FATAL,
 
339
        "Failed to resolve hostname %s (%s)", host, gai_strerror(rc));
 
340
    leave_function();
 
341
    return -1;
 
342
  }
 
343
 
 
344
  for (itr = ai; itr != NULL; itr = itr->ai_next){
 
345
    /* create socket */
 
346
    s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
 
347
    if (s < 0) {
 
348
      ssh_set_error(session, SSH_FATAL,
 
349
          "Socket create failed: %s", strerror(errno));
 
350
      continue;
 
351
    }
 
352
 
 
353
    if (bind_addr) {
 
354
      struct addrinfo *bind_ai;
 
355
      struct addrinfo *bind_itr;
 
356
 
 
357
      ssh_log(session, SSH_LOG_PACKET, "Resolving %s\n", bind_addr);
 
358
 
 
359
      rc = getai(session,bind_addr, 0, &bind_ai);
 
360
      if (rc != 0) {
 
361
        ssh_set_error(session, SSH_FATAL,
 
362
            "Failed to resolve bind address %s (%s)",
 
363
            bind_addr,
 
364
            gai_strerror(rc));
 
365
        close(s);
 
366
        s=-1;
 
367
        break;
 
368
      }
 
369
 
 
370
      for (bind_itr = bind_ai; bind_itr != NULL; bind_itr = bind_itr->ai_next) {
 
371
        if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
 
372
          ssh_set_error(session, SSH_FATAL,
 
373
              "Binding local address: %s", strerror(errno));
 
374
          continue;
 
375
        } else {
 
376
          break;
 
377
        }
 
378
      }
 
379
      freeaddrinfo(bind_ai);
 
380
 
 
381
      /* Cannot bind to any local addresses */
 
382
      if (bind_itr == NULL) {
 
383
        ssh_connect_socket_close(s);
 
384
        s = -1;
 
385
        continue;
 
386
      }
 
387
    }
 
388
    ssh_sock_set_nonblocking(s);
 
389
 
 
390
    connect(s, itr->ai_addr, itr->ai_addrlen);
 
391
    break;
 
392
  }
 
393
 
 
394
  freeaddrinfo(ai);
 
395
  leave_function();
 
396
 
 
397
  return s;
 
398
}
 
399
 
 
400
/**
 
401
 * @addtogroup libssh_session
 
402
 *
 
403
 * @{
 
404
 */
 
405
 
 
406
/**
 
407
 * @brief A wrapper for the select syscall
 
408
 *
 
409
 * This functions acts more or less like the select(2) syscall.\n
 
410
 * There is no support for writing or exceptions.\n
 
411
 *
 
412
 * @param[in]  channels Arrays of channels pointers terminated by a NULL.
 
413
 *                      It is never rewritten.
 
414
 *
 
415
 * @param[out] outchannels Arrays of same size that "channels", there is no need
 
416
 *                         to initialize it.
 
417
 *
 
418
 * @param[in]  maxfd    Maximum +1 file descriptor from readfds.
 
419
 *
 
420
 * @param[in]  readfds  A fd_set of file descriptors to be select'ed for
 
421
 *                      reading.
 
422
 *
 
423
 * @param[in]  timeout  A timeout for the select.
 
424
 *
 
425
 * @return              -1 if an error occured. SSH_EINTR if it was interrupted, in
 
426
 *                      that case, just restart it.
 
427
 *
 
428
 * @warning libssh is not threadsafe here. That means that if a signal is caught
 
429
 *          during the processing of this function, you cannot call ssh
 
430
 *          functions on sessions that are busy with ssh_select().
 
431
 *
 
432
 * @see select(2)
 
433
 */
 
434
int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
 
435
    fd_set *readfds, struct timeval *timeout) {
 
436
  struct timeval zerotime;
 
437
  fd_set localset, localset2;
 
438
  socket_t f;
 
439
  int rep;
 
440
  int set;
 
441
  int i;
 
442
  int j;
 
443
 
 
444
  zerotime.tv_sec = 0;
 
445
  zerotime.tv_usec = 0;
 
446
 
 
447
  /*
 
448
   * First, poll the maxfd file descriptors from the user with a zero-second
 
449
   * timeout. They have the bigger priority.
 
450
   */
 
451
  if (maxfd > 0) {
 
452
    memcpy(&localset, readfds, sizeof(fd_set));
 
453
    rep = select(maxfd, &localset, NULL, NULL, &zerotime);
 
454
    /* catch the eventual errors */
 
455
    if (rep==-1) {
 
456
      return -1;
 
457
    }
 
458
  }
 
459
 
 
460
  /* Poll every channel */
 
461
  j = 0;
 
462
  for (i = 0; channels[i]; i++) {
 
463
    if (channels[i]->session->alive) {
 
464
      if(ssh_channel_poll(channels[i], 0) > 0) {
 
465
        outchannels[j] = channels[i];
 
466
        j++;
 
467
      } else {
 
468
        if(ssh_channel_poll(channels[i], 1) > 0) {
 
469
          outchannels[j] = channels[i];
 
470
          j++;
 
471
        }
 
472
      }
 
473
    }
 
474
  }
 
475
  outchannels[j] = NULL;
 
476
 
 
477
  /* Look into the localset for active fd */
 
478
  set = 0;
 
479
  for (f = 0; (f < maxfd) && !set; f++) {
 
480
    if (FD_ISSET(f, &localset)) {
 
481
      set = 1;
 
482
    }
 
483
  }
 
484
 
 
485
  /* j != 0 means a channel has data */
 
486
  if( (j != 0) || (set != 0)) {
 
487
    if(maxfd > 0) {
 
488
      memcpy(readfds, &localset, sizeof(fd_set));
 
489
    }
 
490
    return 0;
 
491
  }
 
492
 
 
493
  /*
 
494
   * At this point, not any channel had any data ready for reading, nor any fd
 
495
   * had data for reading.
 
496
   */
 
497
  memcpy(&localset, readfds, sizeof(fd_set));
 
498
  for (i = 0; channels[i]; i++) {
 
499
    if (channels[i]->session->alive) {
 
500
      ssh_socket_fd_set(channels[i]->session->socket, &localset, &maxfd);
 
501
    }
 
502
  }
 
503
 
 
504
  rep = select(maxfd, &localset, NULL, NULL, timeout);
 
505
  if (rep == -1 && errno == EINTR) {
 
506
    /* Interrupted by a signal */
 
507
    return SSH_EINTR;
 
508
  }
 
509
 
 
510
  if (rep == -1) {
 
511
    /*
 
512
     * Was the error due to a libssh's channel or from a closed descriptor from
 
513
     * the user? User closed descriptors have been caught in the first select
 
514
     * and not closed since that moment. That case shouldn't occur at all
 
515
     */
 
516
    return -1;
 
517
  }
 
518
 
 
519
  /* Set the data_to_read flag on each session */
 
520
  for (i = 0; channels[i]; i++) {
 
521
    if (channels[i]->session->alive &&
 
522
        ssh_socket_fd_isset(channels[i]->session->socket,&localset)) {
 
523
      ssh_socket_set_read_wontblock(channels[i]->session->socket);
 
524
    }
 
525
  }
 
526
 
 
527
  /* Now, test each channel */
 
528
  j = 0;
 
529
  for (i = 0; channels[i]; i++) {
 
530
    if (channels[i]->session->alive &&
 
531
        ssh_socket_fd_isset(channels[i]->session->socket,&localset)) {
 
532
      if ((ssh_channel_poll(channels[i],0) > 0) ||
 
533
          (ssh_channel_poll(channels[i], 1) > 0)) {
 
534
        outchannels[j] = channels[i];
 
535
        j++;
 
536
      }
 
537
    }
 
538
  }
 
539
  outchannels[j] = NULL;
 
540
 
 
541
  FD_ZERO(&localset2);
 
542
  for (f = 0; f < maxfd; f++) {
 
543
    if (FD_ISSET(f, readfds) && FD_ISSET(f, &localset)) {
 
544
      FD_SET(f, &localset2);
 
545
    }
 
546
  }
 
547
 
 
548
  memcpy(readfds, &localset2, sizeof(fd_set));
 
549
 
 
550
  return 0;
 
551
}
 
552
 
 
553
/** @} */
 
554
 
 
555
/* vim: set ts=4 sw=4 et cindent: */