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