Coverage Report

Created: 2023-03-26 07:12

/src/libssh/src/session.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * session.c - non-networking functions
3
 *
4
 * This file is part of the SSH Library
5
 *
6
 * Copyright (c) 2005-2013 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 <string.h>
27
#include <stdlib.h>
28
29
#include "libssh/priv.h"
30
#include "libssh/libssh.h"
31
#include "libssh/crypto.h"
32
#include "libssh/server.h"
33
#include "libssh/socket.h"
34
#include "libssh/ssh2.h"
35
#include "libssh/agent.h"
36
#include "libssh/packet.h"
37
#include "libssh/session.h"
38
#include "libssh/misc.h"
39
#include "libssh/buffer.h"
40
#include "libssh/poll.h"
41
#include "libssh/pki.h"
42
43
0
#define FIRST_CHANNEL 42 // why not ? it helps to find bugs.
44
45
/**
46
 * @defgroup libssh_session The SSH session functions
47
 * @ingroup libssh
48
 *
49
 * Functions that manage a session.
50
 *
51
 * @{
52
 */
53
54
/**
55
 * @brief Create a new ssh session.
56
 *
57
 * @returns             A new ssh_session pointer, NULL on error.
58
 */
59
ssh_session ssh_new(void)
60
0
{
61
0
    ssh_session session;
62
0
    char *id = NULL;
63
0
    int rc;
64
65
0
    session = calloc(1, sizeof (struct ssh_session_struct));
66
0
    if (session == NULL) {
67
0
        return NULL;
68
0
    }
69
70
0
    session->next_crypto = crypto_new();
71
0
    if (session->next_crypto == NULL) {
72
0
        goto err;
73
0
    }
74
75
0
    session->socket = ssh_socket_new(session);
76
0
    if (session->socket == NULL) {
77
0
        goto err;
78
0
    }
79
80
0
    session->out_buffer = ssh_buffer_new();
81
0
    if (session->out_buffer == NULL) {
82
0
        goto err;
83
0
    }
84
85
0
    session->in_buffer = ssh_buffer_new();
86
0
    if (session->in_buffer == NULL) {
87
0
        goto err;
88
0
    }
89
90
0
    session->out_queue = ssh_list_new();
91
0
    if (session->out_queue == NULL) {
92
0
        goto err;
93
0
    }
94
95
0
    session->alive = 0;
96
0
    session->auth.supported_methods = 0;
97
0
    ssh_set_blocking(session, 1);
98
0
    session->maxchannel = FIRST_CHANNEL;
99
100
0
    session->agent = ssh_agent_new(session);
101
0
    if (session->agent == NULL) {
102
0
        goto err;
103
0
    }
104
105
    /* OPTIONS */
106
0
    session->opts.StrictHostKeyChecking = 1;
107
0
    session->opts.port = 22;
108
0
    session->opts.fd = -1;
109
0
    session->opts.compressionlevel = 7;
110
0
    session->opts.nodelay = 0;
111
0
    session->opts.identities_only = false;
112
113
0
    session->opts.flags = SSH_OPT_FLAG_PASSWORD_AUTH |
114
0
                          SSH_OPT_FLAG_PUBKEY_AUTH |
115
0
                          SSH_OPT_FLAG_KBDINT_AUTH |
116
0
                          SSH_OPT_FLAG_GSSAPI_AUTH;
117
118
0
    session->opts.exp_flags = 0;
119
120
0
    session->opts.identity = ssh_list_new();
121
0
    if (session->opts.identity == NULL) {
122
0
        goto err;
123
0
    }
124
0
    session->opts.identity_non_exp = ssh_list_new();
125
0
    if (session->opts.identity_non_exp == NULL) {
126
0
        goto err;
127
0
    }
128
129
0
    id = strdup("%d/id_ed25519");
130
0
    if (id == NULL) {
131
0
        goto err;
132
0
    }
133
134
0
    rc = ssh_list_append(session->opts.identity_non_exp, id);
135
0
    if (rc == SSH_ERROR) {
136
0
        goto err;
137
0
    }
138
139
0
#ifdef HAVE_ECC
140
0
    id = strdup("%d/id_ecdsa");
141
0
    if (id == NULL) {
142
0
        goto err;
143
0
    }
144
0
    rc = ssh_list_append(session->opts.identity_non_exp, id);
145
0
    if (rc == SSH_ERROR) {
146
0
        goto err;
147
0
    }
148
0
#endif
149
150
0
    id = strdup("%d/id_rsa");
151
0
    if (id == NULL) {
152
0
        goto err;
153
0
    }
154
0
    rc = ssh_list_append(session->opts.identity_non_exp, id);
155
0
    if (rc == SSH_ERROR) {
156
0
        goto err;
157
0
    }
158
159
    /* Explicitly initialize states */
160
0
    session->session_state = SSH_SESSION_STATE_NONE;
161
0
    session->pending_call_state = SSH_PENDING_CALL_NONE;
162
0
    session->packet_state = PACKET_STATE_INIT;
163
0
    session->dh_handshake_state = DH_STATE_INIT;
164
0
    session->global_req_state = SSH_CHANNEL_REQ_STATE_NONE;
165
166
0
    session->auth.state = SSH_AUTH_STATE_NONE;
167
0
    session->auth.service_state = SSH_AUTH_SERVICE_NONE;
168
169
0
    return session;
170
171
0
err:
172
0
    free(id);
173
0
    ssh_free(session);
174
0
    return NULL;
175
0
}
176
177
/**
178
 * @brief Deallocate a SSH session handle.
179
 *
180
 * @param[in] session   The SSH session to free.
181
 *
182
 * @see ssh_disconnect()
183
 * @see ssh_new()
184
 */
