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