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

« back to all changes in this revision

Viewing changes to libssh/client.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
 
 * client.c - SSH client functions
3
 
 *
4
 
 * This file is part of the SSH Library
5
 
 *
6
 
 * Copyright (c) 2003-2008 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 <stdio.h>
25
 
#include <stdlib.h>
26
 
#include <string.h>
27
 
 
28
 
#ifndef _WIN32
29
 
#include <arpa/inet.h>
30
 
#endif
31
 
 
32
 
#include "libssh/priv.h"
33
 
#include "libssh/ssh2.h"
34
 
#include "libssh/buffer.h"
35
 
#include "libssh/packet.h"
36
 
#include "libssh/socket.h"
37
 
#include "libssh/session.h"
38
 
#include "libssh/dh.h"
39
 
 
40
 
#define set_status(session, status) do {\
41
 
        if (session->callbacks && session->callbacks->connect_status_function) \
42
 
            session->callbacks->connect_status_function(session->callbacks->userdata, status); \
43
 
    } while (0)
44
 
 
45
 
/**
46
 
 * @internal
47
 
 *
48
 
 * @brief Get a banner from a socket.
49
 
 *
50
 
 * The caller has to free memroy.
51
 
 *
52
 
 * @param  session      The session to get the banner from.
53
 
 *
54
 
 * @return A newly allocated string with the banner or NULL on error.
55
 
 */
56
 
char *ssh_get_banner(ssh_session session) {
57
 
  char buffer[128] = {0};
58
 
  char *str = NULL;
59
 
  int i;
60
 
 
61
 
  enter_function();
62
 
 
63
 
  for (i = 0; i < 127; i++) {
64
 
    if (ssh_socket_read(session->socket, &buffer[i], 1) != SSH_OK) {
65
 
      ssh_set_error(session, SSH_FATAL, "Remote host closed connection");
66
 
      leave_function();
67
 
      return NULL;
68
 
    }
69
 
#ifdef WITH_PCAP
70
 
    if(session->pcap_ctx && buffer[i] == '\n'){
71
 
        ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_IN,buffer,i+1,i+1);
72
 
    }
73
 
#endif
74
 
    if (buffer[i] == '\r') {
75
 
      buffer[i] = '\0';
76
 
    }
77
 
    if (buffer[i] == '\n') {
78
 
      buffer[i] = '\0';
79
 
      str = strdup(buffer);
80
 
      if (str == NULL) {
81
 
        leave_function();
82
 
        return NULL;
83
 
      }
84
 
      leave_function();
85
 
      return str;
86
 
    }
87
 
  }
88
 
 
89
 
  ssh_set_error(session, SSH_FATAL, "Too large banner");
90
 
 
91
 
  leave_function();
92
 
  return NULL;
93
 
}
94
 
 
95
 
/**
96
 
 * @internal
97
 
 *
98
 
 * @brief Analyze the SSH banner to find out if we have a SSHv1 or SSHv2
99
 
 * server.
100
 
 *
101
 
 * @param  session      The session to analyze the banner from.
102
 
 * @param  ssh1         The variable which is set if it is a SSHv1 server.
103
 
 * @param  ssh2         The variable which is set if it is a SSHv2 server.
104
 
 *
105
 
 * @return 0 on success, < 0 on error.
106
 
 *
107
 
 * @see ssh_get_banner()
108
 
 */
109
 