185
void ssh_free(ssh_session session)
186
0
{
187
0
  int i;
188
0
  struct ssh_iterator *it = NULL;
189
0
  struct ssh_buffer_struct *b = NULL;
190
191
0
  if (session == NULL) {
192
0
    return;
193
0
  }
194
195
  /*
196
   * Delete all channels
197
   *
198
   * This needs the first thing we clean up cause if there is still an open
199
   * channel we call ssh_channel_close() first. So we need a working socket
200
   * and poll context for it.
201
   */
202
0
  for (it = ssh_list_get_iterator(session->channels);
203
0
       it != NULL;
204
0
       it = ssh_list_get_iterator(session->channels)) {
205
0
      ssh_channel_do_free(ssh_iterator_value(ssh_channel,it));
206
0
      ssh_list_remove(session->channels, it);
207
0
  }
208
0
  ssh_list_free(session->channels);
209
0
  session->channels = NULL;
210
211
0
#ifdef WITH_PCAP
212
0
  if (session->pcap_ctx) {
213
0
      ssh_pcap_context_free(session->pcap_ctx);
214
0
      session->pcap_ctx = NULL;
215
0
  }
216
0
#endif
217
218
0
  ssh_socket_free(session->socket);
219
0
  session->socket = NULL;
220
221
0
  if (session->default_poll_ctx) {
222
0
      ssh_poll_ctx_free(session->default_poll_ctx);
223
0
  }
224
225
0
  SSH_BUFFER_FREE(session->in_buffer);
226
0
  SSH_BUFFER_FREE(session->out_buffer);
227
0
  session->in_buffer = session->out_buffer = NULL;
228
229
0
  if (session->in_hashbuf != NULL) {
230
0
      SSH_BUFFER_FREE(session->in_hashbuf);
231
0
  }
232
0
  if (session->out_hashbuf != NULL) {
233
0
      SSH_BUFFER_FREE(session->out_hashbuf);
234
0
  }
235
236
0
  crypto_free(session->current_crypto);
237
0
  crypto_free(session->next_crypto);
238
239
0
#ifndef _WIN32
240
0
  ssh_agent_free(session->agent);
241
0
#endif /* _WIN32 */
242
243
0
  ssh_key_free(session->srv.rsa_key);
244
0
  session->srv.rsa_key = NULL;
245
0
  ssh_key_free(session->srv.ecdsa_key);
246
0
  session->srv.ecdsa_key = NULL;
247
0
  ssh_key_free(session->srv.ed25519_key);
248
0
  session->srv.ed25519_key = NULL;
249
250
0
  if (session->ssh_message_list) {
251
0
      ssh_message msg;
252
253
0
      for (msg = ssh_list_pop_head(ssh_message, session->ssh_message_list);
254
0
           msg != NULL;
255
0
           msg = ssh_list_pop_head(ssh_message, session->ssh_message_list)) {
256
0
          ssh_message_free(msg);
257
0
      }
258
0
      ssh_list_free(session->ssh_message_list);
259
0
  }
260
261
0
  if (session->kbdint != NULL) {
262
0
    ssh_kbdint_free(session->kbdint);
263
0
  }
264
265
0
  if (session->packet_callbacks) {
266
0
    ssh_list_free(session->packet_callbacks);
267
0
  }
268
269
  /* options */
270
0
  if (session->opts.identity) {
271
0
      char *id;
272
273
0
      for (id = ssh_list_pop_head(char *, session->opts.identity);
274
0
           id != NULL;
275
0
           id = ssh_list_pop_head(char *, session->opts.identity)) {
276
0
          SAFE_FREE(id);
277
0
      }
278
0
      ssh_list_free(session->opts.identity);
279
0
  }
280
281
0
  if (session->opts.identity_non_exp) {
282
0
      char *id;
283
284
0
      for (id = ssh_list_pop_head(char *, session->opts.identity_non_exp);
285
0
           id != NULL;
286
0
           id = ssh_list_pop_head(char *, session->opts.identity_non_exp)) {
287
0
          SAFE_FREE(id);
288
0
      }
289
0
      ssh_list_free(session->opts.identity_non_exp);
290
0
  }
291
292
0
    while ((b = ssh_list_pop_head(struct ssh_buffer_struct *,
293
0
                                  session->out_queue)) != NULL) {
294
0
        SSH_BUFFER_FREE(b);
295
0
    }
296
0
    ssh_list_free(session->out_queue);
297
298
0
#ifndef _WIN32
299
0
  ssh_agent_state_free (session->agent_state);
300
0
#endif
301
0
  session->agent_state = NULL;
302
303
0
  SAFE_FREE(session->auth.auto_state);
304
0
  SAFE_FREE(session->serverbanner);
305
0
  SAFE_FREE(session->clientbanner);
306
0
  SAFE_FREE(session->banner);
307
0
  SAFE_FREE(session->disconnect_message);
308
0
  SAFE_FREE(session->peer_discon_msg);
309
310
0
  SAFE_FREE(session->opts.agent_socket);
311
0
  SAFE_FREE(session->opts.bindaddr);
312
0
  SAFE_FREE(session->opts.custombanner);
313
0
  SAFE_FREE(session->opts.moduli_file);
314
0
  SAFE_FREE(session->opts.username);
315
0
  SAFE_FREE(session->opts.host);
316
0
  SAFE_FREE(session->opts.sshdir);
317
0
  SAFE_FREE(session->opts.knownhosts);
318
0
  SAFE_FREE(session->opts.global_knownhosts);
319
0
  SAFE_FREE(session->opts.ProxyCommand);
320
0
  SAFE_FREE(session->opts.gss_server_identity);
321
0
  SAFE_FREE(session->opts.gss_client_identity);
322
0
  SAFE_FREE(session->opts.pubkey_accepted_types);
323
324
0
  for (i = 0; i < SSH_KEX_METHODS; i++) {
325
0
      if (session->opts.wanted_methods[i]) {
326
0
          SAFE_FREE(session->opts.wanted_methods[i]);
327
0
      }
328
0
  }
329
330
  /* burn connection, it could contain sensitive data */
331
0
  explicit_bzero(session, sizeof(struct ssh_session_struct));
332
0
  SAFE_FREE(session);
333
0
}
334
335
/**
336
 * @brief get the client banner
337
 *
338
 * @param[in] session   The SSH session
339
 *
340
 * @return Returns the client banner string or NULL.
341
 */
