1 /*
2  * auth.c - Authentication with SSH protocols
3  *
4  * This file is part of the SSH Library
5  *
6  * Copyright (c) 2003-2013 by Aris Adamantiadis <aris@0xbadc0de.be>
7  * Copyright (c) 2008-2013 Andreas Schneider <asn@cryptomilk.org>
8  *
9  * The SSH Library is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or (at your
12  * option) any later version.
13  *
14  * The SSH Library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with the SSH Library; see the file COPYING.  If not, write to
21  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22  * MA 02111-1307, USA.
23  */
24 
25 #include "config.h"
26 
27 #include <stdio.h>
28 #include <string.h>
29 
30 #ifndef _WIN32
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #endif
34 
35 #include "libssh/priv.h"
36 #include "libssh/crypto.h"
37 #include "libssh/ssh2.h"
38 #include "libssh/buffer.h"
39 #include "libssh/agent.h"
40 #include "libssh/misc.h"
41 #include "libssh/packet.h"
42 #include "libssh/session.h"
43 #include "libssh/keys.h"
44 #include "libssh/auth.h"
45 #include "libssh/pki.h"
46 #include "libssh/gssapi.h"
47 #include "libssh/legacy.h"
48 
49 /**
50  * @defgroup libssh_auth The SSH authentication functions.
51  * @ingroup libssh
52  *
53  * Functions to authenticate with a server.
54  *
55  * @{
56  */
57 
58 /**
59  * @internal
60  *
61  * @brief Ask access to the ssh-userauth service.
62  *
63  * @param[in] session   The SSH session handle.
64  *
65  * @returns SSH_OK on success, SSH_ERROR on error.
66  * @returns SSH_AGAIN on nonblocking mode, if calling that function
67  * again is necessary
68  */
ssh_userauth_request_service(ssh_session session)69 static int ssh_userauth_request_service(ssh_session session) {
70     int rc;
71 
72     rc = ssh_service_request(session, "ssh-userauth");
73     if ((rc != SSH_OK) && (rc != SSH_AGAIN)) {
74         SSH_LOG(SSH_LOG_WARN,
75                 "Failed to request \"ssh-userauth\" service");
76     }
77 
78     return rc;
79 }
80 
ssh_auth_response_termination(void * user)81 static int ssh_auth_response_termination(void *user) {
82     ssh_session session = (ssh_session)user;
83     switch (session->auth.state) {
84         case SSH_AUTH_STATE_NONE:
85         case SSH_AUTH_STATE_KBDINT_SENT:
86         case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT:
87         case SSH_AUTH_STATE_GSSAPI_TOKEN:
88         case SSH_AUTH_STATE_GSSAPI_MIC_SENT:
89         case SSH_AUTH_STATE_PUBKEY_AUTH_SENT:
90         case SSH_AUTH_STATE_PUBKEY_OFFER_SENT:
91         case SSH_AUTH_STATE_PASSWORD_AUTH_SENT:
92         case SSH_AUTH_STATE_AUTH_NONE_SENT:
93             return 0;
94         default:
95             return 1;
96     }
97 }
98 
ssh_auth_get_current_method(ssh_session session)99 static const char *ssh_auth_get_current_method(ssh_session session)
100 {
101     const char *method = "unknown";
102 
103     switch (session->auth.current_method) {
104     case SSH_AUTH_METHOD_NONE:
105         method = "none";
106         break;
107     case SSH_AUTH_METHOD_PASSWORD:
108         method = "password";
109         break;
110     case SSH_AUTH_METHOD_PUBLICKEY:
111         method = "publickey";
112         break;
113     case SSH_AUTH_METHOD_HOSTBASED:
114         method = "hostbased";
115         break;
116     case SSH_AUTH_METHOD_INTERACTIVE:
117         method = "keyboard interactive";
118         break;
119     case SSH_AUTH_METHOD_GSSAPI_MIC:
120         method = "gssapi";
121         break;
122     default:
123         break;
124     }
125 
126     return method;
127 }
128 
129 /**
130  * @internal
131  * @brief Wait for a response of an authentication function.
132  *
133  * @param[in] session   The SSH session.
134  *
135  * @returns SSH_AUTH_SUCCESS Authentication success, or pubkey accepted
136  *          SSH_AUTH_PARTIAL Authentication succeeded but another mean
137  *                           of authentication is needed.
138  *          SSH_AUTH_INFO    Data for keyboard-interactive
139  *          SSH_AUTH_AGAIN   In nonblocking mode, call has to be made again
140  *          SSH_AUTH_ERROR   Error during the process.
141  */
ssh_userauth_get_response(ssh_session session)142 static int ssh_userauth_get_response(ssh_session session) {
143     int rc = SSH_AUTH_ERROR;
144 
145     rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER,
146         ssh_auth_response_termination, session);
147     if (rc == SSH_ERROR) {
148         return SSH_AUTH_ERROR;
149     }
150     if (!ssh_auth_response_termination(session)) {
151         return SSH_AUTH_AGAIN;
152     }
153 
154     switch(session->auth.state) {
155         case SSH_AUTH_STATE_ERROR:
156             rc = SSH_AUTH_ERROR;
157             break;
158         case SSH_AUTH_STATE_FAILED:
159             rc = SSH_AUTH_DENIED;
160             break;
161         case SSH_AUTH_STATE_INFO:
162             rc = SSH_AUTH_INFO;
163             break;
164         case SSH_AUTH_STATE_PARTIAL:
165             rc = SSH_AUTH_PARTIAL;
166             break;
167         case SSH_AUTH_STATE_PK_OK:
168         case SSH_AUTH_STATE_SUCCESS:
169             rc = SSH_AUTH_SUCCESS;
170             break;
171         case SSH_AUTH_STATE_KBDINT_SENT:
172         case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT:
173         case SSH_AUTH_STATE_GSSAPI_TOKEN:
174         case SSH_AUTH_STATE_GSSAPI_MIC_SENT:
175         case SSH_AUTH_STATE_PUBKEY_OFFER_SENT:
176         case SSH_AUTH_STATE_PUBKEY_AUTH_SENT:
177         case SSH_AUTH_STATE_PASSWORD_AUTH_SENT:
178         case SSH_AUTH_STATE_AUTH_NONE_SENT:
179         case SSH_AUTH_STATE_NONE:
180             /* not reached */
181             rc = SSH_AUTH_ERROR;
182             break;
183     }
184 
185     return rc;
186 }
187 
188 /**
189  * @internal
190  *
191  * @brief Handles a SSH_USERAUTH_BANNER packet.
192  *
193  * This banner should be shown to user prior to authentication
194  */
SSH_PACKET_CALLBACK(ssh_packet_userauth_banner)195 SSH_PACKET_CALLBACK(ssh_packet_userauth_banner) {
196     ssh_string banner;
197     (void)type;
198     (void)user;
199 
200     banner = ssh_buffer_get_ssh_string(packet);
201     if (banner == NULL) {
202         SSH_LOG(SSH_LOG_WARN,
203                 "Invalid SSH_USERAUTH_BANNER packet");
204     } else {
205         SSH_LOG(SSH_LOG_DEBUG,
206                 "Received SSH_USERAUTH_BANNER packet");
207         if (session->banner != NULL)
208             SSH_STRING_FREE(session->banner);
209         session->banner = banner;
210     }
211 
212     return SSH_PACKET_USED;
213 }
214 
215 /**
216  * @internal
217  *
218  * @brief Handles a SSH_USERAUTH_FAILURE packet.
219  *
220  * This handles the complete or partial authentication failure.
221  */
SSH_PACKET_CALLBACK(ssh_packet_userauth_failure)222 SSH_PACKET_CALLBACK(ssh_packet_userauth_failure) {
223     const char *current_method = ssh_auth_get_current_method(session);
224     char *auth_methods = NULL;
225     uint8_t partial = 0;
226     int rc;
227     (void) type;
228     (void) user;
229 
230     rc = ssh_buffer_unpack(packet, "sb", &auth_methods, &partial);
231     if (rc != SSH_OK) {
232         ssh_set_error(session, SSH_FATAL,
233                       "Invalid SSH_MSG_USERAUTH_FAILURE message");
234         session->auth.state = SSH_AUTH_STATE_ERROR;
235         goto end;
236     }
237 
238     if (partial) {
239         session->auth.state = SSH_AUTH_STATE_PARTIAL;
240         SSH_LOG(SSH_LOG_INFO,
241                 "Partial success for '%s'. Authentication that can continue: %s",
242                 current_method,
243                 auth_methods);
244     } else {
245         session->auth.state = SSH_AUTH_STATE_FAILED;
246         ssh_set_error(session, SSH_REQUEST_DENIED,
247                       "Access denied for '%s'. Authentication that can continue: %s",
248                       current_method,
249                       auth_methods);
250         SSH_LOG(SSH_LOG_INFO,
251                 "%s",
252                 ssh_get_error(session));
253 
254     }
255     session->auth.supported_methods = 0;
256     if (strstr(auth_methods, "password") != NULL) {
257         session->auth.supported_methods |= SSH_AUTH_METHOD_PASSWORD;
258     }
259     if (strstr(auth_methods, "keyboard-interactive") != NULL) {
260         session->auth.supported_methods |= SSH_AUTH_METHOD_INTERACTIVE;
261     }
262     if (strstr(auth_methods, "publickey") != NULL) {
263         session->auth.supported_methods |= SSH_AUTH_METHOD_PUBLICKEY;
264     }
265     if (strstr(auth_methods, "hostbased") != NULL) {
266         session->auth.supported_methods |= SSH_AUTH_METHOD_HOSTBASED;
267     }
268     if (strstr(auth_methods, "gssapi-with-mic") != NULL) {
269         session->auth.supported_methods |= SSH_AUTH_METHOD_GSSAPI_MIC;
270     }
271 
272 end:
273     session->auth.current_method = SSH_AUTH_METHOD_UNKNOWN;
274     SAFE_FREE(auth_methods);
275 
276     return SSH_PACKET_USED;
277 }
278 
279 /**
280  * @internal
281  *
282  * @brief Handles a SSH_USERAUTH_SUCCESS packet.
283  *
284  * It is also used to communicate the new to the upper levels.
285  */
SSH_PACKET_CALLBACK(ssh_packet_userauth_success)286 SSH_PACKET_CALLBACK(ssh_packet_userauth_success)
287 {
288   struct ssh_crypto_struct *crypto = NULL;
289 
290   (void)packet;
291   (void)type;
292   (void)user;
293 
294   SSH_LOG(SSH_LOG_DEBUG, "Authentication successful");
295   SSH_LOG(SSH_LOG_TRACE, "Received SSH_USERAUTH_SUCCESS");
296 
297   session->auth.state = SSH_AUTH_STATE_SUCCESS;
298   session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
299   session->flags |= SSH_SESSION_FLAG_AUTHENTICATED;
300 
301   crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_OUT);
302   if (crypto != NULL && crypto->delayed_compress_out) {
303       SSH_LOG(SSH_LOG_DEBUG, "Enabling delayed compression OUT");
304       crypto->do_compress_out = 1;
305   }
306 
307   crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_IN);
308   if (crypto != NULL && crypto->delayed_compress_in) {
309       SSH_LOG(SSH_LOG_DEBUG, "Enabling delayed compression IN");
310       crypto->do_compress_in = 1;
311   }
312 
313     /* Reset errors by previous authentication methods. */
314     ssh_reset_error(session);
315     session->auth.current_method = SSH_AUTH_METHOD_UNKNOWN;
316   return SSH_PACKET_USED;
317 }
318 
319 /**
320  * @internal
321  *
322  * @brief Handles a SSH_USERAUTH_PK_OK or SSH_USERAUTH_INFO_REQUEST packet.
323  *
324  * Since the two types of packets share the same code, additional work is done
325  * to understand if we are in a public key or keyboard-interactive context.
326  */
SSH_PACKET_CALLBACK(ssh_packet_userauth_pk_ok)327 SSH_PACKET_CALLBACK(ssh_packet_userauth_pk_ok) {
328     int rc;
329 
330     SSH_LOG(SSH_LOG_TRACE,
331             "Received SSH_USERAUTH_PK_OK/INFO_REQUEST/GSSAPI_RESPONSE");
332 
333     if (session->auth.state == SSH_AUTH_STATE_KBDINT_SENT) {
334         /* Assuming we are in keyboard-interactive context */
335         SSH_LOG(SSH_LOG_TRACE,
336                 "keyboard-interactive context, "
337                 "assuming SSH_USERAUTH_INFO_REQUEST");
338         rc = ssh_packet_userauth_info_request(session,type,packet,user);
339 #ifdef WITH_GSSAPI
340     } else if (session->auth.state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT) {
341         rc = ssh_packet_userauth_gssapi_response(session, type, packet, user);
342 #endif
343     } else if (session->auth.state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT) {
344         session->auth.state = SSH_AUTH_STATE_PK_OK;
345         SSH_LOG(SSH_LOG_TRACE, "Assuming SSH_USERAUTH_PK_OK");
346         rc = SSH_PACKET_USED;
347     } else {
348         session->auth.state = SSH_AUTH_STATE_ERROR;
349         SSH_LOG(SSH_LOG_TRACE, "SSH_USERAUTH_PK_OK received in wrong state");
350         rc = SSH_PACKET_USED;
351     }
352 
353     return rc;
354 }
355 
356 /**
357  * @brief Get available authentication methods from the server.
358  *
359  * This requires the function ssh_userauth_none() to be called before the
360  * methods are available. The server MAY return a list of methods that may
361  * continue.
362  *
363  * @param[in] session   The SSH session.
364  *
365  * @param[in] username  Deprecated, set to NULL.
366  *
367  * @returns             A bitfield of the fllowing values:
368  *                      - SSH_AUTH_METHOD_PASSWORD
369  *                      - SSH_AUTH_METHOD_PUBLICKEY
370  *                      - SSH_AUTH_METHOD_HOSTBASED
371  *                      - SSH_AUTH_METHOD_INTERACTIVE
372  *
373  * @warning Other reserved flags may appear in future versions.
374  * @see ssh_userauth_none()
375  */
ssh_userauth_list(ssh_session session,const char * username)376 int ssh_userauth_list(ssh_session session, const char *username)
377 {
378     (void) username; /* unused */
379 
380     if (session == NULL) {
381         return 0;
382     }
383 
384     return session->auth.supported_methods;
385 }
386 
387 /**
388  * @brief Try to authenticate through the "none" method.
389  *
390  * @param[in] session   The ssh session to use.
391  *
392  * @param[in] username    The username, this SHOULD be NULL.
393  *
394  * @returns SSH_AUTH_ERROR:   A serious error happened.\n
395  *          SSH_AUTH_DENIED:  Authentication failed: use another method\n
396  *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
397  *                            have to use another method\n
398  *          SSH_AUTH_SUCCESS: Authentication success\n
399  *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
400  *                            later.
401  *
402  * @note Most server implementations do not permit changing the username during
403  * authentication. The username should only be set with ssh_options_set() only
404  * before you connect to the server.
405  */
ssh_userauth_none(ssh_session session,const char * username)406 int ssh_userauth_none(ssh_session session, const char *username) {
407     int rc;
408 
409     switch(session->pending_call_state) {
410         case SSH_PENDING_CALL_NONE:
411             break;
412         case SSH_PENDING_CALL_AUTH_NONE:
413             goto pending;
414         default:
415             ssh_set_error(session, SSH_FATAL,
416                           "Wrong state (%d) during pending SSH call",
417                           session->pending_call_state);
418             return SSH_AUTH_ERROR;
419     }
420 
421     rc = ssh_userauth_request_service(session);
422     if (rc == SSH_AGAIN) {
423         return SSH_AUTH_AGAIN;
424     } else if (rc == SSH_ERROR) {
425         return SSH_AUTH_ERROR;
426     }
427 
428     /* request */
429     rc = ssh_buffer_pack(session->out_buffer, "bsss",
430             SSH2_MSG_USERAUTH_REQUEST,
431             username ? username : session->opts.username,
432             "ssh-connection",
433             "none"
434             );
435     if (rc < 0) {
436         goto fail;
437     }
438 
439     session->auth.current_method = SSH_AUTH_METHOD_NONE;
440     session->auth.state = SSH_AUTH_STATE_AUTH_NONE_SENT;
441     session->pending_call_state = SSH_PENDING_CALL_AUTH_NONE;
442     rc = ssh_packet_send(session);
443     if (rc == SSH_ERROR) {
444         return SSH_AUTH_ERROR;
445     }
446 
447 pending:
448     rc = ssh_userauth_get_response(session);
449     if (rc != SSH_AUTH_AGAIN) {
450         session->pending_call_state = SSH_PENDING_CALL_NONE;
451     }
452 
453     return rc;
454 fail:
455     ssh_set_error_oom(session);
456     ssh_buffer_reinit(session->out_buffer);
457 
458     return SSH_AUTH_ERROR;
459 }
460 
461 /**
462  * @brief Try to authenticate with the given public key.
463  *
464  * To avoid unnecessary processing and user interaction, the following method
465  * is provided for querying whether authentication using the 'pubkey' would
466  * be possible.
467  *
468  * @param[in] session     The SSH session.
469  *
470  * @param[in] username    The username, this SHOULD be NULL.
471  *
472  * @param[in] pubkey      The public key to try.
473  *
474  * @return  SSH_AUTH_ERROR:   A serious error happened.\n
475  *          SSH_AUTH_DENIED:  The server doesn't accept that public key as an
476  *                            authentication token. Try another key or another
477  *                            method.\n
478  *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
479  *                            have to use another method.\n
480  *          SSH_AUTH_SUCCESS: The public key is accepted, you want now to use
481  *                            ssh_userauth_publickey().\n
482  *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
483  *                            later.
484  *
485  * @note Most server implementations do not permit changing the username during
486  * authentication. The username should only be set with ssh_options_set() only
487  * before you connect to the server.
488  */
ssh_userauth_try_publickey(ssh_session session,const char * username,const ssh_key pubkey)489 int ssh_userauth_try_publickey(ssh_session session,
490                                const char *username,
491                                const ssh_key pubkey)
492 {
493     ssh_string pubkey_s = NULL;
494     const char *sig_type_c = NULL;
495     int rc;
496 
497     if (session == NULL) {
498         return SSH_AUTH_ERROR;
499     }
500 
501     if (pubkey == NULL || !ssh_key_is_public(pubkey)) {
502         ssh_set_error(session, SSH_FATAL, "Invalid pubkey");
503         return SSH_AUTH_ERROR;
504     }
505 
506     switch(session->pending_call_state) {
507         case SSH_PENDING_CALL_NONE:
508             break;
509         case SSH_PENDING_CALL_AUTH_OFFER_PUBKEY:
510             goto pending;
511         default:
512             ssh_set_error(session,
513                           SSH_FATAL,
514                           "Wrong state (%d) during pending SSH call",
515                           session->pending_call_state);
516             return SSH_ERROR;
517     }
518 
519     /* Check if the given public key algorithm is allowed */
520     sig_type_c = ssh_key_get_signature_algorithm(session, pubkey->type);
521     if (sig_type_c == NULL) {
522         ssh_set_error(session, SSH_REQUEST_DENIED,
523                       "Invalid key type (unknown)");
524         return SSH_AUTH_DENIED;
525     }
526     if (!ssh_key_algorithm_allowed(session, sig_type_c)) {
527         ssh_set_error(session, SSH_REQUEST_DENIED,
528                       "The key algorithm '%s' is not allowed to be used by"
529                       " PUBLICKEY_ACCEPTED_TYPES configuration option",
530                       sig_type_c);
531         return SSH_AUTH_DENIED;
532     }
533 
534     rc = ssh_userauth_request_service(session);
535     if (rc == SSH_AGAIN) {
536         return SSH_AUTH_AGAIN;
537     } else if (rc == SSH_ERROR) {
538         return SSH_AUTH_ERROR;
539     }
540 
541     /* public key */
542     rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_s);
543     if (rc < 0) {
544         goto fail;
545     }
546 
547     /* request */
548     rc = ssh_buffer_pack(session->out_buffer, "bsssbsS",
549             SSH2_MSG_USERAUTH_REQUEST,
550             username ? username : session->opts.username,
551             "ssh-connection",
552             "publickey",
553             0, /* private key ? */
554             sig_type_c, /* algo */
555             pubkey_s /* public key */
556             );
557     if (rc < 0) {
558         goto fail;
559     }
560 
561     SSH_STRING_FREE(pubkey_s);
562 
563     session->auth.current_method = SSH_AUTH_METHOD_PUBLICKEY;
564     session->auth.state = SSH_AUTH_STATE_PUBKEY_OFFER_SENT;
565     session->pending_call_state = SSH_PENDING_CALL_AUTH_OFFER_PUBKEY;
566     rc = ssh_packet_send(session);
567     if (rc == SSH_ERROR) {
568         return SSH_AUTH_ERROR;
569     }
570 
571 pending:
572     rc = ssh_userauth_get_response(session);
573     if (rc != SSH_AUTH_AGAIN) {
574         session->pending_call_state = SSH_PENDING_CALL_NONE;
575     }
576 
577     return rc;
578 fail:
579     SSH_STRING_FREE(pubkey_s);
580     ssh_set_error_oom(session);
581     ssh_buffer_reinit(session->out_buffer);
582 
583     return SSH_AUTH_ERROR;
584 }
585 
586 /**
587  * @brief Authenticate with public/private key or certificate.
588  *
589  * @param[in] session     The SSH session.
590  *
591  * @param[in] username    The username, this SHOULD be NULL.
592  *
593  * @param[in] privkey     The private key for authentication.
594  *
595  * @return  SSH_AUTH_ERROR:   A serious error happened.\n
596  *          SSH_AUTH_DENIED:  The server doesn't accept that public key as an
597  *                            authentication token. Try another key or another
598  *                            method.\n
599  *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
600  *                            have to use another method.\n
601  *          SSH_AUTH_SUCCESS: The public key is accepted.\n
602  *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
603  *                            later.
604  *
605  * @note Most server implementations do not permit changing the username during
606  * authentication. The username should only be set with ssh_options_set() only
607  * before you connect to the server.
608  */
ssh_userauth_publickey(ssh_session session,const char * username,const ssh_key privkey)609 int ssh_userauth_publickey(ssh_session session,
610                            const char *username,
611                            const ssh_key privkey)
612 {
613     ssh_string str = NULL;
614     int rc;
615     const char *sig_type_c = NULL;
616     enum ssh_keytypes_e key_type;
617     enum ssh_digest_e hash_type;
618 
619     if (session == NULL) {
620         return SSH_AUTH_ERROR;
621     }
622 
623     if (privkey == NULL || !ssh_key_is_private(privkey)) {
624         ssh_set_error(session, SSH_FATAL, "Invalid private key");
625         return SSH_AUTH_ERROR;
626     }
627 
628     switch(session->pending_call_state) {
629         case SSH_PENDING_CALL_NONE:
630             break;
631         case SSH_PENDING_CALL_AUTH_PUBKEY:
632             goto pending;
633         default:
634             ssh_set_error(session,
635                           SSH_FATAL,
636                           "Bad call during pending SSH call in ssh_userauth_try_publickey");
637             return SSH_AUTH_ERROR;
638     }
639 
640     /* Cert auth requires presenting the cert type name (*-cert@openssh.com) */
641     key_type = privkey->cert != NULL ? privkey->cert_type : privkey->type;
642 
643     /* Check if the given public key algorithm is allowed */
644     sig_type_c = ssh_key_get_signature_algorithm(session, key_type);
645     if (sig_type_c == NULL) {
646         ssh_set_error(session, SSH_REQUEST_DENIED,
647                       "Invalid key type (unknown)");
648         return SSH_AUTH_DENIED;
649     }
650     if (!ssh_key_algorithm_allowed(session, sig_type_c)) {
651         ssh_set_error(session, SSH_REQUEST_DENIED,
652                       "The key algorithm '%s' is not allowed to be used by"
653                       " PUBLICKEY_ACCEPTED_TYPES configuration option",
654                       sig_type_c);
655         return SSH_AUTH_DENIED;
656     }
657 
658     rc = ssh_userauth_request_service(session);
659     if (rc == SSH_AGAIN) {
660         return SSH_AUTH_AGAIN;
661     } else if (rc == SSH_ERROR) {
662         return SSH_AUTH_ERROR;
663     }
664 
665     /* get public key or cert */
666     rc = ssh_pki_export_pubkey_blob(privkey, &str);
667     if (rc < 0) {
668         goto fail;
669     }
670 
671     /* request */
672     rc = ssh_buffer_pack(session->out_buffer, "bsssbsS",
673             SSH2_MSG_USERAUTH_REQUEST,
674             username ? username : session->opts.username,
675             "ssh-connection",
676             "publickey",
677             1, /* private key */
678             sig_type_c, /* algo */
679             str /* public key or cert */
680             );
681     if (rc < 0) {
682         goto fail;
683     }
684     SSH_STRING_FREE(str);
685 
686     /* Get the hash type to be used in the signature based on the key type */
687     hash_type = ssh_key_type_to_hash(session, privkey->type);
688 
689     /* sign the buffer with the private key */
690     str = ssh_pki_do_sign(session, session->out_buffer, privkey, hash_type);
691     if (str == NULL) {
692         goto fail;
693     }
694 
695     rc = ssh_buffer_add_ssh_string(session->out_buffer, str);
696     SSH_STRING_FREE(str);
697     str = NULL;
698     if (rc < 0) {
699         goto fail;
700     }
701 
702     session->auth.current_method = SSH_AUTH_METHOD_PUBLICKEY;
703     session->auth.state = SSH_AUTH_STATE_PUBKEY_AUTH_SENT;
704     session->pending_call_state = SSH_PENDING_CALL_AUTH_PUBKEY;
705     rc = ssh_packet_send(session);
706     if (rc == SSH_ERROR) {
707         return SSH_AUTH_ERROR;
708     }
709 
710 pending:
711     rc = ssh_userauth_get_response(session);
712     if (rc != SSH_AUTH_AGAIN) {
713         session->pending_call_state = SSH_PENDING_CALL_NONE;
714     }
715 
716     return rc;
717 fail:
718     SSH_STRING_FREE(str);
719     ssh_set_error_oom(session);
720     ssh_buffer_reinit(session->out_buffer);
721 
722     return SSH_AUTH_ERROR;
723 }
724 
725 #ifndef _WIN32
ssh_userauth_agent_publickey(ssh_session session,const char * username,ssh_key pubkey)726 static int ssh_userauth_agent_publickey(ssh_session session,
727                                         const char *username,
728                                         ssh_key pubkey)
729 {
730     ssh_string pubkey_s = NULL;
731     ssh_string sig_blob = NULL;
732     const char *sig_type_c = NULL;
733     int rc;
734 
735     switch(session->pending_call_state) {
736         case SSH_PENDING_CALL_NONE:
737             break;
738         case SSH_PENDING_CALL_AUTH_AGENT:
739             goto pending;
740         default:
741             ssh_set_error(session,
742                           SSH_FATAL,
743                           "Bad call during pending SSH call in ssh_userauth_try_publickey");
744             return SSH_ERROR;
745     }
746 
747     rc = ssh_userauth_request_service(session);
748     if (rc == SSH_AGAIN) {
749         return SSH_AUTH_AGAIN;
750     } else if (rc == SSH_ERROR) {
751         return SSH_AUTH_ERROR;
752     }
753 
754     /* public key */
755     rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_s);
756     if (rc < 0) {
757         goto fail;
758     }
759 
760     /* Check if the given public key algorithm is allowed */
761     sig_type_c = ssh_key_get_signature_algorithm(session, pubkey->type);
762     if (sig_type_c == NULL) {
763         ssh_set_error(session, SSH_REQUEST_DENIED,
764                       "Invalid key type (unknown)");
765         SSH_STRING_FREE(pubkey_s);
766         return SSH_AUTH_DENIED;
767     }
768     if (!ssh_key_algorithm_allowed(session, sig_type_c)) {
769         ssh_set_error(session, SSH_REQUEST_DENIED,
770                       "The key algorithm '%s' is not allowed to be used by"
771                       " PUBLICKEY_ACCEPTED_TYPES configuration option",
772                       sig_type_c);
773         SSH_STRING_FREE(pubkey_s);
774         return SSH_AUTH_DENIED;
775     }
776 
777     /* request */
778     rc = ssh_buffer_pack(session->out_buffer, "bsssbsS",
779             SSH2_MSG_USERAUTH_REQUEST,
780             username ? username : session->opts.username,
781             "ssh-connection",
782             "publickey",
783             1, /* private key */
784             sig_type_c, /* algo */
785             pubkey_s /* public key */
786             );
787     SSH_STRING_FREE(pubkey_s);
788     if (rc < 0) {
789         goto fail;
790     }
791 
792     /* sign the buffer with the private key */
793     sig_blob = ssh_pki_do_sign_agent(session, session->out_buffer, pubkey);
794     if (sig_blob == NULL) {
795         goto fail;
796     }
797 
798     rc = ssh_buffer_add_ssh_string(session->out_buffer, sig_blob);
799     SSH_STRING_FREE(sig_blob);
800     if (rc < 0) {
801         goto fail;
802     }
803 
804     session->auth.current_method = SSH_AUTH_METHOD_PUBLICKEY;
805     session->auth.state = SSH_AUTH_STATE_PUBKEY_AUTH_SENT;
806     session->pending_call_state = SSH_PENDING_CALL_AUTH_AGENT;
807     rc = ssh_packet_send(session);
808     if (rc == SSH_ERROR) {
809         return SSH_AUTH_ERROR;
810     }
811 
812 pending:
813     rc = ssh_userauth_get_response(session);
814     if (rc != SSH_AUTH_AGAIN) {
815         session->pending_call_state = SSH_PENDING_CALL_NONE;
816     }
817 
818     return rc;
819 fail:
820     ssh_set_error_oom(session);
821     ssh_buffer_reinit(session->out_buffer);
822     SSH_STRING_FREE(pubkey_s);
823 
824     return SSH_AUTH_ERROR;
825 }
826 
827 enum ssh_agent_state_e {
828     SSH_AGENT_STATE_NONE = 0,
829     SSH_AGENT_STATE_PUBKEY,
830     SSH_AGENT_STATE_AUTH
831 };
832 
833 struct ssh_agent_state_struct {
834     enum ssh_agent_state_e state;
835     ssh_key pubkey;
836     char *comment;
837 };
838 
839 /* Internal function */
ssh_agent_state_free(void * data)840 void ssh_agent_state_free(void *data) {
841     struct ssh_agent_state_struct *state = data;
842 
843     if (state) {
844         SSH_STRING_FREE_CHAR(state->comment);
845         ssh_key_free(state->pubkey);
846         free (state);
847     }
848 }
849 
850 /**
851  * @brief Try to do public key authentication with ssh agent.
852  *
853  * @param[in]  session  The ssh session to use.
854  *
855  * @param[in]  username The username, this SHOULD be NULL.
856  *
857  * @return  SSH_AUTH_ERROR:   A serious error happened.\n
858  *          SSH_AUTH_DENIED:  The server doesn't accept that public key as an
859  *                            authentication token. Try another key or another
860  *                            method.\n
861  *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
862  *                            have to use another method.\n
863  *          SSH_AUTH_SUCCESS: The public key is accepted, you want now to use
864  *                            ssh_userauth_publickey().\n
865  *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
866  *                            later.
867  *
868  * @note Most server implementations do not permit changing the username during
869  * authentication. The username should only be set with ssh_options_set() only
870  * before you connect to the server.
871  */
ssh_userauth_agent(ssh_session session,const char * username)872 int ssh_userauth_agent(ssh_session session,
873                        const char *username) {
874     int rc = SSH_AUTH_ERROR;
875     struct ssh_agent_state_struct *state;
876 
877     if (session == NULL) {
878         return SSH_AUTH_ERROR;
879     }
880 
881     if (!ssh_agent_is_running(session)) {
882         return SSH_AUTH_DENIED;
883     }
884 
885     if (!session->agent_state) {
886         session->agent_state = malloc(sizeof(struct ssh_agent_state_struct));
887         if (!session->agent_state) {
888             ssh_set_error_oom(session);
889             return SSH_AUTH_ERROR;
890         }
891         ZERO_STRUCTP(session->agent_state);
892         session->agent_state->state=SSH_AGENT_STATE_NONE;
893     }
894 
895     state = session->agent_state;
896     if (state->pubkey == NULL) {
897         state->pubkey = ssh_agent_get_first_ident(session, &state->comment);
898     }
899 
900     if (state->pubkey == NULL) {
901         return SSH_AUTH_DENIED;
902     }
903 
904     while (state->pubkey != NULL) {
905         if (state->state == SSH_AGENT_STATE_NONE) {
906             SSH_LOG(SSH_LOG_DEBUG,
907                     "Trying identity %s", state->comment);
908         }
909         if (state->state == SSH_AGENT_STATE_NONE ||
910                 state->state == SSH_AGENT_STATE_PUBKEY) {
911             rc = ssh_userauth_try_publickey(session, username, state->pubkey);
912             if (rc == SSH_AUTH_ERROR) {
913                 ssh_agent_state_free (state);
914                 session->agent_state = NULL;
915                 return rc;
916             } else if (rc == SSH_AUTH_AGAIN) {
917                 state->state = SSH_AGENT_STATE_PUBKEY;
918                 return rc;
919             } else if (rc != SSH_AUTH_SUCCESS) {
920                 SSH_LOG(SSH_LOG_DEBUG,
921                         "Public key of %s refused by server", state->comment);
922                 SSH_STRING_FREE_CHAR(state->comment);
923                 state->comment = NULL;
924                 ssh_key_free(state->pubkey);
925                 state->pubkey = ssh_agent_get_next_ident(session, &state->comment);
926                 state->state = SSH_AGENT_STATE_NONE;
927                 continue;
928             }
929 
930             SSH_LOG(SSH_LOG_DEBUG,
931                     "Public key of %s accepted by server", state->comment);
932             state->state = SSH_AGENT_STATE_AUTH;
933         }
934         if (state->state == SSH_AGENT_STATE_AUTH) {
935             rc = ssh_userauth_agent_publickey(session, username, state->pubkey);
936             if (rc == SSH_AUTH_AGAIN)
937                 return rc;
938             SSH_STRING_FREE_CHAR(state->comment);
939             state->comment = NULL;
940             if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_PARTIAL) {
941                 ssh_agent_state_free (session->agent_state);
942                 session->agent_state = NULL;
943                 return rc;
944             } else if (rc != SSH_AUTH_SUCCESS) {
945                 SSH_LOG(SSH_LOG_INFO,
946                         "Server accepted public key but refused the signature");
947                 ssh_key_free(state->pubkey);
948                 state->pubkey = ssh_agent_get_next_ident(session, &state->comment);
949                 state->state = SSH_AGENT_STATE_NONE;
950                 continue;
951             }
952             ssh_agent_state_free (session->agent_state);
953             session->agent_state = NULL;
954             return SSH_AUTH_SUCCESS;
955         }
956     }
957 
958     ssh_agent_state_free (session->agent_state);
959     session->agent_state = NULL;
960     return rc;
961 }
962 #endif
963 
964 enum ssh_auth_auto_state_e {
965     SSH_AUTH_AUTO_STATE_NONE = 0,
966     SSH_AUTH_AUTO_STATE_PUBKEY,
967     SSH_AUTH_AUTO_STATE_KEY_IMPORTED,
968     SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED
969 };
970 
971 struct ssh_auth_auto_state_struct {
972     enum ssh_auth_auto_state_e state;
973     struct ssh_iterator *it;
974     ssh_key privkey;
975     ssh_key pubkey;
976 };
977 
978 /**
979  * @brief Tries to automatically authenticate with public key and "none"
980  *
981  * It may fail, for instance it doesn't ask for a password and uses a default
982  * asker for passphrases (in case the private key is encrypted).
983  *
984  * @param[in]  session     The SSH session.
985  *
986  * @param[in]  username    The username, this SHOULD be NULL.
987  *
988  * @param[in]  passphrase  Use this passphrase to unlock the privatekey. Use NULL
989  *                         if you don't want to use a passphrase or the user
990  *                         should be asked.
991  *
992  * @return  SSH_AUTH_ERROR:   A serious error happened.\n
993  *          SSH_AUTH_DENIED:  The server doesn't accept that public key as an
994  *                            authentication token. Try another key or another
995  *                            method.\n
996  *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
997  *                            have to use another method.\n
998  *          SSH_AUTH_SUCCESS: The public key is accepted, you want now to use
999  *                            ssh_userauth_publickey().\n
1000  *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
1001  *                            later.
1002  *
1003  * @note Most server implementations do not permit changing the username during
1004  * authentication. The username should only be set with ssh_options_set() only
1005  * before you connect to the server.
1006  */
ssh_userauth_publickey_auto(ssh_session session,const char * username,const char * passphrase)1007 int ssh_userauth_publickey_auto(ssh_session session,
1008                                 const char *username,
1009                                 const char *passphrase)
1010 {
1011     ssh_auth_callback auth_fn = NULL;
1012     void *auth_data = NULL;
1013     struct ssh_auth_auto_state_struct *state;
1014     int rc;
1015 
1016     if (session == NULL) {
1017         return SSH_AUTH_ERROR;
1018     }
1019     if (! (session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH)) {
1020         session->auth.supported_methods &= ~SSH_AUTH_METHOD_PUBLICKEY;
1021         return SSH_AUTH_DENIED;
1022     }
1023     if (session->common.callbacks) {
1024         auth_fn = session->common.callbacks->auth_function;
1025         auth_data = session->common.callbacks->userdata;
1026     }
1027     if (!session->auth.auto_state) {
1028         session->auth.auto_state =
1029                 calloc(1, sizeof(struct ssh_auth_auto_state_struct));
1030         if (!session->auth.auto_state) {
1031             ssh_set_error_oom(session);
1032             return SSH_AUTH_ERROR;
1033         }
1034 
1035         /* Set state explicitly */
1036         session->auth.auto_state->state = SSH_AUTH_AUTO_STATE_NONE;
1037     }
1038     state = session->auth.auto_state;
1039     if (state->state == SSH_AUTH_AUTO_STATE_NONE) {
1040 #ifndef _WIN32
1041         /* Try authentication with ssh-agent first */
1042         rc = ssh_userauth_agent(session, username);
1043         if (rc == SSH_AUTH_SUCCESS ||
1044             rc == SSH_AUTH_PARTIAL ||
1045             rc == SSH_AUTH_AGAIN ) {
1046             return rc;
1047         }
1048 #endif
1049         state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1050     }
1051     if (state->it == NULL) {
1052         state->it = ssh_list_get_iterator(session->opts.identity);
1053     }
1054 
1055     while (state->it != NULL) {
1056         const char *privkey_file = state->it->data;
1057         char pubkey_file[1024] = {0};
1058         if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY) {
1059             SSH_LOG(SSH_LOG_DEBUG,
1060                     "Trying to authenticate with %s", privkey_file);
1061             state->privkey = NULL;
1062             state->pubkey = NULL;
1063             snprintf(pubkey_file, sizeof(pubkey_file), "%s.pub", privkey_file);
1064 
1065             rc = ssh_pki_import_pubkey_file(pubkey_file, &state->pubkey);
1066             if (rc == SSH_ERROR) {
1067                 ssh_set_error(session,
1068                         SSH_FATAL,
1069                         "Failed to import public key: %s",
1070                         pubkey_file);
1071                 SAFE_FREE(session->auth.auto_state);
1072                 return SSH_AUTH_ERROR;
1073             } else if (rc == SSH_EOF) {
1074                 /* Read the private key and save the public key to file */
1075                 rc = ssh_pki_import_privkey_file(privkey_file,
1076                         passphrase,
1077                         auth_fn,
1078                         auth_data,
1079                         &state->privkey);
1080                 if (rc == SSH_ERROR) {
1081                     ssh_set_error(session,
1082                             SSH_FATAL,
1083                             "Failed to read private key: %s",
1084                             privkey_file);
1085                     state->it=state->it->next;
1086                     continue;
1087                 } else if (rc == SSH_EOF) {
1088                     /* If the file doesn't exist, continue */
1089                     SSH_LOG(SSH_LOG_DEBUG,
1090                             "Private key %s doesn't exist.",
1091                             privkey_file);
1092                     state->it=state->it->next;
1093                     continue;
1094                 }
1095 
1096                 rc = ssh_pki_export_privkey_to_pubkey(state->privkey, &state->pubkey);
1097                 if (rc == SSH_ERROR) {
1098                     ssh_key_free(state->privkey);
1099                     SAFE_FREE(session->auth.auto_state);
1100                     return SSH_AUTH_ERROR;
1101                 }
1102 
1103                 rc = ssh_pki_export_pubkey_file(state->pubkey, pubkey_file);
1104                 if (rc == SSH_ERROR) {
1105                     SSH_LOG(SSH_LOG_WARN,
1106                             "Could not write public key to file: %s",
1107                             pubkey_file);
1108                 }
1109             }
1110             state->state = SSH_AUTH_AUTO_STATE_KEY_IMPORTED;
1111         }
1112         if (state->state == SSH_AUTH_AUTO_STATE_KEY_IMPORTED) {
1113             rc = ssh_userauth_try_publickey(session, username, state->pubkey);
1114             if (rc == SSH_AUTH_ERROR) {
1115                 SSH_LOG(SSH_LOG_WARN,
1116                         "Public key authentication error for %s",
1117                         privkey_file);
1118                 ssh_key_free(state->privkey);
1119                 state->privkey = NULL;
1120                 ssh_key_free(state->pubkey);
1121                 state->pubkey = NULL;
1122                 SAFE_FREE(session->auth.auto_state);
1123                 return rc;
1124             } else if (rc == SSH_AUTH_AGAIN) {
1125                 return rc;
1126             } else if (rc != SSH_AUTH_SUCCESS) {
1127                 SSH_LOG(SSH_LOG_DEBUG,
1128                         "Public key for %s refused by server",
1129                         privkey_file);
1130                 ssh_key_free(state->privkey);
1131                 state->privkey = NULL;
1132                 ssh_key_free(state->pubkey);
1133                 state->pubkey = NULL;
1134                 state->it=state->it->next;
1135                 state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1136                 continue;
1137             }
1138             state->state = SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED;
1139         }
1140         if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED) {
1141             /* Public key has been accepted by the server */
1142             if (state->privkey == NULL) {
1143                 rc = ssh_pki_import_privkey_file(privkey_file,
1144                         passphrase,
1145                         auth_fn,
1146                         auth_data,
1147                         &state->privkey);
1148                 if (rc == SSH_ERROR) {
1149                     ssh_key_free(state->pubkey);
1150                     state->pubkey=NULL;
1151                     ssh_set_error(session,
1152                             SSH_FATAL,
1153                             "Failed to read private key: %s",
1154                             privkey_file);
1155                     state->it=state->it->next;
1156                     state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1157                     continue;
1158                 } else if (rc == SSH_EOF) {
1159                     /* If the file doesn't exist, continue */
1160                     ssh_key_free(state->pubkey);
1161                     state->pubkey = NULL;
1162                     SSH_LOG(SSH_LOG_INFO,
1163                             "Private key %s doesn't exist.",
1164                             privkey_file);
1165                     state->it = state->it->next;
1166                     state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1167                     continue;
1168                 }
1169             }
1170 
1171             rc = ssh_userauth_publickey(session, username, state->privkey);
1172             if (rc != SSH_AUTH_AGAIN && rc != SSH_AUTH_DENIED) {
1173                 ssh_key_free(state->privkey);
1174                 ssh_key_free(state->pubkey);
1175                 SAFE_FREE(session->auth.auto_state);
1176                 if (rc == SSH_AUTH_SUCCESS) {
1177                     SSH_LOG(SSH_LOG_INFO,
1178                             "Successfully authenticated using %s",
1179                             privkey_file);
1180                 }
1181                 return rc;
1182             }
1183             if (rc == SSH_AUTH_AGAIN) {
1184                 return rc;
1185             }
1186 
1187             ssh_key_free(state->privkey);
1188             ssh_key_free(state->pubkey);
1189 
1190             SSH_LOG(SSH_LOG_WARN,
1191                     "The server accepted the public key but refused the signature");
1192             state->it = state->it->next;
1193             state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1194             /* continue */
1195         }
1196     }
1197     SSH_LOG(SSH_LOG_INFO,
1198             "Tried every public key, none matched");
1199     SAFE_FREE(session->auth.auto_state);
1200     return SSH_AUTH_DENIED;
1201 }
1202 
1203 /**
1204  * @brief Try to authenticate by password.
1205  *
1206  * This authentication method is normally disabled on SSHv2 server. You should
1207  * use keyboard-interactive mode.
1208  *
1209  * The 'password' value MUST be encoded UTF-8.  It is up to the server how to
1210  * interpret the password and validate it against the password database.
1211  * However, if you read the password in some other encoding, you MUST convert
1212  * the password to UTF-8.
1213  *
1214  * @param[in] session   The ssh session to use.
1215  *
1216  * @param[in] username  The username, this SHOULD be NULL.
1217  *
1218  * @param[in] password  The password to authenticate in UTF-8.
1219  *
1220  * @returns SSH_AUTH_ERROR:   A serious error happened.\n
1221  *          SSH_AUTH_DENIED:  Authentication failed: use another method\n
1222  *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
1223  *                            have to use another method\n
1224  *          SSH_AUTH_SUCCESS: Authentication success\n
1225  *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
1226  *                            later.
1227  *
1228  * @note Most server implementations do not permit changing the username during
1229  * authentication. The username should only be set with ssh_options_set() only
1230  * before you connect to the server.
1231  *
1232  * @see ssh_userauth_none()
1233  * @see ssh_userauth_kbdint()
1234  */
ssh_userauth_password(ssh_session session,const char * username,const char * password)1235 int ssh_userauth_password(ssh_session session,
1236                           const char *username,
1237                           const char *password) {
1238     int rc;
1239 
1240     switch(session->pending_call_state) {
1241         case SSH_PENDING_CALL_NONE:
1242             break;
1243         case SSH_PENDING_CALL_AUTH_PASSWORD:
1244             goto pending;
1245         default:
1246             ssh_set_error(session,
1247                           SSH_FATAL,
1248                           "Wrong state (%d) during pending SSH call",
1249                           session->pending_call_state);
1250             return SSH_ERROR;
1251     }
1252 
1253     rc = ssh_userauth_request_service(session);
1254     if (rc == SSH_AGAIN) {
1255         return SSH_AUTH_AGAIN;
1256     } else if (rc == SSH_ERROR) {
1257         return SSH_AUTH_ERROR;
1258     }
1259 
1260     /* request */
1261     rc = ssh_buffer_pack(session->out_buffer, "bsssbs",
1262             SSH2_MSG_USERAUTH_REQUEST,
1263             username ? username : session->opts.username,
1264             "ssh-connection",
1265             "password",
1266             0, /* false */
1267             password
1268     );
1269     if (rc < 0) {
1270         goto fail;
1271     }
1272 
1273     /* Set the buffer as secure to be explicitly zeroed when freed */
1274     ssh_buffer_set_secure(session->out_buffer);
1275 
1276     session->auth.current_method = SSH_AUTH_METHOD_PASSWORD;
1277     session->auth.state = SSH_AUTH_STATE_PASSWORD_AUTH_SENT;
1278     session->pending_call_state = SSH_PENDING_CALL_AUTH_PASSWORD;
1279     rc = ssh_packet_send(session);
1280     if (rc == SSH_ERROR) {
1281         return SSH_AUTH_ERROR;
1282     }
1283 
1284 pending:
1285     rc = ssh_userauth_get_response(session);
1286     if (rc != SSH_AUTH_AGAIN) {
1287         session->pending_call_state = SSH_PENDING_CALL_NONE;
1288     }
1289 
1290     return rc;
1291 fail:
1292     ssh_set_error_oom(session);
1293     ssh_buffer_reinit(session->out_buffer);
1294 
1295     return SSH_AUTH_ERROR;
1296 }
1297 
1298 #ifndef _WIN32
1299 /* LEGACY */
ssh_userauth_agent_pubkey(ssh_session session,const char * username,ssh_public_key publickey)1300 int ssh_userauth_agent_pubkey(ssh_session session,
1301                               const char *username,
1302                               ssh_public_key publickey)
1303 {
1304     ssh_key key;
1305     int rc;
1306 
1307     key = ssh_key_new();
1308     if (key == NULL) {
1309         return SSH_AUTH_ERROR;
1310     }
1311 
1312     key->type = publickey->type;
1313     key->type_c = ssh_key_type_to_char(key->type);
1314     key->flags = SSH_KEY_FLAG_PUBLIC;
1315     key->dsa = publickey->dsa_pub;
1316     key->rsa = publickey->rsa_pub;
1317 
1318     rc = ssh_userauth_agent_publickey(session, username, key);
1319 
1320     key->dsa = NULL;
1321     key->rsa = NULL;
1322     ssh_key_free(key);
1323 
1324     return rc;
1325 }
1326 #endif /* _WIN32 */
1327 
ssh_kbdint_new(void)1328 ssh_kbdint ssh_kbdint_new(void) {
1329     ssh_kbdint kbd;
1330 
1331     kbd = calloc(1, sizeof(struct ssh_kbdint_struct));
1332     if (kbd == NULL) {
1333         return NULL;
1334     }
1335 
1336     return kbd;
1337 }
1338 
1339 
ssh_kbdint_free(ssh_kbdint kbd)1340 void ssh_kbdint_free(ssh_kbdint kbd) {
1341     size_t i, n;
1342 
1343     if (kbd == NULL) {
1344         return;
1345     }
1346 
1347     SAFE_FREE(kbd->name);
1348     SAFE_FREE(kbd->instruction);
1349     SAFE_FREE(kbd->echo);
1350 
1351     n = kbd->nprompts;
1352     if (kbd->prompts) {
1353         for (i = 0; i < n; i++) {
1354             if (kbd->prompts[i] != NULL) {
1355                 explicit_bzero(kbd->prompts[i], strlen(kbd->prompts[i]));
1356             }
1357             SAFE_FREE(kbd->prompts[i]);
1358         }
1359         SAFE_FREE(kbd->prompts);
1360     }
1361 
1362     n = kbd->nanswers;
1363     if (kbd->answers) {
1364         for (i = 0; i < n; i++) {
1365             if (kbd->answers[i] != NULL) {
1366                 explicit_bzero(kbd->answers[i], strlen(kbd->answers[i]));
1367             }
1368             SAFE_FREE(kbd->answers[i]);
1369         }
1370         SAFE_FREE(kbd->answers);
1371     }
1372 
1373     SAFE_FREE(kbd);
1374 }
1375 
ssh_kbdint_clean(ssh_kbdint kbd)1376 void ssh_kbdint_clean(ssh_kbdint kbd) {
1377     size_t i, n;
1378 
1379     if (kbd == NULL) {
1380         return;
1381     }
1382 
1383     SAFE_FREE(kbd->name);
1384     SAFE_FREE(kbd->instruction);
1385     SAFE_FREE(kbd->echo);
1386 
1387     n = kbd->nprompts;
1388     if (kbd->prompts) {
1389         for (i = 0; i < n; i++) {
1390             explicit_bzero(kbd->prompts[i], strlen(kbd->prompts[i]));
1391             SAFE_FREE(kbd->prompts[i]);
1392         }
1393         SAFE_FREE(kbd->prompts);
1394     }
1395 
1396     n = kbd->nanswers;
1397 
1398     if (kbd->answers) {
1399         for (i = 0; i < n; i++) {
1400             explicit_bzero(kbd->answers[i], strlen(kbd->answers[i]));
1401             SAFE_FREE(kbd->answers[i]);
1402         }
1403         SAFE_FREE(kbd->answers);
1404     }
1405 
1406     kbd->nprompts = 0;
1407     kbd->nanswers = 0;
1408 }
1409 
1410 /*
1411  * This function sends the first packet as explained in RFC 3066 section 3.1.
1412  */
ssh_userauth_kbdint_init(ssh_session session,const char * username,const char * submethods)1413 static int ssh_userauth_kbdint_init(ssh_session session,
1414                                     const char *username,
1415                                     const char *submethods)
1416 {
1417     int rc;
1418 
1419     if (session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_INIT) {
1420         goto pending;
1421     }
1422     if (session->pending_call_state != SSH_PENDING_CALL_NONE) {
1423         ssh_set_error_invalid(session);
1424         return SSH_ERROR;
1425     }
1426 
1427     rc = ssh_userauth_request_service(session);
1428     if (rc == SSH_AGAIN) {
1429         return SSH_AUTH_AGAIN;
1430     }
1431     if (rc != SSH_OK) {
1432         return SSH_AUTH_ERROR;
1433     }
1434 
1435     /* request */
1436     rc = ssh_buffer_pack(session->out_buffer, "bsssss",
1437             SSH2_MSG_USERAUTH_REQUEST,
1438             username ? username : session->opts.username,
1439             "ssh-connection",
1440             "keyboard-interactive",
1441             "", /* lang (ignore it) */
1442             submethods ? submethods : ""
1443     );
1444     if (rc < 0) {
1445         goto fail;
1446     }
1447 
1448 
1449     session->auth.state = SSH_AUTH_STATE_KBDINT_SENT;
1450     session->pending_call_state = SSH_PENDING_CALL_AUTH_KBDINT_INIT;
1451 
1452     SSH_LOG(SSH_LOG_DEBUG,
1453             "Sending keyboard-interactive init request");
1454 
1455     rc = ssh_packet_send(session);
1456     if (rc == SSH_ERROR) {
1457         return SSH_AUTH_ERROR;
1458     }
1459 pending:
1460     rc = ssh_userauth_get_response(session);
1461     if (rc != SSH_AUTH_AGAIN)
1462         session->pending_call_state = SSH_PENDING_CALL_NONE;
1463     return rc;
1464 fail:
1465     ssh_set_error_oom(session);
1466     ssh_buffer_reinit(session->out_buffer);
1467 
1468     return SSH_AUTH_ERROR;
1469 }
1470 
1471 /**
1472  * @internal
1473  *
1474  * @brief Send the current challenge response and wait for a reply from the
1475  *        server.
1476  *
1477  * @returns SSH_AUTH_INFO if more info is needed
1478  * @returns SSH_AUTH_SUCCESS
1479  * @returns SSH_AUTH_FAILURE
1480  * @returns SSH_AUTH_PARTIAL
1481  */
ssh_userauth_kbdint_send(ssh_session session)1482 static int ssh_userauth_kbdint_send(ssh_session session)
1483 {
1484     uint32_t i;
1485     int rc;
1486     if (session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_SEND)
1487         goto pending;
1488     if (session->pending_call_state != SSH_PENDING_CALL_NONE) {
1489         ssh_set_error_invalid(session);
1490         return SSH_ERROR;
1491     }
1492     rc = ssh_buffer_pack(session->out_buffer, "bd",
1493             SSH2_MSG_USERAUTH_INFO_RESPONSE,
1494             session->kbdint->nprompts);
1495     if (rc < 0) {
1496         goto fail;
1497     }
1498 
1499     for (i = 0; i < session->kbdint->nprompts; i++) {
1500         rc = ssh_buffer_pack(session->out_buffer, "s",
1501                 session->kbdint->answers && session->kbdint->answers[i] ?
1502                         session->kbdint->answers[i]:"");
1503         if (rc < 0) {
1504             goto fail;
1505         }
1506     }
1507 
1508     session->auth.current_method = SSH_AUTH_METHOD_INTERACTIVE;
1509     session->auth.state = SSH_AUTH_STATE_KBDINT_SENT;
1510     session->pending_call_state = SSH_PENDING_CALL_AUTH_KBDINT_SEND;
1511     ssh_kbdint_free(session->kbdint);
1512     session->kbdint = NULL;
1513 
1514     SSH_LOG(SSH_LOG_DEBUG,
1515             "Sending keyboard-interactive response packet");
1516 
1517     rc = ssh_packet_send(session);
1518     if (rc == SSH_ERROR) {
1519         return SSH_AUTH_ERROR;
1520     }
1521 pending:
1522     rc = ssh_userauth_get_response(session);
1523     if (rc != SSH_AUTH_AGAIN)
1524         session->pending_call_state = SSH_PENDING_CALL_NONE;
1525     return rc;
1526 fail:
1527     ssh_set_error_oom(session);
1528     ssh_buffer_reinit(session->out_buffer);
1529 
1530     return SSH_AUTH_ERROR;
1531 }
1532 
1533 /**
1534  * @internal
1535  * @brief handles a SSH_USERAUTH_INFO_REQUEST packet, as used in
1536  *        keyboard-interactive authentication, and changes the
1537  *        authentication state.
1538  */
SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request)1539 SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) {
1540     ssh_string tmp = NULL;
1541     uint32_t nprompts;
1542     uint32_t i;
1543     int rc;
1544     (void)user;
1545     (void)type;
1546 
1547 
1548     if (session->kbdint == NULL) {
1549         session->kbdint = ssh_kbdint_new();
1550         if (session->kbdint == NULL) {
1551             ssh_set_error_oom(session);
1552             return SSH_PACKET_USED;
1553         }
1554     } else {
1555         ssh_kbdint_clean(session->kbdint);
1556     }
1557 
1558     rc = ssh_buffer_unpack(packet, "ssSd",
1559             &session->kbdint->name, /* name of the "asking" window shown to client */
1560             &session->kbdint->instruction,
1561             &tmp, /* to ignore */
1562             &nprompts
1563             );
1564 
1565     /* We don't care about tmp */
1566     SSH_STRING_FREE(tmp);
1567 
1568     if (rc != SSH_OK) {
1569         ssh_set_error(session, SSH_FATAL, "Invalid USERAUTH_INFO_REQUEST msg");
1570         ssh_kbdint_free(session->kbdint);
1571         session->kbdint = NULL;
1572         return SSH_PACKET_USED;
1573     }
1574 
1575     SSH_LOG(SSH_LOG_DEBUG,
1576             "%d keyboard-interactive prompts", nprompts);
1577     if (nprompts > KBDINT_MAX_PROMPT) {
1578         ssh_set_error(session, SSH_FATAL,
1579                 "Too much prompts requested by the server: %u (0x%.4x)",
1580                 nprompts, nprompts);
1581         ssh_kbdint_free(session->kbdint);
1582         session->kbdint = NULL;
1583 
1584         return SSH_PACKET_USED;
1585     }
1586 
1587     session->kbdint->nprompts = nprompts;
1588     session->kbdint->nanswers = nprompts;
1589     session->kbdint->prompts = calloc(nprompts, sizeof(char *));
1590     if (session->kbdint->prompts == NULL) {
1591         session->kbdint->nprompts = 0;
1592         ssh_set_error_oom(session);
1593         ssh_kbdint_free(session->kbdint);
1594         session->kbdint = NULL;
1595 
1596         return SSH_PACKET_USED;
1597     }
1598 
1599     session->kbdint->echo = calloc(nprompts, sizeof(unsigned char));
1600     if (session->kbdint->echo == NULL) {
1601         session->kbdint->nprompts = 0;
1602         ssh_set_error_oom(session);
1603         ssh_kbdint_free(session->kbdint);
1604         session->kbdint = NULL;
1605 
1606         return SSH_PACKET_USED;
1607     }
1608 
1609     for (i = 0; i < nprompts; i++) {
1610         rc = ssh_buffer_unpack(packet, "sb",
1611                 &session->kbdint->prompts[i],
1612                 &session->kbdint->echo[i]);
1613         if (rc == SSH_ERROR) {
1614             ssh_set_error(session, SSH_FATAL, "Short INFO_REQUEST packet");
1615             ssh_kbdint_free(session->kbdint);
1616             session->kbdint = NULL;
1617 
1618             return SSH_PACKET_USED;
1619         }
1620     }
1621     session->auth.state=SSH_AUTH_STATE_INFO;
1622 
1623     return SSH_PACKET_USED;
1624 }
1625 
1626 /**
1627  * @brief Try to authenticate through the "keyboard-interactive" method.
1628  *
1629  * @param[in]  session  The ssh session to use.
1630  *
1631  * @param[in]  user     The username to authenticate. You can specify NULL if
1632  *                      ssh_option_set_username() has been used. You cannot try
1633  *                      two different logins in a row.
1634  *
1635  * @param[in]  submethods Undocumented. Set it to NULL.
1636  *
1637  * @returns SSH_AUTH_ERROR:   A serious error happened\n
1638  *          SSH_AUTH_DENIED:  Authentication failed : use another method\n
1639  *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
1640  *                            have to use another method\n
1641  *          SSH_AUTH_SUCCESS: Authentication success\n
1642  *          SSH_AUTH_INFO:    The server asked some questions. Use
1643  *                            ssh_userauth_kbdint_getnprompts() and such.\n
1644  *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
1645  *                            later.
1646  *
1647  * @see ssh_userauth_kbdint_getnprompts()
1648  * @see ssh_userauth_kbdint_getname()
1649  * @see ssh_userauth_kbdint_getinstruction()
1650  * @see ssh_userauth_kbdint_getprompt()
1651  * @see ssh_userauth_kbdint_setanswer()
1652  */
ssh_userauth_kbdint(ssh_session session,const char * user,const char * submethods)1653 int ssh_userauth_kbdint(ssh_session session, const char *user,
1654     const char *submethods) {
1655     int rc = SSH_AUTH_ERROR;
1656 
1657     if (session == NULL) {
1658         return SSH_AUTH_ERROR;
1659     }
1660 
1661     if ((session->pending_call_state == SSH_PENDING_CALL_NONE && session->kbdint == NULL) ||
1662             session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_INIT)
1663         rc = ssh_userauth_kbdint_init(session, user, submethods);
1664     else if (session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_SEND ||
1665             session->kbdint != NULL) {
1666         /*
1667          * If we are at this point, it is because session->kbdint exists.
1668          * It means the user has set some information there we need to send
1669          * the server and then we need to ack the status (new questions or ok
1670          * pass in).
1671          * It is possible that session->kbdint is NULL while we're waiting for
1672          * a reply, hence the test for the pending call.
1673          */
1674         rc = ssh_userauth_kbdint_send(session);
1675     } else {
1676         /* We are here because session->kbdint == NULL & state != NONE.
1677          * This should not happen
1678          */
1679         rc = SSH_AUTH_ERROR;
1680         ssh_set_error(session, SSH_FATAL, "Invalid state in %s", __func__);
1681     }
1682     return rc;
1683 }
1684 
1685 /**
1686  * @brief Get the number of prompts (questions) the server has given.
1687  *
1688  * Once you have called ssh_userauth_kbdint() and received SSH_AUTH_INFO return
1689  * code, this function can be used to retrieve information about the keyboard
1690  * interactive authentication questions sent by the remote host.
1691  *
1692  * @param[in]  session  The ssh session to use.
1693  *
1694  * @returns             The number of prompts.
1695  */
ssh_userauth_kbdint_getnprompts(ssh_session session)1696 int ssh_userauth_kbdint_getnprompts(ssh_session session) {
1697     if (session == NULL) {
1698         return SSH_ERROR;
1699     }
1700     if (session->kbdint == NULL) {
1701         ssh_set_error_invalid(session);
1702         return SSH_ERROR;
1703     }
1704     return session->kbdint->nprompts;
1705 }
1706 
1707 /**
1708  * @brief Get the "name" of the message block.
1709  *
1710  * Once you have called ssh_userauth_kbdint() and received SSH_AUTH_INFO return
1711  * code, this function can be used to retrieve information about the keyboard
1712  * interactive authentication questions sent by the remote host.
1713  *
1714  * @param[in]  session  The ssh session to use.
1715  *
1716  * @returns             The name of the message block. Do not free it.
1717  */
ssh_userauth_kbdint_getname(ssh_session session)1718 const char *ssh_userauth_kbdint_getname(ssh_session session) {
1719     if (session == NULL) {
1720         return NULL;
1721     }
1722     if (session->kbdint == NULL) {
1723         ssh_set_error_invalid(session);
1724         return NULL;
1725     }
1726     return session->kbdint->name;
1727 }
1728 
1729 /**
1730  * @brief Get the "instruction" of the message block.
1731  *
1732  * Once you have called ssh_userauth_kbdint() and received SSH_AUTH_INFO return
1733  * code, this function can be used to retrieve information about the keyboard
1734  * interactive authentication questions sent by the remote host.
1735  *
1736  * @param[in]  session  The ssh session to use.
1737  *
1738  * @returns             The instruction of the message block.
1739  */
1740 
ssh_userauth_kbdint_getinstruction(ssh_session session)1741 const char *ssh_userauth_kbdint_getinstruction(ssh_session session) {
1742     if (session == NULL)
1743         return NULL;
1744     if (session->kbdint == NULL) {
1745         ssh_set_error_invalid(session);
1746         return NULL;
1747     }
1748     return session->kbdint->instruction;
1749 }
1750 
1751 /**
1752  * @brief Get a prompt from a message block.
1753  *
1754  * Once you have called ssh_userauth_kbdint() and received SSH_AUTH_INFO return
1755  * code, this function can be used to retrieve information about the keyboard
1756  * interactive authentication questions sent by the remote host.
1757  *
1758  * @param[in]  session  The ssh session to use.
1759  *
1760  * @param[in]  i        The index number of the i'th prompt.
1761  *
1762  * @param[out] echo     This is an optional variable. You can obtain a
1763  *                      boolean if the user input should be echoed or
1764  *                      hidden. For passwords it is usually hidden.
1765  *
1766  * @returns             A pointer to the prompt. Do not free it.
1767  *
1768  * @code
1769  *   const char prompt;
1770  *   char echo;
1771  *
1772  *   prompt = ssh_userauth_kbdint_getprompt(session, 0, &echo);
1773  *   if (echo) ...
1774  * @endcode
1775  */
ssh_userauth_kbdint_getprompt(ssh_session session,unsigned int i,char * echo)1776 const char *ssh_userauth_kbdint_getprompt(ssh_session session, unsigned int i,
1777     char *echo) {
1778     if (session == NULL)
1779         return NULL;
1780     if (session->kbdint == NULL) {
1781         ssh_set_error_invalid(session);
1782         return NULL;
1783     }
1784     if (i > session->kbdint->nprompts) {
1785         ssh_set_error_invalid(session);
1786         return NULL;
1787     }
1788 
1789     if (echo) {
1790         *echo = (char)session->kbdint->echo[i];
1791     }
1792 
1793     return session->kbdint->prompts[i];
1794 }
1795 
1796 #ifdef WITH_SERVER
1797 /**
1798  * @brief Get the number of answers the client has given.
1799  *
1800  * @param[in]  session  The ssh session to use.
1801  *
1802  * @returns             The number of answers.
1803  */
ssh_userauth_kbdint_getnanswers(ssh_session session)1804 int ssh_userauth_kbdint_getnanswers(ssh_session session) {
1805     if (session == NULL || session->kbdint == NULL) {
1806         return SSH_ERROR;
1807     }
1808     return session->kbdint->nanswers;
1809 }
1810 
1811 /**
1812  * @brief Get the answer for a question from a message block.
1813  *
1814  * @param[in]  session  The ssh session to use.
1815  *
1816  * @param[in]  i index  The number of the ith answer.
1817  *
1818  * @return              0 on success, < 0 on error.
1819  */
ssh_userauth_kbdint_getanswer(ssh_session session,unsigned int i)1820 const char *ssh_userauth_kbdint_getanswer(ssh_session session, unsigned int i) {
1821     if (session == NULL || session->kbdint == NULL
1822             || session->kbdint->answers == NULL) {
1823         return NULL;
1824     }
1825     if (i >= session->kbdint->nanswers) {
1826         return NULL;
1827     }
1828 
1829     return session->kbdint->answers[i];
1830 }
1831 #endif
1832 
1833 /**
1834  * @brief Set the answer for a question from a message block.
1835  *
1836  * If you have called ssh_userauth_kbdint() and got SSH_AUTH_INFO, this
1837  * function returns the questions from the server.
1838  *
1839  * @param[in]  session  The ssh session to use.
1840  *
1841  * @param[in]  i index  The number of the ith prompt.
1842  *
1843  * @param[in]  answer   The answer to give to the server. The answer MUST be
1844  *                      encoded UTF-8. It is up to the server how to interpret
1845  *                      the value and validate it. However, if you read the
1846  *                      answer in some other encoding, you MUST convert it to
1847  *                      UTF-8.
1848  *
1849  * @return              0 on success, < 0 on error.
1850  */
ssh_userauth_kbdint_setanswer(ssh_session session,unsigned int i,const char * answer)1851 int ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i,
1852     const char *answer) {
1853     if (session == NULL) {
1854         return -1;
1855     }
1856     if (answer == NULL || session->kbdint == NULL ||
1857             i >= session->kbdint->nprompts) {
1858         ssh_set_error_invalid(session);
1859         return -1;
1860     }
1861 
1862     if (session->kbdint->answers == NULL) {
1863         session->kbdint->answers = calloc(session->kbdint->nprompts, sizeof(char *));
1864         if (session->kbdint->answers == NULL) {
1865             ssh_set_error_oom(session);
1866             return -1;
1867         }
1868     }
1869 
1870     if (session->kbdint->answers[i]) {
1871         explicit_bzero(session->kbdint->answers[i],
1872                 strlen(session->kbdint->answers[i]));
1873         SAFE_FREE(session->kbdint->answers[i]);
1874     }
1875 
1876     session->kbdint->answers[i] = strdup(answer);
1877     if (session->kbdint->answers[i] == NULL) {
1878         ssh_set_error_oom(session);
1879         return -1;
1880     }
1881 
1882     return 0;
1883 }
1884 
1885 /**
1886  * @brief Try to authenticate through the "gssapi-with-mic" method.
1887  *
1888  * @param[in]  session  The ssh session to use.
1889  *
1890  * @returns SSH_AUTH_ERROR:   A serious error happened\n
1891  *          SSH_AUTH_DENIED:  Authentication failed : use another method\n
1892  *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
1893  *                            have to use another method\n
1894  *          SSH_AUTH_SUCCESS: Authentication success\n
1895  *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
1896  *                            later.
1897  */
ssh_userauth_gssapi(ssh_session session)1898 int ssh_userauth_gssapi(ssh_session session) {
1899     int rc = SSH_AUTH_DENIED;
1900 #ifdef WITH_GSSAPI
1901     switch(session->pending_call_state) {
1902     case SSH_PENDING_CALL_NONE:
1903         break;
1904     case SSH_PENDING_CALL_AUTH_GSSAPI_MIC:
1905         goto pending;
1906     default:
1907         ssh_set_error(session,
1908                 SSH_FATAL,
1909                 "Wrong state (%d) during pending SSH call",
1910                 session->pending_call_state);
1911         return SSH_ERROR;
1912     }
1913 
1914     rc = ssh_userauth_request_service(session);
1915     if (rc == SSH_AGAIN) {
1916         return SSH_AUTH_AGAIN;
1917     } else if (rc == SSH_ERROR) {
1918         return SSH_AUTH_ERROR;
1919     }
1920     SSH_LOG(SSH_LOG_PROTOCOL, "Authenticating with gssapi-with-mic");
1921 
1922     session->auth.current_method = SSH_AUTH_METHOD_GSSAPI_MIC;
1923     session->auth.state = SSH_AUTH_STATE_NONE;
1924     session->pending_call_state = SSH_PENDING_CALL_AUTH_GSSAPI_MIC;
1925     rc = ssh_gssapi_auth_mic(session);
1926 
1927     if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_DENIED) {
1928         session->auth.state = SSH_AUTH_STATE_NONE;
1929         session->pending_call_state = SSH_PENDING_CALL_NONE;
1930         return rc;
1931     }
1932 
1933 pending:
1934     rc = ssh_userauth_get_response(session);
1935     if (rc != SSH_AUTH_AGAIN) {
1936         session->pending_call_state = SSH_PENDING_CALL_NONE;
1937     }
1938 #else
1939     (void) session; /* unused */
1940 #endif
1941     return rc;
1942 }
1943 
1944 /** @} */
1945