static int ssh_analyze_banner(ssh_session session, int *ssh1, int *ssh2) {
110
 
  const char *banner = session->serverbanner;
111
 
  const char *openssh;
112
 
 
113
 
  if (banner == NULL) {
114
 
      ssh_set_error(session, SSH_FATAL, "Invalid banner");
115
 
      return -1;
116
 
  }
117
 
 
118
 
  /*
119
 
   * Typical banners e.g. are:
120
 
   *
121
 
   * SSH-1.5-openSSH_5.4
122
 
   * SSH-1.99-openSSH_3.0
123
 
   *
124
 
   * SSH-2.0-something
125
 
   * 012345678901234567890
126
 
   */
127
 
  if (strlen(banner) < 6 ||
128
 
      strncmp(banner, "SSH-", 4) != 0) {
129
 
    ssh_set_error(session, SSH_FATAL, "Protocol mismatch: %s", banner);
130
 
    return -1;
131
 
  }
132
 
 
133
 
  ssh_log(session, SSH_LOG_RARE, "Analyzing banner: %s", banner);
134
 
 
135
 
  switch(banner[4]) {
136
 
    case '1':
137
 
      *ssh1 = 1;
138
 
      if (strlen(banner) > 6) {
139
 
          if (banner[6] == '9') {
140
 
            *ssh2 = 1;
141
 
          } else {
142
 
            *ssh2 = 0;
143
 
          }
144
 
      }
145
 
      break;
146
 
    case '2':
147
 
      *ssh1 = 0;
148
 
      *ssh2 = 1;
149
 
      break;
150
 
    default:
151
 
      ssh_set_error(session, SSH_FATAL, "Protocol mismatch: %s", banner);
152
 
      return -1;
153
 
  }
154
 
 
155
 
  openssh = strstr(banner, "OpenSSH");
156
 
  if (openssh != NULL) {
157
 
      int major, minor;
158
 
 
159
 
      /*
160
 
       * The banner is typical:
161
 
       * OpenSSH_5.4
162
 
       * 012345678901234567890
163
 
       */
164
 
      if (strlen(openssh) > 9) {
165
 
          major = strtol(openssh + 8, (char **) NULL, 10);
166
 
          minor = strtol(openssh + 10, (char **) NULL, 10);
167
 
          session->openssh = SSH_VERSION_INT(major, minor, 0);
168
 
          ssh_log(session, SSH_LOG_RARE,
169
 
                  "We are talking to an OpenSSH client version: %d.%d (%x)",
170
 
                  major, minor, session->openssh);
171
 
      }
172
 
  }
173
 
 
174
 
  return 0;
175
 
}
176
 
 
177
 
/** @internal
178
 
 * @brief Sends a SSH banner to the server.
179
 
 *
180
 
 * @param session      The SSH session to use.
181
 
 *
182
 
 * @param server       Send client or server banner.
183
 
 *
184
 
 * @return 0 on success, < 0 on error.
185
 
 */
186
 
int ssh_send_banner(ssh_session session, int server) {
187
 
  const char *banner = NULL;
188
 
  char buffer[128] = {0};
189
 
 
190
 
  enter_function();
191
 
 
192
 
  banner = session->version == 1 ? CLIENTBANNER1 : CLIENTBANNER2;
193
 
 
194
 
  if (session->xbanner) {
195
 
    banner = session->xbanner;
196
 
  }
197
 
 
198
 
  if (server) {
199
 
    session->serverbanner = strdup(banner);
200
 
    if (session->serverbanner == NULL) {
201
 
      leave_function();
202
 
      return -1;
203
 
    }
204
 
  } else {
205
 
    session->clientbanner = strdup(banner);
206
 
    if (session->clientbanner == NULL) {
207
 
      leave_function();
208
 
      return -1;
209
 
    }
210
 
  }
211
 
 
212
 
  snprintf(buffer, 128, "%s\r\n", banner);
213
 
 
214
 
  if (ssh_socket_write(session->socket, buffer, strlen(buffer)) == SSH_ERROR) {
215
 
    leave_function();
216
 
    return -1;
217
 
  }
218
 
 
219
 
  if (ssh_socket_blocking_flush(session->socket) != SSH_OK) {
220
 
    leave_function();
221
 
    return -1;
222
 
  }
223
 
#ifdef WITH_PCAP
224
 
  if(session->pcap_ctx)
225
 
        ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,buffer,strlen(buffer),strlen(buffer));