342
0
const char* ssh_get_clientbanner(ssh_session session) {
343
0
    if (session == NULL) {
344
0
        return NULL;
345
0
    }
346
347
0
    return session->clientbanner;
348
0
}
349
350
/**
351
 * @brief get the server banner
352
 *
353
 * @param[in] session   The SSH session
354
 *
355
 * @return Returns the server banner string or NULL.
356
 */
357
0
const char* ssh_get_serverbanner(ssh_session session) {
358
0
  if(!session) {
359
0
    return NULL;
360
0
  }
361
0
  return session->serverbanner;
362
0
}
363
364
/**
365
 * @brief get the name of the current key exchange algorithm.
366
 *
367
 * @param[in] session   The SSH session
368
 *
369
 * @return Returns the key exchange algorithm string or NULL.
370
 */
371
0
const char* ssh_get_kex_algo(ssh_session session) {
372
0
    if ((session == NULL) ||
373
0
        (session->current_crypto == NULL)) {
374
0
        return NULL;
375
0
    }
376
377
0
    switch (session->current_crypto->kex_type) {
378
0
        case SSH_KEX_DH_GROUP1_SHA1:
379
0
            return "diffie-hellman-group1-sha1";
380
0
        case SSH_KEX_DH_GROUP14_SHA1:
381
0
            return "diffie-hellman-group14-sha1";
382
0
        case SSH_KEX_DH_GROUP14_SHA256:
383
0
            return "diffie-hellman-group14-sha256";
384
0
        case SSH_KEX_DH_GROUP16_SHA512:
385
0
            return "diffie-hellman-group16-sha512";
386
0
        case SSH_KEX_DH_GROUP18_SHA512:
387
0
            return "diffie-hellman-group18-sha512";
388
0
        case SSH_KEX_ECDH_SHA2_NISTP256:
389
0
            return "ecdh-sha2-nistp256";
390
0
        case SSH_KEX_ECDH_SHA2_NISTP384:
391
0
            return "ecdh-sha2-nistp384";
392
0
        case SSH_KEX_ECDH_SHA2_NISTP521:
393
0
            return "ecdh-sha2-nistp521";
394
0
        case SSH_KEX_CURVE25519_SHA256:
395
0
           return "curve25519-sha256";
396
0
        case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
397
0
            return "curve25519-sha256@libssh.org";
398
0
        default:
399
0
            break;
400
0
    }
401
402
0
    return NULL;
403
0
}
404
405
/**
406
 * @brief get the name of the input cipher for the given session.
407
 *
408
 * @param[in] session The SSH session.
409
 *
410
 * @return Returns cipher name or NULL.
411
 */
412
0
const char* ssh_get_cipher_in(ssh_session session) {
413
0
    if ((session != NULL) &&
414
0
        (session->current_crypto != NULL) &&
415
0
        (session->current_crypto->in_cipher != NULL)) {
416
0
        return session->current_crypto->in_cipher->name;
417
0
    }
418
0
    return NULL;
419
0
}
420
421
/**
422
 * @brief get the name of the output cipher for the given session.
423
 *
424
 * @param[in] session The SSH session.
425
 *
426
 * @return Returns cipher name or NULL.
427
 */
428
0
const char* ssh_get_cipher_out(ssh_session session) {
429
0
    if ((session != NULL) &&
430
0
        (session->current_crypto != NULL) &&
431
0
        (session->current_crypto->out_cipher != NULL)) {
432
0
        return session->current_crypto->out_cipher->name;
433
0
    }
434
0
    return NULL;
435
0
}
436
437
/**
438
 * @brief get the name of the input HMAC algorithm for the given session.
439
 *
440
 * @param[in] session The SSH session.
441
 *
442
 * @return Returns HMAC algorithm name or NULL if unknown.
443
 */
444
0
const char* ssh_get_hmac_in(ssh_session session) {
445
0
    if ((session != NULL) &&
446
0
        (session->current_crypto != NULL)) {
447
0
        return ssh_hmac_type_to_string(session->current_crypto->in_hmac, session->current_crypto->in_hmac_etm);
448
0
    }
449
0
    return NULL;
450
0
}
451
452
/**
453
 * @brief get the name of the output HMAC algorithm for the given session.
454
 *
455
 * @param[in] session The SSH session.
456
 *
457
 * @return Returns HMAC algorithm name or NULL if unknown.
458
 */
459
0
const char* ssh_get_hmac_out(ssh_session session) {
460
0
    if ((session != NULL) &&
461
0
        (session->current_crypto != NULL)) {
462
0
        return ssh_hmac_type_to_string(session->current_crypto->out_hmac, session->current_crypto->out_hmac_etm);
463
0
    }
464
0
    return NULL;
465
0
}
466
467
/**
468
 * @brief Disconnect impolitely from a remote host by closing the socket.
469
 *
470
 * Suitable if you forked and want to destroy this session.
471
 *
472
 * @param[in]  session  The SSH session to disconnect.
473
 */