226
 
#endif
227
 
  leave_function();
228
 
  return 0;
229
 
}
230
 
 
231
 
#define DH_STATE_INIT 0
232
 
#define DH_STATE_INIT_TO_SEND 1
233
 
#define DH_STATE_INIT_SENT 2
234
 
#define DH_STATE_NEWKEYS_TO_SEND 3
235
 
#define DH_STATE_NEWKEYS_SENT 4
236
 
#define DH_STATE_FINISHED 5
237
 
static int dh_handshake(ssh_session session) {
238
 
  ssh_string e = NULL;
239
 
  ssh_string f = NULL;
240
 
  ssh_string pubkey = NULL;
241
 
  ssh_string signature = NULL;
242
 
  int rc = SSH_ERROR;
243
 
 
244
 
  enter_function();
245
 
 
246
 
  switch (session->dh_handshake_state) {
247
 
    case DH_STATE_INIT:
248
 
      if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_INIT) < 0) {
249
 
        goto error;
250
 
      }
251
 
 
252
 
      if (dh_generate_x(session) < 0) {
253
 
        goto error;
254
 
      }
255
 
      if (dh_generate_e(session) < 0) {
256
 
        goto error;
257
 
      }
258
 
 
259
 
      e = dh_get_e(session);
260
 
      if (e == NULL) {
261
 
        goto error;
262
 
      }
263
 
 
264
 
      if (buffer_add_ssh_string(session->out_buffer, e) < 0) {
265
 
        goto error;
266
 
      }
267
 
      string_burn(e);
268
 
      string_free(e);
269
 
      e=NULL;
270
 
 
271
 
      rc = packet_send(session);
272
 
      if (rc == SSH_ERROR) {
273
 
        goto error;
274
 
      }
275
 
 
276
 
      session->dh_handshake_state = DH_STATE_INIT_TO_SEND;
277
 
    case DH_STATE_INIT_TO_SEND:
278
 
      rc = packet_flush(session, 0);
279
 
      if (rc != SSH_OK) {
280
 
        goto error;
281
 
      }
282
 
      session->dh_handshake_state = DH_STATE_INIT_SENT;
283
 
    case DH_STATE_INIT_SENT:
284
 
      rc = packet_wait(session, SSH2_MSG_KEXDH_REPLY, 1);
285
 
      if (rc != SSH_OK) {
286
 
        goto error;
287
 
      }
288
 
 
289
 
      pubkey = buffer_get_ssh_string(session->in_buffer);
290
 
      if (pubkey == NULL){
291
 
        ssh_set_error(session,SSH_FATAL, "No public key in packet");
292
 
        rc = SSH_ERROR;
293
 
        goto error;
294
 
      }
295
 
      dh_import_pubkey(session, pubkey);
296
 
 
297
 
      f = buffer_get_ssh_string(session->in_buffer);
298
 
      if (f == NULL) {
299
 
        ssh_set_error(session,SSH_FATAL, "No F number in packet");
300
 
        rc = SSH_ERROR;
301
 
        goto error;
302
 
      }
303
 
      if (dh_import_f(session, f) < 0) {
304
 
        ssh_set_error(session, SSH_FATAL, "Cannot import f number");
305
 
        rc = SSH_ERROR;
306
 
        goto error;
307
 
      }
308
 
      string_burn(f);
309
 
      string_free(f);
310
 
      f=NULL;
311
 
      signature = buffer_get_ssh_string(session->in_buffer);
312
 
      if (signature == NULL) {
313
 
        ssh_set_error(session, SSH_FATAL, "No signature in packet");
314
 
        rc = SSH_ERROR;
315
 
        goto error;
316
 
      }
317
 
      session->dh_server_signature = signature;
318
 
      signature=NULL; /* ownership changed */
319
 
      if (dh_build_k(session) < 0) {
320
 
        ssh_set_error(session, SSH_FATAL, "Cannot build k number");
321
 
        rc = SSH_ERROR;
322
 
        goto error;
323
 
      }
324
 
 
325
 
      /* Send the MSG_NEWKEYS */
326
 
      if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
327
 
        rc = SSH_ERROR;
328
 
        goto error;
329
 
      }
330
 
 
331
 
      rc = packet_send(session);
332
 
      if (rc == SSH_ERROR) {
333
 
        goto error;
334
 
      }
335
 
 
336
 
      session->dh_handshake_state = DH_STATE_NEWKEYS_TO_SEND;
337
 
    case DH_STATE_NEWKEYS_TO_SEND:
338
 
      rc = packet_flush(session, 0);
339
 
      if (rc != SSH_OK) {
340
 
        goto error;
341
 
      }
342
 
      ssh_log(session, SSH_LOG_RARE, "SSH_MSG_NEWKEYS sent\n");
343
 
 
344
 
      session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
345
 
    case DH_STATE_NEWKEYS_SENT:
346
 
      rc = packet_wait(session, SSH2_MSG_NEWKEYS, 1);
347
 
      if (rc != SSH_OK) {
348
 
        goto error;
349
 
      }
350
 
      ssh_log(session, SSH_LOG_RARE, "Got SSH_MSG_NEWKEYS\n");
351
 
 
352
 
      rc = make_sessionid(session);
353
 
      if (rc != SSH_OK) {
354
 
        goto error;
355
 
      }
356
 
 
357
 
      /*
358
 
       * Set the cryptographic functions for the next crypto
359
 
       * (it is needed for generate_session_keys for key lenghts)
360
 
       */
361
 
      if (crypt_set_algorithms(session)) {
362
 
        rc = SSH_ERROR;
363
 
        goto error;
364
 
      }
365
 
 
366
 
      if (generate_session_keys(session) < 0) {
367
 
        rc = SSH_ERROR;
368
 
        goto error;
369
 
      }
370
 
 
371
 
      /* Verify the host's signature. FIXME do it sooner */
372
 
      signature = session->dh_server_signature;
373
 
      session->dh_server_signature = NULL;
374
 
      if (signature_verify(session, signature)) {
375
 
        rc = SSH_ERROR;
376
 
        goto error;
377
 
      }
378
 
 
379
 
      /* forget it for now ... */
380
 
      string_burn(signature);
381
 
      string_free(signature);
382
 
      signature=NULL;
383
 
      /*
384
 
       * Once we got SSH2_MSG_NEWKEYS we can switch next_crypto and
385
 
       * current_crypto
386
 
       */
387
 
      if (session->current_crypto) {
388
 
        crypto_free(session->current_crypto);
389
 
        session->current_crypto=NULL;
390
 
      }
391
 
 
392
 
      /* FIXME later, include a function to change keys */
393
 
      session->current_crypto = session->next_crypto;
394
 
 
395
 
      session->next_crypto = crypto_new();
396
 
      if (session->next_crypto == NULL) {
397
 
        rc = SSH_ERROR;
398
 
        goto error;
399
 
      }
400
 
 
401
 
      session->dh_handshake_state = DH_STATE_FINISHED;
402
 
 
403
 
      leave_function();
404
 
      return SSH_OK;
405
 
    default:
406
 
      ssh_set_error(session, SSH_FATAL, "Invalid state in dh_handshake(): %d",
407
 
          session->dh_handshake_state);
408
 
 
409
 
      leave_function();
410
 
      return SSH_ERROR;
411
 
  }
412
 
 
413
 
  /* not reached */
414
 
error:
415
 
  if(e != NULL){
416
 
    string_burn(e);
417
 
    string_free(e);
418
 
  }
419
 
  if(f != NULL){
420
 
    string_burn(f);
421
 
    string_free(f);
422
 
  }
423
 
  if(signature != NULL){
424
 
    string_burn(signature);
425
 
    string_free(signature);
426
 
  }