474
0
void ssh_silent_disconnect(ssh_session session) {
475
0
  if (session == NULL) {
476
0
    return;
477
0
  }
478
479
0
  ssh_socket_close(session->socket);
480
0
  session->alive = 0;
481
0
  ssh_disconnect(session);
482
0
}
483
484
/**
485
 * @brief Set the session in blocking/nonblocking mode.
486
 *
487
 * @param[in]  session  The ssh session to change.
488
 *
489
 * @param[in]  blocking Zero for nonblocking mode.
490
 */
491
void ssh_set_blocking(ssh_session session, int blocking)
492
0
{
493
0
    if (session == NULL) {
494
0
        return;
495
0
    }
496
0
    session->flags &= ~SSH_SESSION_FLAG_BLOCKING;
497
0
    session->flags |= blocking ? SSH_SESSION_FLAG_BLOCKING : 0;
498
0
}
499
500
/**
501
 * @brief Return the blocking mode of libssh
502
 * @param[in] session The SSH session
503
 * @returns 0 if the session is nonblocking,
504
 * @returns 1 if the functions may block.
505
 */
506
int ssh_is_blocking(ssh_session session)
507
0
{
508
0
    return (session->flags & SSH_SESSION_FLAG_BLOCKING) ? 1 : 0;
509
0
}
510
511
/* Waits until the output socket is empty */
512
0
static int ssh_flush_termination(void *c){
513
0
  ssh_session session = c;
514
0
  if (ssh_socket_buffered_write_bytes(session->socket) == 0 ||
515
0
      session->session_state == SSH_SESSION_STATE_ERROR)
516
0
    return 1;
517
0
  else
518
0
    return 0;
519
0
}
520
521
/**
522
 * @brief Blocking flush of the outgoing buffer
523
 * @param[in] session The SSH session
524
 * @param[in] timeout Set an upper limit on the time for which this function
525
 *                    will block, in milliseconds. Specifying -1
526
 *                    means an infinite timeout. This parameter is passed to
527
 *                    the poll() function.
528
 * @returns           SSH_OK on success, SSH_AGAIN if timeout occurred,
529
 *                    SSH_ERROR otherwise.
530
 */
531
532
0
int ssh_blocking_flush(ssh_session session, int timeout){
533
0
    int rc;
534
0
    if (session == NULL) {
535
0
        return SSH_ERROR;
536
0
    }
537
538
0
    rc = ssh_handle_packets_termination(session, timeout,
539
0
            ssh_flush_termination, session);
540
0
    if (rc == SSH_ERROR) {
541
0
        return rc;
542
0
    }
543
0
    if (!ssh_flush_termination(session)) {
544
0
        rc = SSH_AGAIN;
545
0
    }
546
547
0
    return rc;
548
0
}
549
550
/**
551
 * @brief Check if we are connected.
552
 *
553
 * @param[in]  session  The session to check if it is connected.
554
 *
555
 * @return              1 if we are connected, 0 if not.
556
 */
557
0
int ssh_is_connected(ssh_session session) {
558
0
    if (session == NULL) {
559
0
        return 0;
560
0
    }
561
562
0
    return session->alive;
563
0
}
564
565
/**
566
 * @brief Get the fd of a connection.
567
 *
568
 * In case you'd need the file descriptor of the connection to the server/client.
569
 *
570
 * @param[in] session   The ssh session to use.
571
 *
572
 * @return              The file descriptor of the connection, or -1 if it is
573
 *                      not connected
574
 */
575
0
socket_t ssh_get_fd(ssh_session session) {
576
0
  if (session == NULL) {
577
0
    return -1;
578
0
  }
579
580
0
  return ssh_socket_get_fd(session->socket);
581
0
}
582
583
/**
584
 * @brief Tell the session it has data to read on the file descriptor without
585
 * blocking.
586
 *
587
 * @param[in] session   The ssh session to use.
588
 */
589
0
void ssh_set_fd_toread(ssh_session session) {
590
0
  if (session == NULL) {
591
0
    return;
592
0
  }
593
594
0
  ssh_socket_set_read_wontblock(session->socket);
595
0
}
596
597
/**
598
 * @brief Tell the session it may write to the file descriptor without blocking.
599
 *
600
 * @param[in] session   The ssh session to use.
601
 */
602
0
void ssh_set_fd_towrite(ssh_session session) {
603
0
  if (session == NULL) {
604
0
    return;
605
0
  }
606
607
0
  ssh_socket_set_write_wontblock(session->socket);
608
0
}
609
610
/**
611
 * @brief Tell the session it has an exception to catch on the file descriptor.
612
 *
613
 * \param[in] session   The ssh session to use.
614
 */
615
0
void ssh_set_fd_except(ssh_session session) {
616
0
  if (session == NULL) {
617
0
    return;
618
0
  }
619
620
0
  ssh_socket_set_except(session->socket);
621
0
}
622
623
/**
624
 * @internal
625
 *
626
 * @brief Poll the current session for an event and call the appropriate
627
 * callbacks. This function will not loop until the timeout is expired.
628
 *
629
 * This will block until one event happens.
630
 *
631
 * @param[in] session   The session handle to use.
632
 *
633
 * @param[in] timeout   Set an upper limit on the time for which this function
634
 *                      will block, in milliseconds. Specifying SSH_TIMEOUT_INFINITE
635
 *                      (-1) means an infinite timeout.
636
 *                      Specifying SSH_TIMEOUT_USER means to use the timeout
637
 *                      specified in options. 0 means poll will return immediately.
638
 *                      This parameter is passed to the poll() function.
639
 *
640
 * @return              SSH_OK on success, SSH_ERROR otherwise.
641
 */