427
 
 
428
 
  leave_function();
429
 
  return rc;
430
 
}
431
 
 
432
 
/**
433
 
 * @internal
434
 
 *
435
 
 * @brief Request a service from the SSH server.
436
 
 *
437
 
 * Service requests are for example: ssh-userauth, ssh-connection, etc.
438
 
 *
439
 
 * @param  session      The session to use to ask for a service request.
440
 
 * @param  service      The service request.
441
 
 *
442
 
 * @return 0 on success, < 0 on error.
443
 
 */
444
 
int ssh_service_request(ssh_session session, const char *service) {
445
 
  ssh_string service_s = NULL;
446
 
 
447
 
  enter_function();
448
 
 
449
 
  if (buffer_add_u8(session->out_buffer, SSH2_MSG_SERVICE_REQUEST) < 0) {
450
 
    leave_function();
451
 
    return -1;
452
 
  }
453
 
 
454
 
  service_s = string_from_char(service);
455
 
  if (service_s == NULL) {
456
 
    leave_function();
457
 
    return -1;
458
 
  }
459
 
 
460
 
  if (buffer_add_ssh_string(session->out_buffer,service_s) < 0) {
461
 
    string_free(service_s);
462
 
    leave_function();
463
 
    return -1;
464
 
  }
465
 
  string_free(service_s);
466
 
 
467
 
  if (packet_send(session) != SSH_OK) {
468
 
    ssh_set_error(session, SSH_FATAL,
469
 
        "Sending SSH2_MSG_SERVICE_REQUEST failed.");
470
 
    leave_function();
471
 
    return -1;
472
 
  }
473
 
 
474
 
  ssh_log(session, SSH_LOG_PACKET,
475
 
      "Sent SSH_MSG_SERVICE_REQUEST (service %s)", service);
476
 
 
477
 
  if (packet_wait(session,SSH2_MSG_SERVICE_ACCEPT,1) != SSH_OK) {
478
 
    ssh_set_error(session, SSH_FATAL, "Did not receive SERVICE_ACCEPT");
479
 
    leave_function();
480
 
    return -1;
481
 
  }
482
 
 
483
 
  ssh_log(session, SSH_LOG_PACKET,
484
 
      "Received SSH_MSG_SERVICE_ACCEPT (service %s)", service);
485
 
 
486
 
  leave_function();
487
 
  return 0;
488
 
}
489
 
 
490
 
/** \addtogroup ssh_session
491
 
 * @{
492
 
 */
493
 
 
494
 
/** \brief connect to the ssh server
495
 
 * \param session ssh session
496
 
 * \return SSH_OK on success, SSH_ERROR on error
497
 
 * \see ssh_new()
498
 
 * \see ssh_disconnect()
499
 
 */
500
 