642
int ssh_handle_packets(ssh_session session, int timeout)
643
0
{
644
0
    ssh_poll_handle spoll = NULL;
645
0
    ssh_poll_ctx ctx = NULL;
646
0
    int tm = timeout;
647
0
    int rc;
648
649
0
    if (session == NULL || session->socket == NULL) {
650
0
        return SSH_ERROR;
651
0
    }
652
653
0
    spoll = ssh_socket_get_poll_handle(session->socket);
654
0
    ssh_poll_add_events(spoll, POLLIN);
655
0
    ctx = ssh_poll_get_ctx(spoll);
656
657
0
    if (!ctx) {
658
0
        ctx = ssh_poll_get_default_ctx(session);
659
0
        ssh_poll_ctx_add(ctx, spoll);
660
0
    }
661
662
0
    if (timeout == SSH_TIMEOUT_USER) {
663
0
        if (ssh_is_blocking(session)) {
664
0
            tm = ssh_make_milliseconds(session->opts.timeout,
665
0
                                       session->opts.timeout_usec);
666
0
        } else {
667
0
            tm = 0;
668
0
        }
669
0
    }
670
0
    rc = ssh_poll_ctx_dopoll(ctx, tm);
671
0
    if (rc == SSH_ERROR) {
672
0
        session->session_state = SSH_SESSION_STATE_ERROR;
673
0
    }
674
675
0
    return rc;
676
0
}
677
678
/**
679
 * @internal
680
 *
681
 * @brief Poll the current session for an event and call the appropriate
682
 * callbacks.
683
 *
684
 * This will block until termination function returns true, or timeout expired.
685
 *
686
 * @param[in] session   The session handle to use.
687
 *
688
 * @param[in] timeout   Set an upper limit on the time for which this function
689
 *                      will block, in milliseconds. Specifying
690
 *                      SSH_TIMEOUT_INFINITE (-1) means an infinite timeout.
691
 *                      Specifying SSH_TIMEOUT_USER means using the timeout
692
 *                      specified in options. 0 means poll will return
693
 *                      immediately.
694
 *                      SSH_TIMEOUT_DEFAULT uses the session timeout if set or
695
 *                      uses blocking parameters of the session.
696
 *                      This parameter is passed to the poll() function.
697
 *
698
 * @param[in] fct       Termination function to be used to determine if it is
699
 *                      possible to stop polling.
700
 * @param[in] user      User parameter to be passed to fct termination function.
701
 * @returns             SSH_OK on success, SSH_AGAIN if timeout occurred,
702
 *                      SSH_ERROR otherwise.
703
 */
704
int ssh_handle_packets_termination(ssh_session session,
705
                                   int timeout,
706
                                   ssh_termination_function fct,
707
                                   void *user)
708
0
{
709
0
    struct ssh_timestamp ts;
710
0
    int timeout_ms = SSH_TIMEOUT_INFINITE;
711
0
    int tm;
712
0
    int ret = SSH_OK;
713
714
    /* If a timeout has been provided, use it */
715
0
    if (timeout >= 0) {
716
0
        timeout_ms = timeout;
717
0
    } else {
718
0
        if (ssh_is_blocking(session)) {
719
0
            if (timeout == SSH_TIMEOUT_USER || timeout == SSH_TIMEOUT_DEFAULT) {
720
0
                if (session->opts.timeout > 0 ||
721
0
                    session->opts.timeout_usec > 0) {
722
0
                    timeout_ms =
723
0
                        ssh_make_milliseconds(session->opts.timeout,
724
0
                                              session->opts.timeout_usec);
725
0
                }
726
0
            }
727
0
        } else {
728
0
            timeout_ms = SSH_TIMEOUT_NONBLOCKING;
729
0
        }
730
0
    }
731
732
    /* avoid unnecessary syscall for the SSH_TIMEOUT_NONBLOCKING case */
733
0
    if (timeout_ms != SSH_TIMEOUT_NONBLOCKING) {
734
0
        ssh_timestamp_init(&ts);
735
0
    }
736
737
0
    tm = timeout_ms;
738
0
    while(!fct(user)) {
739
0
        ret = ssh_handle_packets(session, tm);
740
0
        if (ret == SSH_ERROR) {
741
0
            break;
742
0
        }
743
0
        if (ssh_timeout_elapsed(&ts, timeout_ms)) {
744
0
            ret = fct(user) ? SSH_OK : SSH_AGAIN;
745
0
            break;
746
0
        }
747
748
0
        tm = ssh_timeout_update(&ts, timeout_ms);
749
0
    }
750
751
0
    return ret;
752
0
}
753
754
/**
755
 * @brief Get session status
756
 *
757
 * @param session       The ssh session to use.
758
 *
759
 * @returns A bitmask including SSH_CLOSED, SSH_READ_PENDING, SSH_WRITE_PENDING
760
 *          or SSH_CLOSED_ERROR which respectively means the session is closed,
761
 *          has data to read on the connection socket and session was closed
762
 *          due to an error.
763
 */
764
0
int ssh_get_status(ssh_session session) {
765
0
  int socketstate;
766
0
  int r = 0;
767
768
0
  if (session == NULL) {
769
0
    return 0;
770
0
  }
771
772
0
  socketstate = ssh_socket_get_status(session->socket);
773
774
0
  if (session->session_state == SSH_SESSION_STATE_DISCONNECTED) {
775
0
    r |= SSH_CLOSED;
776
0
  }
777
0
  if (socketstate & SSH_READ_PENDING) {
778
0
    r |= SSH_READ_PENDING;
779
0
  }
780
0
  if (socketstate & SSH_WRITE_PENDING) {
781
0
      r |= SSH_WRITE_PENDING;
782
0
  }
783
0
  if ((session->session_state == SSH_SESSION_STATE_DISCONNECTED &&
784
0
       (socketstate & SSH_CLOSED_ERROR)) ||
785
0
      session->session_state == SSH_SESSION_STATE_ERROR) {
786
0
    r |= SSH_CLOSED_ERROR;
787
0
  }
788
789
0
  return r;
790
0
}
791
792
/**
793
 * @brief Get poll flags for an external mainloop
794
 *
795
 * @param session       The ssh session to use.
796
 *
797
 * @returns A bitmask including SSH_READ_PENDING or SSH_WRITE_PENDING.
798
 *          For SSH_READ_PENDING, your invocation of poll() should include
799
 *          POLLIN.  For SSH_WRITE_PENDING, your invocation of poll() should
800
 *          include POLLOUT.
801
 */
802
int ssh_get_poll_flags(ssh_session session)
803
0
{
804
0
  if (session == NULL) {
805
0
    return 0;
806
0
  }
807
808
0
  return ssh_socket_get_poll_flags (session->socket);
809
0
}
810
811
/**
812
 * @brief Get the disconnect message from the server.
813
 *
814
 * @param[in] session   The ssh session to use.
815
 *
816
 * @return              The message sent by the server along with the
817
 *                      disconnect, or NULL in which case the reason of the
818
 *                      disconnect may be found with ssh_get_error.
819
 *
820
 * @see ssh_get_error()
821
 */
822
0
const char *ssh_get_disconnect_message(ssh_session session) {
823
0
  if (session == NULL) {
824
0
    return NULL;
825
0
  }
826
827
0
  if (session->session_state != SSH_SESSION_STATE_DISCONNECTED) {
828
0
    ssh_set_error(session, SSH_REQUEST_DENIED,
829
0
        "Connection not closed yet");
830
0
  } else if(!session->peer_discon_msg) {
831
0
    ssh_set_error(session, SSH_FATAL,
832
0
        "Connection correctly closed but no disconnect message");
833
0
  } else {
834
0
    return session->peer_discon_msg;
835
0
  }
836
837
0
  return NULL;
838
0
}
839
840
/**
841
 * @brief Get the protocol version of the session.
842
 *
843
 * @param session       The ssh session to use.
844
 *
845
 * @return The SSH version as integer, < 0 on error.
846
 */
847
0
int ssh_get_version(ssh_session session) {
848
0
    if (session == NULL) {
849
0
        return -1;
850
0
    }
851
852
0
    return 2;
853
0
}
854
855
/**
856
 * @internal
857
 * @brief Callback to be called when the socket received an exception code.
858
 * @param user is a pointer to session
859
 */
860
0
void ssh_socket_exception_callback(int code, int errno_code, void *user){
861
0
    ssh_session session=(ssh_session)user;
862
863
0
    SSH_LOG(SSH_LOG_RARE,"Socket exception callback: %d (%d)",code, errno_code);
864
0
    session->session_state = SSH_SESSION_STATE_ERROR;
865
0
    if (errno_code == 0 && code == SSH_SOCKET_EXCEPTION_EOF) {
866
0
        ssh_set_error(session, SSH_FATAL, "Socket error: disconnected");
867
0
    } else {
868
0
        char err_msg[SSH_ERRNO_MSG_MAX] = {0};
869
0
        ssh_set_error(session, SSH_FATAL, "Socket error: %s",
870
0
                ssh_strerror(errno_code, err_msg, SSH_ERRNO_MSG_MAX));
871
0
    }
872
873
0
    session->ssh_connection_callback(session);
874
0
}
875
876
/**
877
 * @brief Send a message that should be ignored
878
 *
879
 * @param[in] session   The SSH session
880
 * @param[in] data      Data to be sent
881
 *
882
 * @return              SSH_OK on success, SSH_ERROR otherwise.
883
 */
884
0
int ssh_send_ignore (ssh_session session, const char *data) {
885
0
    const int type = SSH2_MSG_IGNORE;
886
0
    int rc;
887
888
0
    if (ssh_socket_is_open(session->socket)) {
889
0
        rc = ssh_buffer_pack(session->out_buffer,
890
0
                             "bs",
891
0
                             type,
892
0
                             data);
893
0
        if (rc != SSH_OK){
894
0
            ssh_set_error_oom(session);
895
0
            goto error;
896
0
        }
897
0
        ssh_packet_send(session);
898
0
        ssh_handle_packets(session, 0);
899
0
    }
900
901
0
    return SSH_OK;
902
903
0
error:
904
0
    ssh_buffer_reinit(session->out_buffer);
905
0
    return SSH_ERROR;
906
0
}
907
908
/**
909
 * @brief Send a debug message
910
 *
911
 * @param[in] session          The SSH session
912
 * @param[in] message          Data to be sent
913
 * @param[in] always_display   Message SHOULD be displayed by the server. It
914
 *                             SHOULD NOT be displayed unless debugging
915
 *                             information has been explicitly requested.
916
 *
917
 * @return                     SSH_OK on success, SSH_ERROR otherwise.
918
 */