int ssh_connect(ssh_session session) {
501
 
  int ssh1 = 0;
502
 
  int ssh2 = 0;
503
 
  socket_t fd = SSH_INVALID_SOCKET;
504
 
  int ret;
505
 
 
506
 
  if (session == NULL) {
507
 
    ssh_set_error(session, SSH_FATAL, "Invalid session pointer");
508
 
    return SSH_ERROR;
509
 
  }
510
 
 
511
 
  enter_function();
512
 
 
513
 
  session->alive = 0;
514
 
  session->client = 1;
515
 
 
516
 
  if (ssh_init() < 0) {
517
 
    leave_function();
518
 
    return SSH_ERROR;
519
 
  }
520
 
  if (session->fd == SSH_INVALID_SOCKET && session->host == NULL &&
521
 
      session->ProxyCommand == NULL) {
522
 
    ssh_set_error(session, SSH_FATAL, "Hostname required");
523
 
    leave_function();
524
 
    return SSH_ERROR;
525
 
  }
526
 
 
527
 
  ret = ssh_options_apply(session);
528
 
  if (ret < 0) {
529
 
      ssh_set_error(session, SSH_FATAL, "Couldn't apply options");
530
 
      leave_function();
531
 
      return SSH_ERROR;
532
 
  }
533
 
 
534
 
  if (session->fd != SSH_INVALID_SOCKET) {
535
 
    fd = session->fd;
536
 
#ifndef _WIN32
537
 
  } else if (session->ProxyCommand != NULL) {
538
 
    fd=ssh_socket_connect_proxycommand(session, session->ProxyCommand);
539
 
#endif
540
 
  } else {
541
 
    fd = ssh_connect_host(session, session->host, session->bindaddr,
542
 
        session->port, session->timeout, session->timeout_usec);
543
 
  }
544
 
  if (fd == SSH_INVALID_SOCKET) {
545
 
    leave_function();
546
 
    return SSH_ERROR;
547
 
  }
548
 
  set_status(session, 0.2);
549
 
 
550
 
  ssh_socket_set_fd(session->socket, fd);
551
 
 
552
 
  session->alive = 1;
553
 
  session->serverbanner = ssh_get_banner(session);
554
 
  if (session->serverbanner == NULL) {
555
 
    ssh_socket_close(session->socket);
556
 
    session->alive = 0;
557
 
    leave_function();
558
 
    return SSH_ERROR;
559
 
  }
560
 
  set_status(session, 0.4);
561
 
 
562
 
  ssh_log(session, SSH_LOG_RARE,
563
 
      "SSH server banner: %s", session->serverbanner);
564
 
 
565
 
  /* Here we analyse the different protocols the server allows. */
566
 
  if (ssh_analyze_banner(session, &ssh1, &ssh2) < 0) {
567
 
    ssh_socket_close(session->socket);
568
 
    session->alive = 0;
569
 
    leave_function();
570
 
    return SSH_ERROR;
571
 
  }
572
 
 
573
 
  /* Here we decide which version of the protocol to use. */
574
 
  if (ssh2 && session->ssh2) {
575
 
    session->version = 2;
576
 
  } else if(ssh1 && session->ssh1) {
577
 
    session->version = 1;
578
 
  } else {
579
 
    ssh_set_error(session, SSH_FATAL,
580
 
        "No version of SSH protocol usable (banner: %s)",
581
 
        session->serverbanner);
582
 
    ssh_socket_close(session->socket);
583
 
    session->alive = 0;
584
 
    leave_function();
585
 
    return SSH_ERROR;
586
 
  }
587
 
 
588
 
  if (ssh_send_banner(session, 0) < 0) {
589
 
    ssh_set_error(session, SSH_FATAL, "Sending the banner failed");
590
 
    ssh_socket_close(session->socket);
591
 
    session->alive = 0;
592
 
    leave_function();
593
 
    return SSH_ERROR;
594
 
  }
595
 
  set_status(session, 0.5);
596
 
 
597
 
  switch (session->version) {
598
 
    case 2:
599
 
      if (ssh_get_kex(session,0) < 0) {
600
 
        ssh_socket_close(session->socket);
601
 
        session->alive = 0;
602
 
        leave_function();
603
 
        return SSH_ERROR;
604
 
      }
605
 
      set_status(session,0.6);
606
 
 
607
 
      ssh_list_kex(session, &session->server_kex);
608
 
      if (set_kex(session) < 0) {
609
 
        ssh_socket_close(session->socket);
610
 
        session->alive = 0;
611
 
        leave_function();
612
 
        return SSH_ERROR;
613
 
      }
614
 
      if (ssh_send_kex(session, 0) < 0) {
615
 
        ssh_socket_close(session->socket);
616
 
        session->alive = 0;
617
 
        leave_function();
618
 
        return SSH_ERROR;
619
 
      }
620
 
      set_status(session,0.8);
621
 
 
622
 
      if (dh_handshake(session) < 0) {
623
 
        ssh_socket_close(session->socket);
624
 
        session->alive = 0;
625
 
        leave_function();
626
 
        return SSH_ERROR;
627
 
      }
628
 
      set_status(session,1.0);
629
 
 
630
 
      session->connected = 1;
631
 
      break;
632
 
    case 1:
633
 
      if (ssh_get_kex1(session) < 0) {
634
 
        ssh_socket_close(session->socket);
635
 
        session->alive = 0;
636
 
        leave_function();
637
 
        return SSH_ERROR;
638
 
      }
639
 
      set_status(session,0.6);
640
 
 
641
 
      session->connected = 1;
642
 
      break;
643
 
  }
644
 
 
645
 
  leave_function();
646
 
  return 0;
647
 
}
648
 
 
649
 