919
0
int ssh_send_debug (ssh_session session, const char *message, int always_display) {
920
0
    int rc;
921
922
0
    if (ssh_socket_is_open(session->socket)) {
923
0
        rc = ssh_buffer_pack(session->out_buffer,
924
0
                             "bbsd",
925
0
                             SSH2_MSG_DEBUG,
926
0
                             always_display != 0 ? 1 : 0,
927
0
                             message,
928
0
                             0); /* empty language tag */
929
0
        if (rc != SSH_OK) {
930
0
            ssh_set_error_oom(session);
931
0
            goto error;
932
0
        }
933
0
        ssh_packet_send(session);
934
0
        ssh_handle_packets(session, 0);
935
0
    }
936
937
0
    return SSH_OK;
938
939
0
error:
940
0
    ssh_buffer_reinit(session->out_buffer);
941
0
    return SSH_ERROR;
942
0
}
943
944
 /**
945
 * @brief Set the session data counters.
946
 *
947
 * This function sets the counter structures to be used to calculate data
948
 * which comes in and goes out through the session at different levels.
949
 *
950
 * @code
951
 * struct ssh_counter_struct scounter = {
952
 *     .in_bytes = 0,
953
 *     .out_bytes = 0,
954
 *     .in_packets = 0,
955
 *     .out_packets = 0
956
 * };
957
 *
958
 * struct ssh_counter_struct rcounter = {
959
 *     .in_bytes = 0,
960
 *     .out_bytes = 0,
961
 *     .in_packets = 0,
962
 *     .out_packets = 0
963
 * };
964
 *
965
 * ssh_set_counters(session, &scounter, &rcounter);
966
 * @endcode
967
 *
968
 * @param[in] session   The SSH session.
969
 *
970
 * @param[in] scounter  Counter for byte data handled by the session sockets.
971
 *
972
 * @param[in] rcounter  Counter for byte and packet data handled by the session,
973
 *                      prior compression and SSH overhead.
974
 */
975
void ssh_set_counters(ssh_session session, ssh_counter scounter,
976
0
                              ssh_counter rcounter) {
977
0
    if (session != NULL) {
978
0
        session->socket_counter = scounter;
979
0
        session->raw_counter = rcounter;
980
0
    }
981
0
}
982
983
/**
984
 * @deprecated Use ssh_get_publickey_hash()
985
 */
986
int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash)
987
0
{
988
0
    ssh_key pubkey = NULL;
989
0
    ssh_string pubkey_blob = NULL;
990
0
    MD5CTX ctx;
991
0
    unsigned char *h;
992
0
    int rc;
993
994
0
    if (session == NULL || hash == NULL) {
995
0
        return SSH_ERROR;
996
0
    }
997
998
    /* In FIPS mode, we cannot use MD5 */
999
0
    if (ssh_fips_mode()) {
1000
0
        ssh_set_error(session,
1001
0
                      SSH_FATAL,
1002
0
                      "In FIPS mode MD5 is not allowed."
1003
0
                      "Try ssh_get_publickey_hash() with"
1004
0
                      "SSH_PUBLICKEY_HASH_SHA256");
1005
0
        return SSH_ERROR;
1006
0
    }
1007
1008
0
    *hash = NULL;
1009
0
    if (session->current_crypto == NULL ||
1010
0
        session->current_crypto->server_pubkey == NULL) {
1011
0
        ssh_set_error(session,SSH_FATAL,"No current cryptographic context");
1012
0
        return SSH_ERROR;
1013
0
    }
1014
1015
0
    h = calloc(MD5_DIGEST_LEN, sizeof(unsigned char));
1016
0
    if (h == NULL) {
1017
0
        return SSH_ERROR;
1018
0
    }
1019
1020
0
    ctx = md5_init();
1021
0
    if (ctx == NULL) {
1022
0
        SAFE_FREE(h);
1023
0
        return SSH_ERROR;
1024
0
    }
1025
1026
0
    rc = ssh_get_server_publickey(session, &pubkey);
1027
0
    if (rc != SSH_OK) {
1028
0
        md5_final(h, ctx);
1029
0
        SAFE_FREE(h);
1030
0
        return SSH_ERROR;
1031
0
    }
1032
1033
0
    rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_blob);
1034
0
    ssh_key_free(pubkey);
1035
0
    if (rc != SSH_OK) {
1036
0
        md5_final(h, ctx);
1037
0
        SAFE_FREE(h);
1038
0
        return SSH_ERROR;
1039
0
    }
1040
1041
0
    md5_update(ctx, ssh_string_data(pubkey_blob), ssh_string_len(pubkey_blob));
1042
0
    SSH_STRING_FREE(pubkey_blob);
1043
0
    md5_final(h, ctx);
1044
1045
0
    *hash = h;
1046
1047
0
    return MD5_DIGEST_LEN;
1048
0
}
1049
1050
/**
1051
 * @brief Deallocate the hash obtained by ssh_get_pubkey_hash.
1052
 *
1053
 * This is required under Microsoft platform as this library might use a
1054
 * different C library than your software, hence a different heap.
1055
 *
1056
 * @param[in] hash      The buffer to deallocate.
1057
 *
1058
 * @see ssh_get_pubkey_hash()
1059
 */
1060
void ssh_clean_pubkey_hash(unsigned char **hash)
1061
0
{
1062
0
    SAFE_FREE(*hash);
1063
0
}
1064
1065
/**
1066
 * @brief Get the server public key from a session.
1067
 *
1068
 * @param[in]  session  The session to get the key from.
1069
 *
1070
 * @param[out] key      A pointer to store the allocated key. You need to free
1071
 *                      the key using ssh_key_free().
1072
 *
1073
 * @return              SSH_OK on success, SSH_ERROR on error.
1074
 *
1075
 * @see ssh_key_free()
1076
 */