/**
650
 
 * @brief Get the issue banner from the server.
651
 
 *
652
 
 * This is the banner showing a disclaimer to users who log in,
653
 
 * typically their right or the fact that they will be monitored.
654
 
 *
655
 
 * @param session       The SSH session to use.
656
 
 *
657
 
 * @return A newly allocated string with the banner, NULL on error.
658
 
 */
659
 
char *ssh_get_issue_banner(ssh_session session) {
660
 
  if (session == NULL || session->banner == NULL) {
661
 
    return NULL;
662
 
  }
663
 
 
664
 
  return string_to_char(session->banner);
665
 
}
666
 
 
667
 
/**
668
 
 * @brief Get the version of the OpenSSH server, if it is not an OpenSSH server
669
 
 * then 0 will be returned.
670
 
 *
671
 
 * You can use the SSH_VERSION_INT macro to compare version numbers.
672
 
 *
673
 
 * @param  session      The SSH session to use.
674
 
 *
675
 
 * @return The version number if available, 0 otherwise.
676
 
 */
677
 
int ssh_get_openssh_version(ssh_session session) {
678
 
  if (session == NULL) {
679
 
    return 0;
680
 
  }
681
 
 
682
 
  return session->openssh;
683
 
}
684
 
 
685
 
/**
686
 
 * @brief Disconnect from a session (client or server).
687
 
 * The session can then be reused to open a new session.
688
 
 *
689
 
 * @param session       The SSH session to disconnect.
690
 
 */
691
 
void ssh_disconnect(ssh_session session) {
692
 
  ssh_string str = NULL;
693
 
 
694
 
  if (session == NULL) {
695
 
    return;
696
 
  }
697
 
 
698
 
  enter_function();
699
 
 
700
 
  if (ssh_socket_is_open(session->socket)) {
701
 
    if (buffer_add_u8(session->out_buffer, SSH2_MSG_DISCONNECT) < 0) {
702
 
      goto error;
703
 
    }
704
 
    if (buffer_add_u32(session->out_buffer,
705
 
          htonl(SSH2_DISCONNECT_BY_APPLICATION)) < 0) {
706
 
      goto error;
707
 
    }
708
 
 
709
 
    str = string_from_char("Bye Bye");
710
 
    if (str == NULL) {
711
 
      goto error;
712
 
    }
713
 
 
714
 
    if (buffer_add_ssh_string(session->out_buffer,str) < 0) {
715
 
      string_free(str);
716
 
      goto error;
717
 
    }
718
 
    string_free(str);
719
 
 
720
 
    packet_send(session);
721
 
    ssh_socket_close(session->socket);
722
 
  }
723
 
  session->alive = 0;
724
 
 
725
 
error:
726
 
  leave_function();
727
 
}
728
 
 
729
 
const char *ssh_copyright(void) {
730
 
    return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2008 Aris Adamantiadis "
731
 
    "(aris@0xbadc0de.be) Distributed under the LGPL, please refer to COPYING"
732
 
    "file for information about your rights";
733
 
}
734
 
/** @} */
735
 
/* vim: set ts=2 sw=2 et cindent: */