1077
int ssh_get_server_publickey(ssh_session session, ssh_key *key)
1078
0
{
1079
0
    ssh_key pubkey = NULL;
1080
1081
0
    if (session == NULL ||
1082
0
        session->current_crypto == NULL ||
1083
0
        session->current_crypto->server_pubkey == NULL) {
1084
0
        return SSH_ERROR;
1085
0
    }
1086
1087
0
    pubkey = ssh_key_dup(session->current_crypto->server_pubkey);
1088
0
    if (pubkey == NULL) {
1089
0
        return SSH_ERROR;
1090
0
    }
1091
1092
0
    *key = pubkey;
1093
0
    return SSH_OK;
1094
0
}
1095
1096
/**
1097
 * @deprecated Use ssh_get_server_publickey()
1098
 */
1099
int ssh_get_publickey(ssh_session session, ssh_key *key)
1100
0
{
1101
0
    return ssh_get_server_publickey(session, key);
1102
0
}
1103
1104
/**
1105
 * @brief Allocates a buffer with the hash of the public key.
1106
 *
1107
 * This function allows you to get a hash of the public key. You can then
1108
 * print this hash in a human-readable form to the user so that he is able to
1109
 * verify it. Use ssh_get_hexa() or ssh_print_hash() to display it.
1110
 *
1111
 * @param[in]  key      The public key to create the hash for.
1112
 *
1113
 * @param[in]  type     The type of the hash you want.
1114
 *
1115
 * @param[out]  hash    A pointer to store the allocated buffer. It can be
1116
 *                      freed using ssh_clean_pubkey_hash().
1117
 *
1118
 * @param[in]  hlen     The length of the hash.
1119
 *
1120
 * @return 0 on success, -1 if an error occurred.
1121
 *
1122
 * @warning It is very important that you verify at some moment that the hash
1123
 *          matches a known server. If you don't do it, cryptography won't help
1124
 *          you at making things secure.
1125
 *          OpenSSH uses SHA256 to print public key digests.
1126
 *
1127
 * @see ssh_session_update_known_hosts()
1128
 * @see ssh_get_hexa()
1129
 * @see ssh_print_hash()
1130
 * @see ssh_clean_pubkey_hash()
1131
 */
1132
int ssh_get_publickey_hash(const ssh_key key,
1133
                           enum ssh_publickey_hash_type type,
1134
                           unsigned char **hash,
1135
                           size_t *hlen)
1136
0
{
1137
0
    ssh_string blob;
1138
0
    unsigned char *h = NULL;
1139
0
    int rc;
1140
1141
0
    rc = ssh_pki_export_pubkey_blob(key, &blob);
1142
0
    if (rc < 0) {
1143
0
        return rc;
1144
0
    }
1145
1146
0
    switch (type) {
1147
0
    case SSH_PUBLICKEY_HASH_SHA1:
1148
0
        {
1149
0
            SHACTX ctx;
1150
1151
0
            h = calloc(1, SHA_DIGEST_LEN);
1152
0
            if (h == NULL) {
1153
0
                rc = -1;
1154
0
                goto out;
1155
0
            }
1156
1157
0
            ctx = sha1_init();
1158
0
            if (ctx == NULL) {
1159
0
                free(h);
1160
0
                rc = -1;
1161
0
                goto out;
1162
0
            }
1163
1164
0
            sha1_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
1165
0
            sha1_final(h, ctx);
1166
1167
0
            *hlen = SHA_DIGEST_LEN;
1168
0
        }
1169
0
        break;
1170
0
    case SSH_PUBLICKEY_HASH_SHA256:
1171
0
        {
1172
0
            SHA256CTX ctx;
1173
1174
0
            h = calloc(1, SHA256_DIGEST_LEN);
1175
0
            if (h == NULL) {
1176
0
                rc = -1;
1177
0
                goto out;
1178
0
            }
1179
1180
0
            ctx = sha256_init();
1181
0
            if (ctx == NULL) {
1182
0
                free(h);
1183
0
                rc = -1;
1184
0
                goto out;
1185
0
            }
1186
1187
0
            sha256_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
1188
0
            sha256_final(h, ctx);
1189
1190
0
            *hlen = SHA256_DIGEST_LEN;
1191
0
        }
1192
0
        break;
1193
0
    case SSH_PUBLICKEY_HASH_MD5:
1194
0
        {
1195
0
            MD5CTX ctx;
1196
1197
            /* In FIPS mode, we cannot use MD5 */
1198
0
            if (ssh_fips_mode()) {
1199
0
                SSH_LOG(SSH_LOG_TRACE, "In FIPS mode MD5 is not allowed."
1200
0
                                       "Try using SSH_PUBLICKEY_HASH_SHA256");
1201
0
                rc = SSH_ERROR;
1202
0
                goto out;
1203
0
            }
1204
1205
0
            h = calloc(1, MD5_DIGEST_LEN);
1206
0
            if (h == NULL) {
1207
0
                rc = -1;
1208
0
                goto out;
1209
0
            }
1210
1211
0
            ctx = md5_init();
1212
0
            if (ctx == NULL) {
1213
0
                free(h);
1214
0
                rc = -1;
1215
0
                goto out;
1216
0
            }
1217
1218
0
            md5_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
1219
0
            md5_final(h, ctx);
1220
1221
0
            *hlen = MD5_DIGEST_LEN;
1222
0
        }
1223
0
        break;
1224
0
    default:
1225
0
        rc = -1;
1226
0
        goto out;
1227
0
    }
1228
1229
0
    *hash = h;
1230
0
    rc = 0;
1231
0
out:
1232
0
    SSH_STRING_FREE(blob);
1233
0
    return rc;
1234
0
}
1235
1236
/** @} */