Coverage Report

Created: 2025-08-26 07:03

/src/libssh/src/auth.c
Line
Count
Source (jump to first uncovered line)
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 for 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
 */
69
static int ssh_userauth_request_service(ssh_session session)
70
5
{
71
5
    int rc;
72
73
5
    rc = ssh_service_request(session, "ssh-userauth");
74
5
    if ((rc != SSH_OK) && (rc != SSH_AGAIN)) {
75
2
        SSH_LOG(SSH_LOG_TRACE,
76
2
                "Failed to request \"ssh-userauth\" service");
77
2
    }
78
79
5
    return rc;
80
5
}
81
82
static int ssh_auth_response_termination(void *user)
83
32
{
84
32
    ssh_session session = (ssh_session)user;
85
32
    switch (session->auth.state) {
86
0
        case SSH_AUTH_STATE_NONE:
87
0
        case SSH_AUTH_STATE_KBDINT_SENT:
88
0
        case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT:
89
0
        case SSH_AUTH_STATE_GSSAPI_TOKEN:
90
0
        case SSH_AUTH_STATE_GSSAPI_MIC_SENT:
91
0
        case SSH_AUTH_STATE_PUBKEY_AUTH_SENT:
92
0
        case SSH_AUTH_STATE_PUBKEY_OFFER_SENT:
93
0
        case SSH_AUTH_STATE_PASSWORD_AUTH_SENT:
94
32
        case SSH_AUTH_STATE_AUTH_NONE_SENT:
95
32
            return 0;
96
0
        default:
97
0
            return 1;
98
32
    }
99
32
}
100
101
static const char *ssh_auth_get_current_method(ssh_session session)
102
0
{
103
0
    const char *method = "unknown";
104
105
0
    switch (session->auth.current_method) {
106
0
    case SSH_AUTH_METHOD_NONE:
107
0
        method = "none";
108
0
        break;
109
0
    case SSH_AUTH_METHOD_PASSWORD:
110
0
        method = "password";
111
0
        break;
112
0
    case SSH_AUTH_METHOD_PUBLICKEY:
113
0
        method = "publickey";
114
0
        break;
115
0
    case SSH_AUTH_METHOD_HOSTBASED:
116
0
        method = "hostbased";
117
0
        break;
118
0
    case SSH_AUTH_METHOD_INTERACTIVE:
119
0
        method = "keyboard interactive";
120
0
        break;
121
0
    case SSH_AUTH_METHOD_GSSAPI_MIC:
122
0
        method = "gssapi";
123
0
        break;
124
0
    default:
125
0
        break;
126
0
    }
127
128
0
    return method;
129
0
}
130
131
/**
132
 * @internal
133
 * @brief Wait for a response of an authentication function.
134
 *
135
 * @param[in] session   The SSH session.
136
 *
137
 * @returns SSH_AUTH_SUCCESS Authentication success, or pubkey accepted
138
 *          SSH_AUTH_PARTIAL Authentication succeeded but another mean
139
 *                           of authentication is needed.
140
 *          SSH_AUTH_INFO    Data for keyboard-interactive
141
 *          SSH_AUTH_AGAIN   In nonblocking mode, call has to be made again
142
 *          SSH_AUTH_ERROR   Error during the process.
143
 */
144
static int ssh_userauth_get_response(ssh_session session)
145
2
{
146
2
    int rc = SSH_AUTH_ERROR;
147
148
2
    rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER,
149
2
        ssh_auth_response_termination, session);
150
2
    if (rc == SSH_ERROR) {
151
2
        return SSH_AUTH_ERROR;
152
2
    }
153
0
    if (!ssh_auth_response_termination(session)) {
154
0
        return SSH_AUTH_AGAIN;
155
0
    }
156
157
0
    switch(session->auth.state) {
158
0
        case SSH_AUTH_STATE_ERROR:
159
0
            rc = SSH_AUTH_ERROR;
160
0
            break;
161
0
        case SSH_AUTH_STATE_FAILED:
162
0
            rc = SSH_AUTH_DENIED;
163
0
            break;
164
0
        case SSH_AUTH_STATE_INFO:
165
0
            rc = SSH_AUTH_INFO;
166
0
            break;
167
0
        case SSH_AUTH_STATE_PARTIAL:
168
0
            rc = SSH_AUTH_PARTIAL;
169
0
            break;
170
0
        case SSH_AUTH_STATE_PK_OK:
171
0
        case SSH_AUTH_STATE_SUCCESS:
172
0
            rc = SSH_AUTH_SUCCESS;
173
0
            break;
174
0
        case SSH_AUTH_STATE_KBDINT_SENT:
175
0
        case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT:
176
0
        case SSH_AUTH_STATE_GSSAPI_TOKEN:
177
0
        case SSH_AUTH_STATE_GSSAPI_MIC_SENT:
178
0
        case SSH_AUTH_STATE_PUBKEY_OFFER_SENT:
179
0
        case SSH_AUTH_STATE_PUBKEY_AUTH_SENT:
180
0
        case SSH_AUTH_STATE_PASSWORD_AUTH_SENT:
181
0
        case SSH_AUTH_STATE_AUTH_NONE_SENT:
182
0
        case SSH_AUTH_STATE_NONE:
183
            /* not reached */
184
0
            rc = SSH_AUTH_ERROR;
185
0
            break;
186
0
    }
187
188
0
    return rc;
189
0
}
190
191
/**
192
 * @internal
193
 *
194
 * @brief Handles a SSH_USERAUTH_BANNER packet.
195
 *
196
 * This banner should be shown to user prior to authentication
197
 */
198
SSH_PACKET_CALLBACK(ssh_packet_userauth_banner)
199
44
{
200
44
    ssh_string banner = NULL;
201
44
    (void)type;
202
44
    (void)user;
203
204
44
    banner = ssh_buffer_get_ssh_string(packet);
205
44
    if (banner == NULL) {
206
29
        SSH_LOG(SSH_LOG_TRACE,
207
29
                "Invalid SSH_USERAUTH_BANNER packet");
208
29
    } else {
209
15
        SSH_LOG(SSH_LOG_DEBUG,
210
15
                "Received SSH_USERAUTH_BANNER packet");
211
15
        if (session->banner != NULL)
212
10
            SSH_STRING_FREE(session->banner);
213
15
        session->banner = banner;
214
15
    }
215
216
44
    return SSH_PACKET_USED;
217
44
}
218
219
/**
220
 * @internal
221
 *
222
 * @brief Handles a SSH_USERAUTH_FAILURE packet.
223
 *
224
 * This handles the complete or partial authentication failure.
225
 */
226
0
SSH_PACKET_CALLBACK(ssh_packet_userauth_failure) {
227
0
    const char *current_method = ssh_auth_get_current_method(session);
228
0
    char *auth_methods = NULL;
229
0
    uint8_t partial = 0;
230
0
    int rc;
231
0
    (void) type;
232
0
    (void) user;
233
234
0
    rc = ssh_buffer_unpack(packet, "sb", &auth_methods, &partial);
235
0
    if (rc != SSH_OK) {
236
0
        ssh_set_error(session, SSH_FATAL,
237
0
                      "Invalid SSH_MSG_USERAUTH_FAILURE message");
238
0
        session->auth.state = SSH_AUTH_STATE_ERROR;
239
0
        goto end;
240
0
    }
241
242
0
    if (partial) {
243
0
        session->auth.state = SSH_AUTH_STATE_PARTIAL;
244
0
        SSH_LOG(SSH_LOG_DEBUG,
245
0
                "Partial success for '%s'. Authentication that can continue: %s",
246
0
                current_method,
247
0
                auth_methods);
248
0
    } else {
249
0
        session->auth.state = SSH_AUTH_STATE_FAILED;
250
0
        ssh_set_error(session, SSH_REQUEST_DENIED,
251
0
                      "Access denied for '%s'. Authentication that can continue: %s",
252
0
                      current_method,
253
0
                      auth_methods);
254
0
        SSH_LOG(SSH_LOG_DEBUG,
255
0
                "%s",
256
0
                ssh_get_error(session));
257
258
0
    }
259
0
    session->auth.supported_methods = 0;
260
0
    if (strstr(auth_methods, "password") != NULL) {
261
0
        session->auth.supported_methods |= SSH_AUTH_METHOD_PASSWORD;
262
0
    }
263
0
    if (strstr(auth_methods, "keyboard-interactive") != NULL) {
264
0
        session->auth.supported_methods |= SSH_AUTH_METHOD_INTERACTIVE;
265
0
    }
266
0
    if (strstr(auth_methods, "publickey") != NULL) {
267
0
        session->auth.supported_methods |= SSH_AUTH_METHOD_PUBLICKEY;
268
0
    }
269
0
    if (strstr(auth_methods, "hostbased") != NULL) {
270
0
        session->auth.supported_methods |= SSH_AUTH_METHOD_HOSTBASED;
271
0
    }
272
0
    if (strstr(auth_methods, "gssapi-with-mic") != NULL) {
273
0
        session->auth.supported_methods |= SSH_AUTH_METHOD_GSSAPI_MIC;
274
0
    }
275
276
0
end:
277
0
    session->auth.current_method = SSH_AUTH_METHOD_UNKNOWN;
278
0
    SAFE_FREE(auth_methods);
279
280
0
    return SSH_PACKET_USED;
281
0
}
282
283
/**
284
 * @internal
285
 *
286
 * @brief Handles a SSH_USERAUTH_SUCCESS packet.
287
 *
288
 * It is also used to communicate the new to the upper levels.
289
 */
290
SSH_PACKET_CALLBACK(ssh_packet_userauth_success)
291
0
{
292
0
  struct ssh_crypto_struct *crypto = NULL;
293
294
0
  (void)packet;
295
0
  (void)type;
296
0
  (void)user;
297
298
0
  SSH_LOG(SSH_LOG_DEBUG, "Authentication successful");
299
0
  SSH_LOG(SSH_LOG_TRACE, "Received SSH_USERAUTH_SUCCESS");
300
301
0
  session->auth.state = SSH_AUTH_STATE_SUCCESS;
302
0
  session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
303
0
  session->flags |= SSH_SESSION_FLAG_AUTHENTICATED;
304
305
0
  crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_OUT);
306
0
  if (crypto != NULL && crypto->delayed_compress_out) {
307
0
      SSH_LOG(SSH_LOG_DEBUG, "Enabling delayed compression OUT");
308
0
      crypto->do_compress_out = 1;
309
0
  }
310
311
0
  crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_IN);
312
0
  if (crypto != NULL && crypto->delayed_compress_in) {
313
0
      SSH_LOG(SSH_LOG_DEBUG, "Enabling delayed compression IN");
314
0
      crypto->do_compress_in = 1;
315
0
  }
316
317
    /* Reset errors by previous authentication methods. */
318
0
    ssh_reset_error(session);
319
0
    session->auth.current_method = SSH_AUTH_METHOD_UNKNOWN;
320
0
  return SSH_PACKET_USED;
321
0
}
322
323
/**
324
 * @internal
325
 *
326
 * @brief Handles a SSH_USERAUTH_PK_OK or SSH_USERAUTH_INFO_REQUEST packet.
327
 *
328
 * Since the two types of packets share the same code, additional work is done
329
 * to understand if we are in a public key or keyboard-interactive context.
330
 */
331
0
SSH_PACKET_CALLBACK(ssh_packet_userauth_pk_ok) {
332
0
    int rc;
333
334
0
    SSH_LOG(SSH_LOG_TRACE,
335
0
            "Received SSH_USERAUTH_PK_OK/INFO_REQUEST/GSSAPI_RESPONSE");
336
337
0
    if (session->auth.state == SSH_AUTH_STATE_KBDINT_SENT) {
338
        /* Assuming we are in keyboard-interactive context */
339
0
        SSH_LOG(SSH_LOG_TRACE,
340
0
                "keyboard-interactive context, "
341
0
                "assuming SSH_USERAUTH_INFO_REQUEST");
342
0
        rc = ssh_packet_userauth_info_request(session,type,packet,user);
343
#ifdef WITH_GSSAPI
344
    } else if (session->auth.state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT) {
345
        rc = ssh_packet_userauth_gssapi_response(session, type, packet, user);
346
#endif
347
0
    } else if (session->auth.state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT) {
348
0
        session->auth.state = SSH_AUTH_STATE_PK_OK;
349
0
        SSH_LOG(SSH_LOG_TRACE, "Assuming SSH_USERAUTH_PK_OK");
350
0
        rc = SSH_PACKET_USED;
351
0
    } else {
352
0
        session->auth.state = SSH_AUTH_STATE_ERROR;
353
0
        SSH_LOG(SSH_LOG_TRACE, "SSH_USERAUTH_PK_OK received in wrong state");
354
0
        rc = SSH_PACKET_USED;
355
0
    }
356
357
0
    return rc;
358
0
}
359
360
/**
361
 * @brief Get available authentication methods from the server.
362
 *
363
 * This requires the function ssh_userauth_none() to be called before the
364
 * methods are available. The server MAY return a list of methods that may
365
 * continue.
366
 *
367
 * @param[in] session   The SSH session.
368
 *
369
 * @param[in] username  Deprecated, set to NULL.
370
 *
371
 * @returns             A bitfield of the following values:
372
 *                      - SSH_AUTH_METHOD_PASSWORD
373
 *                      - SSH_AUTH_METHOD_PUBLICKEY
374
 *                      - SSH_AUTH_METHOD_HOSTBASED
375
 *                      - SSH_AUTH_METHOD_INTERACTIVE
376
 *
377
 * @warning Other reserved flags may appear in future versions.
378
 * @see ssh_userauth_none()
379
 */
380
int ssh_userauth_list(ssh_session session, const char *username)
381
0
{
382
0
    (void) username; /* unused */
383
384
0
    if (session == NULL) {
385
0
        return 0;
386
0
    }
387
388
0
    return session->auth.supported_methods;
389
0
}
390
391
/**
392
 * @brief Try to authenticate through the "none" method.
393
 *
394
 * @param[in] session   The ssh session to use.
395
 *
396
 * @param[in] username    The username, this SHOULD be NULL.
397
 *
398
 * @returns SSH_AUTH_ERROR:   A serious error happened.\n
399
 *          SSH_AUTH_DENIED:  Authentication failed: use another method\n
400
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
401
 *                            have to use another method\n
402
 *          SSH_AUTH_SUCCESS: Authentication success\n
403
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
404
 *                            later.
405
 *
406
 * @note Most server implementations do not permit changing the username during
407
 * authentication. The username should only be set with ssh_options_set() only
408
 * before you connect to the server.
409
 */
410
int ssh_userauth_none(ssh_session session, const char *username)
411
5
{
412
5
    int rc;
413
414
5
    switch (session->pending_call_state) {
415
5
        case SSH_PENDING_CALL_NONE:
416
5
            break;
417
0
        case SSH_PENDING_CALL_AUTH_NONE:
418
0
            goto pending;
419
0
        default:
420
0
            ssh_set_error(session, SSH_FATAL,
421
0
                          "Wrong state (%d) during pending SSH call",
422
0
                          session->pending_call_state);
423
0
            return SSH_AUTH_ERROR;
424
5
    }
425
426
5
    rc = ssh_userauth_request_service(session);
427
5
    if (rc == SSH_AGAIN) {
428
1
        return SSH_AUTH_AGAIN;
429
4
    } else if (rc == SSH_ERROR) {
430
2
        return SSH_AUTH_ERROR;
431
2
    }
432
433
    /* request */
434
2
    rc = ssh_buffer_pack(session->out_buffer, "bsss",
435
2
            SSH2_MSG_USERAUTH_REQUEST,
436
2
            username ? username : session->opts.username,
437
2
            "ssh-connection",
438
2
            "none"
439
2
            );
440
2
    if (rc < 0) {
441
0
        goto fail;
442
0
    }
443
444
2
    session->auth.current_method = SSH_AUTH_METHOD_NONE;
445
2
    session->auth.state = SSH_AUTH_STATE_AUTH_NONE_SENT;
446
2
    session->pending_call_state = SSH_PENDING_CALL_AUTH_NONE;
447
2
    rc = ssh_packet_send(session);
448
2
    if (rc == SSH_ERROR) {
449
0
        return SSH_AUTH_ERROR;
450
0
    }
451
452
2
pending:
453
2
    rc = ssh_userauth_get_response(session);
454
2
    if (rc != SSH_AUTH_AGAIN) {
455
2
        session->pending_call_state = SSH_PENDING_CALL_NONE;
456
2
    }
457
458
2
    return rc;
459
0
fail:
460
0
    ssh_set_error_oom(session);
461
0
    ssh_buffer_reinit(session->out_buffer);
462
463
0
    return SSH_AUTH_ERROR;
464
2
}
465
466
/**
467
 * @internal
468
 *
469
 * @brief Adds the server's public key to the authentication request.
470
 *
471
 * This function is used internally when the hostbound public key authentication
472
 * extension is enabled. It export the server's public key and adds it to the
473
 * authentication buffer.
474
 *
475
 * @param[in]  session          The SSH session.
476
 *
477
 * @returns SSH_OK on success, SSH_ERROR if an error occurred.
478
 */
479
static int add_hostbound_pubkey(ssh_session session)
480
0
{
481
0
    int rc;
482
0
    ssh_string server_pubkey_s = NULL;
483
484
0
    if (session == NULL) {
485
0
        return SSH_ERROR;
486
0
    }
487
488
0
    if (session->current_crypto == NULL ||
489
0
        session->current_crypto->server_pubkey == NULL) {
490
0
        ssh_set_error(session,
491
0
                      SSH_FATAL,
492
0
                      "Invalid session or server public key");
493
0
        return SSH_ERROR;
494
0
    }
495
496
0
    rc = ssh_pki_export_pubkey_blob(session->current_crypto->server_pubkey,
497
0
                                    &server_pubkey_s);
498
0
    if (rc < 0) {
499
0
        goto error;
500
0
    }
501
502
0
    rc = ssh_buffer_add_ssh_string(session->out_buffer, server_pubkey_s);
503
0
    if (rc < 0) {
504
0
        goto error;
505
0
    }
506
507
0
error:
508
0
    SSH_STRING_FREE(server_pubkey_s);
509
0
    return rc;
510
0
}
511
512
/**
513
 * @internal
514
 *
515
 * @brief Build a public key authentication request.
516
 *
517
 * This helper function creates a SSH2_MSG_USERAUTH_REQUEST message for public
518
 * key authentication and adds the server's public key if the hostbound
519
 * extension is enabled.
520
 *
521
 * @param[in] session       The SSH session.
522
 * @param[in] username      The username, may be NULL.
523
 * @param[in] auth_type     Authentication type (0 for key offer, 1 for actual
524
 * auth).
525
 * @param[in] sig_type_c    The signature algorithm name.
526
 * @param[in] pubkey_s      The public key string.
527
 *
528
 * @return  SSH_OK on success, SSH_ERROR if an error occurred.
529
 */
530
static int build_pubkey_auth_request(ssh_session session,
531
                                     const char *username,
532
                                     int has_signature,
533
                                     const char *sig_type_c,
534
                                     ssh_string pubkey_s)
535
0
{
536
0
    int rc;
537
0
    const char *auth_method = "publickey";
538
539
0
    if (session->extensions & SSH_EXT_PUBLICKEY_HOSTBOUND) {
540
0
        auth_method = "publickey-hostbound-v00@openssh.com";
541
0
    }
542
543
    /* request */
544
0
    rc = ssh_buffer_pack(session->out_buffer,
545
0
                         "bsssbsS",
546
0
                         SSH2_MSG_USERAUTH_REQUEST,
547
0
                         username ? username : session->opts.username,
548
0
                         "ssh-connection",
549
0
                         auth_method,
550
0
                         has_signature, /* private key? */
551
0
                         sig_type_c,    /* algo */
552
0
                         pubkey_s       /* public key */
553
0
    );
554
0
    if (rc < 0) {
555
0
        return SSH_ERROR;
556
0
    }
557
558
0
    if (session->extensions & SSH_EXT_PUBLICKEY_HOSTBOUND) {
559
0
        rc = add_hostbound_pubkey(session);
560
0
        if (rc < 0) {
561
0
            return SSH_ERROR;
562
0
        }
563
0
    }
564
565
0
    return SSH_OK;
566
0
}
567
568
/**
569
 * @brief Try to authenticate with the given public key.
570
 *
571
 * To avoid unnecessary processing and user interaction, the following method
572
 * is provided for querying whether authentication using the 'pubkey' would
573
 * be possible.
574
 *
575
 * @param[in] session     The SSH session.
576
 *
577
 * @param[in] username    The username, this SHOULD be NULL.
578
 *
579
 * @param[in] pubkey      The public key to try.
580
 *
581
 * @return  SSH_AUTH_ERROR:   A serious error happened.\n
582
 *          SSH_AUTH_DENIED:  The server doesn't accept that public key as an
583
 *                            authentication token. Try another key or another
584
 *                            method.\n
585
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
586
 *                            have to use another method.\n
587
 *          SSH_AUTH_SUCCESS: The public key is accepted, you want now to use
588
 *                            ssh_userauth_publickey().\n
589
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
590
 *                            later.
591
 *
592
 * @note Most server implementations do not permit changing the username during
593
 * authentication. The username should only be set with ssh_options_set() only
594
 * before you connect to the server.
595
 */
596
int ssh_userauth_try_publickey(ssh_session session,
597
                               const char *username,
598
                               const ssh_key pubkey)
599
0
{
600
0
    ssh_string pubkey_s = NULL;
601
0
    const char *sig_type_c = NULL;
602
0
    bool allowed;
603
0
    int rc;
604
605
0
    if (session == NULL) {
606
0
        return SSH_AUTH_ERROR;
607
0
    }
608
609
0
    if (pubkey == NULL || !ssh_key_is_public(pubkey)) {
610
0
        ssh_set_error(session, SSH_FATAL, "Invalid pubkey");
611
0
        return SSH_AUTH_ERROR;
612
0
    }
613
614
0
    switch (session->pending_call_state) {
615
0
    case SSH_PENDING_CALL_NONE:
616
0
        break;
617
0
    case SSH_PENDING_CALL_AUTH_OFFER_PUBKEY:
618
0
        goto pending;
619
0
    default:
620
0
        ssh_set_error(session,
621
0
                      SSH_FATAL,
622
0
                      "Wrong state (%d) during pending SSH call",
623
0
                      session->pending_call_state);
624
0
        return SSH_AUTH_ERROR;
625
0
    }
626
627
    /* Note, that this is intentionally before checking the signature type
628
     * compatibility to make sure the possible EXT_INFO packet is processed,
629
     * extensions recorded and the right signature type is used below
630
     */
631
0
    rc = ssh_userauth_request_service(session);
632
0
    if (rc == SSH_AGAIN) {
633
0
        return SSH_AUTH_AGAIN;
634
0
    } else if (rc == SSH_ERROR) {
635
0
        return SSH_AUTH_ERROR;
636
0
    }
637
638
    /* Check if the given public key algorithm is allowed */
639
0
    sig_type_c = ssh_key_get_signature_algorithm(session, pubkey->type);
640
0
    if (sig_type_c == NULL) {
641
0
        ssh_set_error(session,
642
0
                      SSH_REQUEST_DENIED,
643
0
                      "Invalid key type (unknown)");
644
0
        return SSH_AUTH_DENIED;
645
0
    }
646
0
    rc = ssh_key_algorithm_allowed(session, sig_type_c);
647
0
    if (!rc) {
648
0
        ssh_set_error(session,
649
0
                      SSH_REQUEST_DENIED,
650
0
                      "The key algorithm '%s' is not allowed to be used by"
651
0
                      " PUBLICKEY_ACCEPTED_TYPES configuration option",
652
0
                      sig_type_c);
653
0
        return SSH_AUTH_DENIED;
654
0
    }
655
0
    allowed = ssh_key_size_allowed(session, pubkey);
656
0
    if (!allowed) {
657
0
        ssh_set_error(session,
658
0
                      SSH_REQUEST_DENIED,
659
0
                      "The '%s' key type of size %d is not allowed by "
660
0
                      "RSA_MIN_SIZE",
661
0
                      sig_type_c,
662
0
                      ssh_key_size(pubkey));
663
0
        return SSH_AUTH_DENIED;
664
0
    }
665
666
    /* public key */
667
0
    rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_s);
668
0
    if (rc < 0) {
669
0
        goto fail;
670
0
    }
671
672
0
    SSH_LOG(SSH_LOG_TRACE, "Trying signature type %s", sig_type_c);
673
0
    rc = build_pubkey_auth_request(session, username, 0, sig_type_c, pubkey_s);
674
0
    if (rc < 0) {
675
0
        goto fail;
676
0
    }
677
0
    SSH_STRING_FREE(pubkey_s);
678
679
0
    session->auth.current_method = SSH_AUTH_METHOD_PUBLICKEY;
680
0
    session->auth.state = SSH_AUTH_STATE_PUBKEY_OFFER_SENT;
681
0
    session->pending_call_state = SSH_PENDING_CALL_AUTH_OFFER_PUBKEY;
682
0
    rc = ssh_packet_send(session);
683
0
    if (rc == SSH_ERROR) {
684
0
        return SSH_AUTH_ERROR;
685
0
    }
686
687
0
pending:
688
0
    rc = ssh_userauth_get_response(session);
689
0
    if (rc != SSH_AUTH_AGAIN) {
690
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
691
0
    }
692
693
0
    return rc;
694
0
fail:
695
0
    SSH_STRING_FREE(pubkey_s);
696
0
    ssh_set_error_oom(session);
697
0
    ssh_buffer_reinit(session->out_buffer);
698
699
0
    return SSH_AUTH_ERROR;
700
0
}
701
702
/**
703
 * @brief Authenticate with public/private key or certificate.
704
 *
705
 * @param[in] session     The SSH session.
706
 *
707
 * @param[in] username    The username, this SHOULD be NULL.
708
 *
709
 * @param[in] privkey     The private key for authentication.
710
 *
711
 * @return  SSH_AUTH_ERROR:   A serious error happened.\n
712
 *          SSH_AUTH_DENIED:  The server doesn't accept that public key as an
713
 *                            authentication token. Try another key or another
714
 *                            method.\n
715
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
716
 *                            have to use another method.\n
717
 *          SSH_AUTH_SUCCESS: The public key is accepted.\n
718
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
719
 *                            later.
720
 *
721
 * @note Most server implementations do not permit changing the username during
722
 * authentication. The username should only be set with ssh_options_set() only
723
 * before you connect to the server.
724
 */
725
int ssh_userauth_publickey(ssh_session session,
726
                           const char *username,
727
                           const ssh_key privkey)
728
0
{
729
0
    ssh_string str = NULL;
730
0
    bool allowed;
731
0
    int rc;
732
0
    const char *sig_type_c = NULL;
733
0
    enum ssh_keytypes_e key_type;
734
0
    enum ssh_digest_e hash_type;
735
736
0
    if (session == NULL) {
737
0
        return SSH_AUTH_ERROR;
738
0
    }
739
740
0
    if (privkey == NULL || !ssh_key_is_private(privkey)) {
741
0
        ssh_set_error(session, SSH_FATAL, "Invalid private key");
742
0
        return SSH_AUTH_ERROR;
743
0
    }
744
745
0
    switch (session->pending_call_state) {
746
0
    case SSH_PENDING_CALL_NONE:
747
0
        break;
748
0
    case SSH_PENDING_CALL_AUTH_PUBKEY:
749
0
        goto pending;
750
0
    default:
751
0
        ssh_set_error(
752
0
            session,
753
0
            SSH_FATAL,
754
0
            "Bad call during pending SSH call in ssh_userauth_try_publickey");
755
0
        return SSH_AUTH_ERROR;
756
0
    }
757
758
    /* Note, that this is intentionally before checking the signature type
759
     * compatibility to make sure the possible EXT_INFO packet is processed,
760
     * extensions recorded and the right signature type is used below
761
     */
762
0
    rc = ssh_userauth_request_service(session);
763
0
    if (rc == SSH_AGAIN) {
764
0
        return SSH_AUTH_AGAIN;
765
0
    } else if (rc == SSH_ERROR) {
766
0
        return SSH_AUTH_ERROR;
767
0
    }
768
769
    /* Cert auth requires presenting the cert type name (*-cert@openssh.com) */
770
0
    key_type = privkey->cert != NULL ? privkey->cert_type : privkey->type;
771
772
    /* Check if the given public key algorithm is allowed */
773
0
    sig_type_c = ssh_key_get_signature_algorithm(session, key_type);
774
0
    if (sig_type_c == NULL) {
775
0
        ssh_set_error(session,
776
0
                      SSH_REQUEST_DENIED,
777
0
                      "Invalid key type (unknown)");
778
0
        return SSH_AUTH_DENIED;
779
0
    }
780
0
    rc = ssh_key_algorithm_allowed(session, sig_type_c);
781
0
    if (!rc) {
782
0
        ssh_set_error(session,
783
0
                      SSH_REQUEST_DENIED,
784
0
                      "The key algorithm '%s' is not allowed to be used by"
785
0
                      " PUBLICKEY_ACCEPTED_TYPES configuration option",
786
0
                      sig_type_c);
787
0
        return SSH_AUTH_DENIED;
788
0
    }
789
0
    allowed = ssh_key_size_allowed(session, privkey);
790
0
    if (!allowed) {
791
0
        ssh_set_error(session,
792
0
                      SSH_REQUEST_DENIED,
793
0
                      "The '%s' key type of size %d is not allowed by "
794
0
                      "RSA_MIN_SIZE",
795
0
                      sig_type_c,
796
0
                      ssh_key_size(privkey));
797
0
        return SSH_AUTH_DENIED;
798
0
    }
799
800
    /* get public key or cert */
801
0
    rc = ssh_pki_export_pubkey_blob(privkey, &str);
802
0
    if (rc < 0) {
803
0
        goto fail;
804
0
    }
805
806
0
    SSH_LOG(SSH_LOG_TRACE, "Sending signature type %s", sig_type_c);
807
0
    rc = build_pubkey_auth_request(session, username, 1, sig_type_c, str);
808
0
    if (rc < 0) {
809
0
        goto fail;
810
0
    }
811
0
    SSH_STRING_FREE(str);
812
813
    /* Get the hash type to be used in the signature based on the key type */
814
0
    hash_type = ssh_key_type_to_hash(session, privkey->type);
815
816
    /* sign the buffer with the private key */
817
0
    str = ssh_pki_do_sign(session, session->out_buffer, privkey, hash_type);
818
0
    if (str == NULL) {
819
0
        goto fail;
820
0
    }
821
822
0
    rc = ssh_buffer_add_ssh_string(session->out_buffer, str);
823
0
    SSH_STRING_FREE(str);
824
0
    str = NULL;
825
0
    if (rc < 0) {
826
0
        goto fail;
827
0
    }
828
829
0
    session->auth.current_method = SSH_AUTH_METHOD_PUBLICKEY;
830
0
    session->auth.state = SSH_AUTH_STATE_PUBKEY_AUTH_SENT;
831
0
    session->pending_call_state = SSH_PENDING_CALL_AUTH_PUBKEY;
832
0
    rc = ssh_packet_send(session);
833
0
    if (rc == SSH_ERROR) {
834
0
        return SSH_AUTH_ERROR;
835
0
    }
836
837
0
pending:
838
0
    rc = ssh_userauth_get_response(session);
839
0
    if (rc != SSH_AUTH_AGAIN) {
840
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
841
0
    }
842
843
0
    return rc;
844
0
fail:
845
0
    SSH_STRING_FREE(str);
846
0
    ssh_set_error_oom(session);
847
0
    ssh_buffer_reinit(session->out_buffer);
848
849
0
    return SSH_AUTH_ERROR;
850
0
}
851
852
static int ssh_userauth_agent_publickey(ssh_session session,
853
                                        const char *username,
854
                                        ssh_key pubkey)
855
0
{
856
0
    ssh_string pubkey_s = NULL;
857
0
    ssh_string sig_blob = NULL;
858
0
    const char *sig_type_c = NULL;
859
0
    bool allowed;
860
0
    int rc;
861
862
0
    switch (session->pending_call_state) {
863
0
    case SSH_PENDING_CALL_NONE:
864
0
        break;
865
0
    case SSH_PENDING_CALL_AUTH_AGENT:
866
0
        goto pending;
867
0
    default:
868
0
        ssh_set_error(session,
869
0
                      SSH_FATAL,
870
0
                      "Bad call during pending SSH call in %s",
871
0
                      __func__);
872
0
        return SSH_ERROR;
873
0
    }
874
875
    /* Note, that this is intentionally before checking the signature type
876
     * compatibility to make sure the possible EXT_INFO packet is processed,
877
     * extensions recorded and the right signature type is used below
878
     */
879
0
    rc = ssh_userauth_request_service(session);
880
0
    if (rc == SSH_AGAIN) {
881
0
        return SSH_AUTH_AGAIN;
882
0
    } else if (rc == SSH_ERROR) {
883
0
        return SSH_AUTH_ERROR;
884
0
    }
885
886
    /* public key */
887
0
    rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_s);
888
0
    if (rc < 0) {
889
0
        goto fail;
890
0
    }
891
892
    /* Check if the given public key algorithm is allowed */
893
0
    sig_type_c = ssh_key_get_signature_algorithm(session, pubkey->type);
894
0
    if (sig_type_c == NULL) {
895
0
        ssh_set_error(session,
896
0
                      SSH_REQUEST_DENIED,
897
0
                      "Invalid key type (unknown)");
898
0
        SSH_STRING_FREE(pubkey_s);
899
0
        return SSH_AUTH_DENIED;
900
0
    }
901
0
    rc = ssh_key_algorithm_allowed(session, sig_type_c);
902
0
    if (!rc) {
903
0
        ssh_set_error(session,
904
0
                      SSH_REQUEST_DENIED,
905
0
                      "The key algorithm '%s' is not allowed to be used by"
906
0
                      " PUBLICKEY_ACCEPTED_TYPES configuration option",
907
0
                      sig_type_c);
908
0
        SSH_STRING_FREE(pubkey_s);
909
0
        return SSH_AUTH_DENIED;
910
0
    }
911
0
    allowed = ssh_key_size_allowed(session, pubkey);
912
0
    if (!allowed) {
913
0
        ssh_set_error(session,
914
0
                      SSH_REQUEST_DENIED,
915
0
                      "The '%s' key type of size %d is not allowed by "
916
0
                      "RSA_MIN_SIZE",
917
0
                      sig_type_c,
918
0
                      ssh_key_size(pubkey));
919
0
        SSH_STRING_FREE(pubkey_s);
920
0
        return SSH_AUTH_DENIED;
921
0
    }
922
923
0
    rc = build_pubkey_auth_request(session, username, 1, sig_type_c, pubkey_s);
924
0
    if (rc < 0) {
925
0
        goto fail;
926
0
    }
927
0
    SSH_STRING_FREE(pubkey_s);
928
929
    /* sign the buffer with the private key */
930
0
    sig_blob = ssh_pki_do_sign_agent(session, session->out_buffer, pubkey);
931
0
    if (sig_blob == NULL) {
932
0
        goto fail;
933
0
    }
934
935
0
    rc = ssh_buffer_add_ssh_string(session->out_buffer, sig_blob);
936
0
    SSH_STRING_FREE(sig_blob);
937
0
    if (rc < 0) {
938
0
        goto fail;
939
0
    }
940
941
0
    session->auth.current_method = SSH_AUTH_METHOD_PUBLICKEY;
942
0
    session->auth.state = SSH_AUTH_STATE_PUBKEY_AUTH_SENT;
943
0
    session->pending_call_state = SSH_PENDING_CALL_AUTH_AGENT;
944
0
    rc = ssh_packet_send(session);
945
0
    if (rc == SSH_ERROR) {
946
0
        return SSH_AUTH_ERROR;
947
0
    }
948
949
0
pending:
950
0
    rc = ssh_userauth_get_response(session);
951
0
    if (rc != SSH_AUTH_AGAIN) {
952
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
953
0
    }
954
955
0
    return rc;
956
0
fail:
957
0
    ssh_set_error_oom(session);
958
0
    ssh_buffer_reinit(session->out_buffer);
959
0
    SSH_STRING_FREE(pubkey_s);
960
961
0
    return SSH_AUTH_ERROR;
962
0
}
963
964
enum ssh_agent_state_e {
965
    SSH_AGENT_STATE_NONE = 0,
966
    SSH_AGENT_STATE_PUBKEY,
967
    SSH_AGENT_STATE_CERT,
968
    SSH_AGENT_STATE_AUTH
969
};
970
971
struct ssh_agent_state_struct {
972
    enum ssh_agent_state_e state;
973
    ssh_key pubkey;
974
    char *comment;
975
};
976
977
/* Internal function */
978
void ssh_agent_state_free(void *data)
979
12.1k
{
980
12.1k
    struct ssh_agent_state_struct *state = data;
981
982
12.1k
    if (state) {
983
0
        SSH_STRING_FREE_CHAR(state->comment);
984
0
        ssh_key_free(state->pubkey);
985
0
        free(state);
986
0
    }
987
12.1k
}
988
989
/**
990
 * @brief Try to do public key authentication with ssh agent.
991
 *
992
 * @param[in]  session  The ssh session to use.
993
 *
994
 * @param[in]  username The username, this SHOULD be NULL.
995
 *
996
 * @return  SSH_AUTH_ERROR:   A serious error happened.\n
997
 *          SSH_AUTH_DENIED:  The server doesn't accept that public key as an
998
 *                            authentication token. Try another key or another
999
 *                            method.\n
1000
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
1001
 *                            have to use another method.\n
1002
 *          SSH_AUTH_SUCCESS: The public key is accepted, you want now to use
1003
 *                            ssh_userauth_publickey().\n
1004
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
1005
 *                            later.
1006
 *
1007
 * @note Most server implementations do not permit changing the username during
1008
 * authentication. The username should only be set with ssh_options_set() only
1009
 * before you connect to the server.
1010
 */
1011
int ssh_userauth_agent(ssh_session session, const char *username)
1012
0
{
1013
0
    int rc = SSH_AUTH_ERROR;
1014
0
    struct ssh_agent_state_struct *state = NULL;
1015
0
    ssh_key *configKeys = NULL;
1016
0
    ssh_key *configCerts = NULL;
1017
0
    size_t configKeysCount = 0;
1018
0
    size_t configCertsCount = 0;
1019
0
    size_t i;
1020
1021
0
    if (session == NULL) {
1022
0
        return SSH_AUTH_ERROR;
1023
0
    }
1024
1025
0
    if (!ssh_agent_is_running(session)) {
1026
0
        return SSH_AUTH_DENIED;
1027
0
    }
1028
1029
0
    if (!session->agent_state) {
1030
0
        session->agent_state = calloc(1, sizeof(struct ssh_agent_state_struct));
1031
0
        if (!session->agent_state) {
1032
0
            ssh_set_error_oom(session);
1033
0
            return SSH_AUTH_ERROR;
1034
0
        }
1035
0
        session->agent_state->state = SSH_AGENT_STATE_NONE;
1036
0
    }
1037
1038
0
    state = session->agent_state;
1039
0
    if (state->pubkey == NULL) {
1040
0
        state->pubkey = ssh_agent_get_first_ident(session, &state->comment);
1041
0
    }
1042
1043
0
    if (state->pubkey == NULL) {
1044
0
        return SSH_AUTH_DENIED;
1045
0
    }
1046
1047
0
    if (session->opts.identities_only) {
1048
        /*
1049
         * Read keys mentioned in the config, so we can check if key from agent
1050
         * is in there.
1051
         */
1052
0
        size_t identityLen = ssh_list_count(session->opts.identity);
1053
0
        size_t certsLen = ssh_list_count(session->opts.certificate);
1054
0
        struct ssh_iterator *it = ssh_list_get_iterator(session->opts.identity);
1055
1056
0
        configKeys = malloc(identityLen * sizeof(ssh_key));
1057
0
        configCerts = malloc((certsLen + identityLen) * sizeof(ssh_key));
1058
0
        if (configKeys == NULL || configCerts == NULL) {
1059
0
            free(configKeys);
1060
0
            free(configCerts);
1061
0
            ssh_set_error_oom(session);
1062
0
            return SSH_AUTH_ERROR;
1063
0
        }
1064
1065
0
        while (it != NULL && configKeysCount < identityLen) {
1066
0
            const char *privkeyFile = it->data;
1067
0
            size_t certPathLen;
1068
0
            char *certFile = NULL;
1069
0
            ssh_key pubkey = NULL;
1070
0
            ssh_key cert = NULL;
1071
1072
            /*
1073
             * Read the private key file listed in the config, but we're only
1074
             * interested in the public key. Don't try to decrypt private key.
1075
             */
1076
0
            rc = ssh_pki_import_pubkey_file(privkeyFile, &pubkey);
1077
0
            if (rc == SSH_OK) {
1078
0
                configKeys[configKeysCount++] = pubkey;
1079
0
            } else {
1080
0
                char *pubkeyFile = NULL;
1081
0
                size_t pubkeyPathLen = strlen(privkeyFile) + sizeof(".pub");
1082
1083
0
                SSH_KEY_FREE(pubkey);
1084
1085
                /*
1086
                * If we couldn't get the public key from the private key file,
1087
                * try a .pub file instead.
1088
                */
1089
0
                pubkeyFile = malloc(pubkeyPathLen);
1090
0
                if (!pubkeyFile) {
1091
0
                    ssh_set_error_oom(session);
1092
0
                    rc = SSH_AUTH_ERROR;
1093
0
                    goto done;
1094
0
                }
1095
0
                snprintf(pubkeyFile, pubkeyPathLen, "%s.pub", privkeyFile);
1096
0
                rc = ssh_pki_import_pubkey_file(pubkeyFile, &pubkey);
1097
0
                free(pubkeyFile);
1098
0
                if (rc == SSH_OK) {
1099
0
                    configKeys[configKeysCount++] = pubkey;
1100
0
                } else if (pubkey) {
1101
0
                    SSH_KEY_FREE(pubkey);
1102
0
                }
1103
0
            }
1104
            /* Now try to see if there is a certificate with default name
1105
             * do not merge it yet with the key as we need to try first the
1106
             * non-certified key */
1107
0
            certPathLen = strlen(privkeyFile) + sizeof("-cert.pub");
1108
0
            certFile = malloc(certPathLen);
1109
0
            if (!certFile) {
1110
0
                ssh_set_error_oom(session);
1111
0
                rc = SSH_AUTH_ERROR;
1112
0
                goto done;
1113
0
            }
1114
0
            snprintf(certFile, certPathLen, "%s-cert.pub", privkeyFile);
1115
0
            rc = ssh_pki_import_cert_file(certFile, &cert);
1116
0
            free(certFile);
1117
0
            if (rc == SSH_OK) {
1118
0
                configCerts[configCertsCount++] = cert;
1119
0
            } else if (cert) {
1120
0
                SSH_KEY_FREE(cert);
1121
0
            }
1122
1123
0
            it = it->next;
1124
0
        }
1125
        /* And now load separately-listed certificates. */
1126
0
        it = ssh_list_get_iterator(session->opts.certificate);
1127
0
        while (it != NULL && configCertsCount < certsLen + identityLen) {
1128
0
            const char *certFile = it->data;
1129
0
            ssh_key cert = NULL;
1130
1131
0
            rc = ssh_pki_import_cert_file(certFile, &cert);
1132
0
            if (rc == SSH_OK) {
1133
0
                configCerts[configCertsCount++] = cert;
1134
0
            } else if (cert) {
1135
0
                SSH_KEY_FREE(cert);
1136
0
            }
1137
1138
0
            it = it->next;
1139
0
        }
1140
0
    }
1141
1142
0
    while (state->pubkey != NULL) {
1143
0
        if (state->state == SSH_AGENT_STATE_NONE) {
1144
0
            SSH_LOG(SSH_LOG_DEBUG,
1145
0
                    "Trying identity %s",
1146
0
                    state->comment);
1147
0
            if (session->opts.identities_only) {
1148
                /* Check if this key is one of the keys listed in the config */
1149
0
                bool found_key = false;
1150
0
                for (i = 0; i < configKeysCount; i++) {
1151
0
                    int cmp = ssh_key_cmp(state->pubkey,
1152
0
                                          configKeys[i],
1153
0
                                          SSH_KEY_CMP_PUBLIC);
1154
0
                    if (cmp == 0) {
1155
0
                        found_key = true;
1156
0
                        break;
1157
0
                    }
1158
0
                }
1159
                /* or in separate certificates */
1160
0
                for (i = 0; i < configCertsCount; i++) {
1161
0
                    int cmp = ssh_key_cmp(state->pubkey,
1162
0
                                          configCerts[i],
1163
0
                                          SSH_KEY_CMP_PUBLIC);
1164
0
                    if (cmp == 0) {
1165
0
                        found_key = true;
1166
0
                        break;
1167
0
                    }
1168
0
                }
1169
1170
0
                if (!found_key) {
1171
0
                    SSH_LOG(SSH_LOG_DEBUG,
1172
0
                            "Identities only is enabled and identity %s was "
1173
0
                            "not listed in config, skipping",
1174
0
                            state->comment);
1175
0
                    SSH_STRING_FREE_CHAR(state->comment);
1176
0
                    state->comment = NULL;
1177
0
                    SSH_KEY_FREE(state->pubkey);
1178
0
                    state->pubkey = ssh_agent_get_next_ident(
1179
0
                        session, &state->comment);
1180
1181
0
                    if (state->pubkey == NULL) {
1182
0
                        rc = SSH_AUTH_DENIED;
1183
0
                    }
1184
0
                    continue;
1185
0
                }
1186
0
            }
1187
0
        }
1188
0
        if (state->state == SSH_AGENT_STATE_NONE ||
1189
0
            state->state == SSH_AGENT_STATE_PUBKEY ||
1190
0
            state->state == SSH_AGENT_STATE_CERT) {
1191
0
            rc = ssh_userauth_try_publickey(session, username, state->pubkey);
1192
0
            if (rc == SSH_AUTH_ERROR) {
1193
0
                ssh_agent_state_free(state);
1194
0
                session->agent_state = NULL;
1195
0
                goto done;
1196
0
            } else if (rc == SSH_AUTH_AGAIN) {
1197
0
                state->state = (state->state == SSH_AGENT_STATE_NONE ?
1198
0
                                SSH_AGENT_STATE_PUBKEY : state->state);
1199
0
                goto done;
1200
0
            } else if (rc != SSH_AUTH_SUCCESS) {
1201
0
                SSH_LOG(SSH_LOG_DEBUG,
1202
0
                        "Public key of %s refused by server",
1203
0
                        state->comment);
1204
0
                if (state->state == SSH_AGENT_STATE_PUBKEY) {
1205
0
                    for (i = 0; i < configCertsCount; i++) {
1206
0
                        int cmp = ssh_key_cmp(state->pubkey,
1207
0
                                              configCerts[i],
1208
0
                                              SSH_KEY_CMP_PUBLIC);
1209
0
                        if (cmp == 0) {
1210
0
                            SSH_LOG(SSH_LOG_DEBUG,
1211
0
                                    "Retry with matching certificate");
1212
0
                            SSH_KEY_FREE(state->pubkey);
1213
0
                            state->pubkey = ssh_key_dup(configCerts[i]);
1214
0
                            state->state = SSH_AGENT_STATE_CERT;
1215
0
                            continue;
1216
0
                        }
1217
0
                    }
1218
0
                }
1219
0
                SSH_STRING_FREE_CHAR(state->comment);
1220
0
                state->comment = NULL;
1221
0
                SSH_KEY_FREE(state->pubkey);
1222
0
                state->pubkey = ssh_agent_get_next_ident(session,
1223
0
                                                         &state->comment);
1224
0
                state->state = SSH_AGENT_STATE_NONE;
1225
0
                continue;
1226
0
            }
1227
1228
0
            SSH_LOG(SSH_LOG_DEBUG,
1229
0
                    "Public key of %s accepted by server",
1230
0
                    state->comment);
1231
0
            state->state = SSH_AGENT_STATE_AUTH;
1232
0
        }
1233
0
        if (state->state == SSH_AGENT_STATE_AUTH) {
1234
0
            rc = ssh_userauth_agent_publickey(session, username, state->pubkey);
1235
0
            if (rc == SSH_AUTH_AGAIN) {
1236
0
                goto done;
1237
0
            }
1238
0
            SSH_STRING_FREE_CHAR(state->comment);
1239
0
            state->comment = NULL;
1240
0
            if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_PARTIAL) {
1241
0
                ssh_agent_state_free(session->agent_state);
1242
0
                session->agent_state = NULL;
1243
0
                goto done;
1244
0
            } else if (rc != SSH_AUTH_SUCCESS) {
1245
0
                SSH_LOG(SSH_LOG_DEBUG,
1246
0
                        "Server accepted public key but refused the signature");
1247
0
                SSH_KEY_FREE(state->pubkey);
1248
0
                state->pubkey = ssh_agent_get_next_ident(session,
1249
0
                                                         &state->comment);
1250
0
                state->state = SSH_AGENT_STATE_NONE;
1251
0
                continue;
1252
0
            }
1253
0
            ssh_agent_state_free (session->agent_state);
1254
0
            session->agent_state = NULL;
1255
0
            rc = SSH_AUTH_SUCCESS;
1256
0
            goto done;
1257
0
        }
1258
0
    }
1259
1260
0
    ssh_agent_state_free (session->agent_state);
1261
0
    session->agent_state = NULL;
1262
0
done:
1263
0
    for (i = 0; i < configKeysCount; i++) {
1264
0
        ssh_key_free(configKeys[i]);
1265
0
    }
1266
0
    free(configKeys);
1267
0
    for (i = 0; i < configCertsCount; i++) {
1268
0
        ssh_key_free(configCerts[i]);
1269
0
    }
1270
0
    free(configCerts);
1271
0
    return rc;
1272
0
}
1273
1274
enum ssh_auth_auto_state_e {
1275
    SSH_AUTH_AUTO_STATE_NONE = 0,
1276
    SSH_AUTH_AUTO_STATE_PUBKEY,
1277
    SSH_AUTH_AUTO_STATE_KEY_IMPORTED,
1278
    SSH_AUTH_AUTO_STATE_CERTIFICATE_FILE,
1279
    SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION,
1280
    SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED
1281
};
1282
1283
struct ssh_auth_auto_state_struct {
1284
    enum ssh_auth_auto_state_e state;
1285
    struct ssh_iterator *it;
1286
    ssh_key privkey;
1287
    ssh_key pubkey;
1288
    ssh_key cert;
1289
    struct ssh_iterator *cert_it;
1290
};
1291
1292
/**
1293
 * @brief Get the identity that is currently being processed by
1294
 * ssh_userauth_publickey_auto()
1295
 *
1296
 * This is meant to be used by a callback that happens as part of the
1297
 * execution of ssh_userauth_publickey_auto().  The auth_function
1298
 * callback might want to know which key a passphrase is needed for,
1299
 * for example.
1300
 *
1301
 * @param[in]  session     The SSH session.
1302
 *
1303
 * @param[out] value       The value to get into. As a char**, space will be
1304
 *                         allocated by the function for the value, it is
1305
 *                         your responsibility to free the memory using
1306
 *                         ssh_string_free_char().
1307
 *
1308
 * @return  SSH_OK on success, SSH_ERROR on error.
1309
 */
1310
int ssh_userauth_publickey_auto_get_current_identity(ssh_session session,
1311
                                                     char** value)
1312
0
{
1313
0
    const char *id = NULL;
1314
1315
0
    if (session == NULL) {
1316
0
        return SSH_ERROR;
1317
0
    }
1318
1319
0
    if (value == NULL) {
1320
0
        ssh_set_error_invalid(session);
1321
0
        return SSH_ERROR;
1322
0
    }
1323
1324
0
    if (session->auth.auto_state != NULL &&
1325
0
        session->auth.auto_state->it != NULL) {
1326
0
        id = session->auth.auto_state->it->data;
1327
0
    }
1328
1329
0
    if (id == NULL) {
1330
0
        return SSH_ERROR;
1331
0
    }
1332
1333
0
    *value = strdup(id);
1334
0
    if (*value == NULL) {
1335
0
        ssh_set_error_oom(session);
1336
0
        return SSH_ERROR;
1337
0
    }
1338
1339
0
    return SSH_OK;
1340
0
}
1341
1342
/**
1343
 * @brief Tries to automatically authenticate with public key and "none"
1344
 *
1345
 * It may fail, for instance it doesn't ask for a password and uses a default
1346
 * asker for passphrases (in case the private key is encrypted).
1347
 *
1348
 * @param[in]  session     The SSH session.
1349
 *
1350
 * @param[in]  username    The username, this SHOULD be NULL.
1351
 *
1352
 * @param[in]  passphrase  Use this passphrase to unlock the privatekey. Use NULL
1353
 *                         if you don't want to use a passphrase or the user
1354
 *                         should be asked.
1355
 *
1356
 * @return  SSH_AUTH_ERROR:   A serious error happened.\n
1357
 *          SSH_AUTH_DENIED:  The server doesn't accept that public key as an
1358
 *                            authentication token. Try another key or another
1359
 *                            method.\n
1360
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
1361
 *                            have to use another method.\n
1362
 *          SSH_AUTH_SUCCESS: Authentication success\n
1363
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
1364
 *                            later.
1365
 *
1366
 * @note Most server implementations do not permit changing the username during
1367
 * authentication. The username should only be set with ssh_options_set() only
1368
 * before you connect to the server.
1369
 *
1370
 * The OpenSSH iterates over the identities and first try the plain public key
1371
 * and then the certificate if it is in place.
1372
 */
1373
int ssh_userauth_publickey_auto(ssh_session session,
1374
                                const char *username,
1375
                                const char *passphrase)
1376
0
{
1377
0
    ssh_auth_callback auth_fn = NULL;
1378
0
    void *auth_data = NULL;
1379
0
    struct ssh_auth_auto_state_struct *state = NULL;
1380
0
    int rc;
1381
1382
0
    if (session == NULL) {
1383
0
        return SSH_AUTH_ERROR;
1384
0
    }
1385
0
    if (! (session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH)) {
1386
0
        session->auth.supported_methods &= ~SSH_AUTH_METHOD_PUBLICKEY;
1387
0
        return SSH_AUTH_DENIED;
1388
0
    }
1389
0
    if (session->common.callbacks) {
1390
0
        auth_fn = session->common.callbacks->auth_function;
1391
0
        auth_data = session->common.callbacks->userdata;
1392
0
    }
1393
0
    if (!session->auth.auto_state) {
1394
0
        session->auth.auto_state =
1395
0
                calloc(1, sizeof(struct ssh_auth_auto_state_struct));
1396
0
        if (!session->auth.auto_state) {
1397
0
            ssh_set_error_oom(session);
1398
0
            return SSH_AUTH_ERROR;
1399
0
        }
1400
1401
        /* Set state explicitly */
1402
0
        session->auth.auto_state->state = SSH_AUTH_AUTO_STATE_NONE;
1403
0
    }
1404
0
    state = session->auth.auto_state;
1405
0
    if (state->state == SSH_AUTH_AUTO_STATE_NONE) {
1406
        /* Try authentication with ssh-agent first */
1407
0
        rc = ssh_userauth_agent(session, username);
1408
0
        if (rc == SSH_AUTH_SUCCESS ||
1409
0
            rc == SSH_AUTH_PARTIAL ||
1410
0
            rc == SSH_AUTH_AGAIN) {
1411
0
            return rc;
1412
0
        }
1413
0
        state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1414
0
    }
1415
0
    if (state->it == NULL) {
1416
0
        state->it = ssh_list_get_iterator(session->opts.identity);
1417
0
    }
1418
1419
0
    while (state->it != NULL) {
1420
0
        const char *privkey_file = state->it->data;
1421
0
        char pubkey_file[PATH_MAX] = {0};
1422
1423
0
        if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY) {
1424
0
            SSH_LOG(SSH_LOG_DEBUG,
1425
0
                    "Trying to authenticate with %s",
1426
0
                    privkey_file);
1427
0
            state->cert = NULL;
1428
0
            state->privkey = NULL;
1429
0
            state->pubkey = NULL;
1430
1431
#ifdef WITH_PKCS11_URI
1432
            if (ssh_pki_is_uri(privkey_file)) {
1433
                char *pub_uri_from_priv = NULL;
1434
                SSH_LOG(SSH_LOG_INFO,
1435
                        "Authenticating with PKCS #11 URI.");
1436
                pub_uri_from_priv = ssh_pki_export_pub_uri_from_priv_uri(privkey_file);
1437
                if (pub_uri_from_priv == NULL) {
1438
                    return SSH_ERROR;
1439
                } else {
1440
                    snprintf(pubkey_file,
1441
                             sizeof(pubkey_file),
1442
                             "%s",
1443
                             pub_uri_from_priv);
1444
                    SAFE_FREE(pub_uri_from_priv);
1445
                }
1446
            } else
1447
#endif /* WITH_PKCS11_URI */
1448
0
            {
1449
0
                snprintf(pubkey_file,
1450
0
                         sizeof(pubkey_file),
1451
0
                         "%s.pub",
1452
0
                         privkey_file);
1453
0
            }
1454
1455
0
            rc = ssh_pki_import_pubkey_file(pubkey_file, &state->pubkey);
1456
0
            if (rc == SSH_ERROR) {
1457
0
                ssh_set_error(session,
1458
0
                              SSH_FATAL,
1459
0
                              "Failed to import public key: %s",
1460
0
                              pubkey_file);
1461
0
                SAFE_FREE(session->auth.auto_state);
1462
0
                return SSH_AUTH_ERROR;
1463
0
            } else if (rc == SSH_EOF) {
1464
                /* Read the private key and save the public key to file */
1465
0
                rc = ssh_pki_import_privkey_file(privkey_file,
1466
0
                                                 passphrase,
1467
0
                                                 auth_fn,
1468
0
                                                 auth_data,
1469
0
                                                 &state->privkey);
1470
0
                if (rc == SSH_ERROR) {
1471
0
                    ssh_set_error(session,
1472
0
                                  SSH_FATAL,
1473
0
                                  "Failed to read private key: %s",
1474
0
                                  privkey_file);
1475
0
                    state->it = state->it->next;
1476
0
                    continue;
1477
0
                } else if (rc == SSH_EOF) {
1478
                    /* If the file doesn't exist, continue */
1479
0
                    SSH_LOG(SSH_LOG_DEBUG,
1480
0
                            "Private key %s doesn't exist.",
1481
0
                            privkey_file);
1482
0
                    state->it = state->it->next;
1483
0
                    continue;
1484
0
                }
1485
1486
0
                rc = ssh_pki_export_privkey_to_pubkey(state->privkey,
1487
0
                                                      &state->pubkey);
1488
0
                if (rc == SSH_ERROR) {
1489
0
                    SSH_KEY_FREE(state->privkey);
1490
0
                    SAFE_FREE(session->auth.auto_state);
1491
0
                    return SSH_AUTH_ERROR;
1492
0
                }
1493
1494
0
                rc = ssh_pki_export_pubkey_file(state->pubkey, pubkey_file);
1495
0
                if (rc == SSH_ERROR) {
1496
0
                    SSH_LOG(SSH_LOG_TRACE,
1497
0
                            "Could not write public key to file: %s",
1498
0
                            pubkey_file);
1499
0
                }
1500
0
            }
1501
0
            state->state = SSH_AUTH_AUTO_STATE_KEY_IMPORTED;
1502
0
        }
1503
0
        if (state->state == SSH_AUTH_AUTO_STATE_KEY_IMPORTED ||
1504
0
            state->state == SSH_AUTH_AUTO_STATE_CERTIFICATE_FILE ||
1505
0
            state->state == SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION) {
1506
0
            ssh_key k = state->pubkey;
1507
0
            if (state->state != SSH_AUTH_AUTO_STATE_KEY_IMPORTED) {
1508
0
                k = state->cert;
1509
0
            }
1510
0
            rc = ssh_userauth_try_publickey(session, username, k);
1511
0
            if (rc == SSH_AUTH_ERROR) {
1512
0
                SSH_LOG(SSH_LOG_TRACE,
1513
0
                        "Public key authentication error for %s",
1514
0
                        privkey_file);
1515
0
                SSH_KEY_FREE(state->cert);
1516
0
                SSH_KEY_FREE(state->privkey);
1517
0
                SSH_KEY_FREE(state->pubkey);
1518
0
                SAFE_FREE(session->auth.auto_state);
1519
0
                return rc;
1520
0
            } else if (rc == SSH_AUTH_AGAIN) {
1521
0
                return rc;
1522
0
            } else if (rc != SSH_AUTH_SUCCESS) {
1523
0
                int r; /* do not reuse `rc` as it is used to return from here */
1524
0
                SSH_KEY_FREE(state->cert);
1525
0
                SSH_LOG(SSH_LOG_DEBUG,
1526
0
                        "Public key for %s%s refused by server",
1527
0
                        privkey_file,
1528
0
                        (state->state != SSH_AUTH_AUTO_STATE_KEY_IMPORTED
1529
0
                            ? " (with certificate)" : ""));
1530
                /* Try certificate file by appending -cert.pub (if present) */
1531
0
                if (state->state == SSH_AUTH_AUTO_STATE_KEY_IMPORTED) {
1532
0
                    char cert_file[PATH_MAX] = {0};
1533
0
                    ssh_key cert = NULL;
1534
1535
0
                    snprintf(cert_file,
1536
0
                             sizeof(cert_file),
1537
0
                             "%s-cert.pub",
1538
0
                             privkey_file);
1539
0
                    SSH_LOG(SSH_LOG_TRACE,
1540
0
                            "Trying to load the certificate %s (default path)",
1541
0
                            cert_file);
1542
0
                    r = ssh_pki_import_cert_file(cert_file, &cert);
1543
0
                    if (r == SSH_OK) {
1544
                        /* TODO check the pubkey and certs match */
1545
0
                        SSH_LOG(SSH_LOG_TRACE,
1546
0
                                "Certificate loaded %s. Retry the authentication.",
1547
0
                                cert_file);
1548
0
                        state->state = SSH_AUTH_AUTO_STATE_CERTIFICATE_FILE;
1549
0
                        SSH_KEY_FREE(state->cert);
1550
0
                        state->cert = cert;
1551
                        /* try to authenticate with this certificate */
1552
0
                        continue;
1553
0
                    }
1554
                    /* if the file does not exists, try configuration options */
1555
0
                    state->state = SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION;
1556
0
                }
1557
                /* Try certificate files loaded through options */
1558
0
                if (state->state == SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION) {
1559
0
                    SSH_KEY_FREE(state->cert);
1560
0
                    if (state->cert_it == NULL) {
1561
0
                        state->cert_it = ssh_list_get_iterator(session->opts.certificate);
1562
0
                    }
1563
0
                    while (state->cert_it != NULL) {
1564
0
                        const char *cert_file = state->cert_it->data;
1565
0
                        ssh_key cert = NULL;
1566
1567
0
                        SSH_LOG(SSH_LOG_TRACE,
1568
0
                                "Trying to load the certificate %s (options)",
1569
0
                                cert_file);
1570
0
                        r = ssh_pki_import_cert_file(cert_file, &cert);
1571
0
                        if (r == SSH_OK) {
1572
0
                            int cmp = ssh_key_cmp(cert,
1573
0
                                                  state->pubkey,
1574
0
                                                  SSH_KEY_CMP_PUBLIC);
1575
0
                            if (cmp != 0) {
1576
0
                                state->cert_it = state->cert_it->next;
1577
0
                                SSH_KEY_FREE(cert);
1578
0
                                continue; /* with next cert */
1579
0
                            }
1580
0
                            SSH_LOG(SSH_LOG_TRACE,
1581
0
                                    "Found matching certificate %s in options. Retry the authentication.",
1582
0
                                    cert_file);
1583
0
                            state->cert = cert;
1584
0
                            cert = NULL;
1585
0
                            state->state = SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION;
1586
                            /* try to authenticate with this identity */
1587
0
                            break; /* try this cert */
1588
0
                        }
1589
                        /* continue with next identity */
1590
0
                    }
1591
0
                    if (state->cert != NULL) {
1592
0
                        continue; /* retry with the certificate */
1593
0
                    }
1594
0
                }
1595
0
                SSH_KEY_FREE(state->cert);
1596
0
                SSH_KEY_FREE(state->privkey);
1597
0
                SSH_KEY_FREE(state->pubkey);
1598
0
                state->it = state->it->next;
1599
0
                state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1600
0
                continue;
1601
0
            }
1602
0
            state->state = SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED;
1603
0
        }
1604
0
        if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED) {
1605
            /* Public key has been accepted by the server */
1606
0
            if (state->privkey == NULL) {
1607
0
                rc = ssh_pki_import_privkey_file(privkey_file,
1608
0
                                                 passphrase,
1609
0
                                                 auth_fn,
1610
0
                                                 auth_data,
1611
0
                                                 &state->privkey);
1612
0
                if (rc == SSH_ERROR) {
1613
0
                    SSH_KEY_FREE(state->cert);
1614
0
                    SSH_KEY_FREE(state->pubkey);
1615
0
                    ssh_set_error(session,
1616
0
                                  SSH_FATAL,
1617
0
                                  "Failed to read private key: %s",
1618
0
                                  privkey_file);
1619
0
                    state->it = state->it->next;
1620
0
                    state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1621
0
                    continue;
1622
0
                } else if (rc == SSH_EOF) {
1623
                    /* If the file doesn't exist, continue */
1624
0
                    SSH_KEY_FREE(state->cert);
1625
0
                    SSH_KEY_FREE(state->pubkey);
1626
0
                    SSH_LOG(SSH_LOG_DEBUG,
1627
0
                            "Private key %s doesn't exist.",
1628
0
                            privkey_file);
1629
0
                    state->it = state->it->next;
1630
0
                    state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1631
0
                    continue;
1632
0
                }
1633
0
            }
1634
0
            if (state->cert != NULL && !is_cert_type(state->privkey->cert_type)) {
1635
0
                rc = ssh_pki_copy_cert_to_privkey(state->cert, state->privkey);
1636
0
                if (rc != SSH_OK) {
1637
0
                    SSH_KEY_FREE(state->cert);
1638
0
                    SSH_KEY_FREE(state->privkey);
1639
0
                    SSH_KEY_FREE(state->pubkey);
1640
0
                    ssh_set_error(session,
1641
0
                                  SSH_FATAL,
1642
0
                                  "Failed to copy cert to private key");
1643
0
                    state->it = state->it->next;
1644
0
                    state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1645
0
                    continue;
1646
0
                }
1647
0
            }
1648
1649
0
            rc = ssh_userauth_publickey(session, username, state->privkey);
1650
0
            if (rc != SSH_AUTH_AGAIN && rc != SSH_AUTH_DENIED) {
1651
0
                bool cert_used = (state->cert != NULL);
1652
0
                SSH_KEY_FREE(state->cert);
1653
0
                SSH_KEY_FREE(state->privkey);
1654
0
                SSH_KEY_FREE(state->pubkey);
1655
0
                SAFE_FREE(session->auth.auto_state);
1656
0
                if (rc == SSH_AUTH_SUCCESS) {
1657
0
                    SSH_LOG(SSH_LOG_DEBUG,
1658
0
                            "Successfully authenticated using %s%s",
1659
0
                            privkey_file,
1660
0
                            (cert_used ? " and certificate" : ""));
1661
0
                }
1662
0
                return rc;
1663
0
            }
1664
0
            if (rc == SSH_AUTH_AGAIN) {
1665
0
                return rc;
1666
0
            }
1667
1668
0
            SSH_KEY_FREE(state->cert);
1669
0
            SSH_KEY_FREE(state->privkey);
1670
0
            SSH_KEY_FREE(state->pubkey);
1671
1672
0
            SSH_LOG(SSH_LOG_DEBUG,
1673
0
                    "The server accepted the public key but refused the signature");
1674
0
            state->it = state->it->next;
1675
0
            state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1676
            /* continue */
1677
0
        }
1678
0
    }
1679
0
    SSH_LOG(SSH_LOG_WARN,
1680
0
            "Access denied: Tried every public key, none matched");
1681
0
    SAFE_FREE(session->auth.auto_state);
1682
0
    return SSH_AUTH_DENIED;
1683
0
}
1684
1685
/**
1686
 * @brief Try to authenticate by password.
1687
 *
1688
 * This authentication method is normally disabled on SSHv2 server. You should
1689
 * use keyboard-interactive mode.
1690
 *
1691
 * The 'password' value MUST be encoded UTF-8.  It is up to the server how to
1692
 * interpret the password and validate it against the password database.
1693
 * However, if you read the password in some other encoding, you MUST convert
1694
 * the password to UTF-8.
1695
 *
1696
 * @param[in] session   The ssh session to use.
1697
 *
1698
 * @param[in] username  The username, this SHOULD be NULL.
1699
 *
1700
 * @param[in] password  The password to authenticate in UTF-8.
1701
 *
1702
 * @returns SSH_AUTH_ERROR:   A serious error happened.\n
1703
 *          SSH_AUTH_DENIED:  Authentication failed: use another method\n
1704
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
1705
 *                            have to use another method\n
1706
 *          SSH_AUTH_SUCCESS: Authentication success\n
1707
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
1708
 *                            later.
1709
 *
1710
 * @note Most server implementations do not permit changing the username during
1711
 * authentication. The username should only be set with ssh_options_set() only
1712
 * before you connect to the server.
1713
 *
1714
 * @see ssh_userauth_none()
1715
 * @see ssh_userauth_kbdint()
1716
 */
1717
int ssh_userauth_password(ssh_session session,
1718
                          const char *username,
1719
                          const char *password)
1720
0
{
1721
0
    int rc;
1722
1723
0
    switch (session->pending_call_state) {
1724
0
        case SSH_PENDING_CALL_NONE:
1725
0
            break;
1726
0
        case SSH_PENDING_CALL_AUTH_PASSWORD:
1727
0
            goto pending;
1728
0
        default:
1729
0
            ssh_set_error(session,
1730
0
                          SSH_FATAL,
1731
0
                          "Wrong state (%d) during pending SSH call",
1732
0
                          session->pending_call_state);
1733
0
            return SSH_ERROR;
1734
0
    }
1735
1736
0
    rc = ssh_userauth_request_service(session);
1737
0
    if (rc == SSH_AGAIN) {
1738
0
        return SSH_AUTH_AGAIN;
1739
0
    } else if (rc == SSH_ERROR) {
1740
0
        return SSH_AUTH_ERROR;
1741
0
    }
1742
1743
    /* request */
1744
0
    rc = ssh_buffer_pack(session->out_buffer, "bsssbs",
1745
0
            SSH2_MSG_USERAUTH_REQUEST,
1746
0
            username ? username : session->opts.username,
1747
0
            "ssh-connection",
1748
0
            "password",
1749
0
            0, /* false */
1750
0
            password
1751
0
    );
1752
0
    if (rc < 0) {
1753
0
        goto fail;
1754
0
    }
1755
1756
    /* Set the buffer as secure to be explicitly zeroed when freed */
1757
0
    ssh_buffer_set_secure(session->out_buffer);
1758
1759
0
    session->auth.current_method = SSH_AUTH_METHOD_PASSWORD;
1760
0
    session->auth.state = SSH_AUTH_STATE_PASSWORD_AUTH_SENT;
1761
0
    session->pending_call_state = SSH_PENDING_CALL_AUTH_PASSWORD;
1762
0
    rc = ssh_packet_send(session);
1763
0
    if (rc == SSH_ERROR) {
1764
0
        return SSH_AUTH_ERROR;
1765
0
    }
1766
1767
0
pending:
1768
0
    rc = ssh_userauth_get_response(session);
1769
0
    if (rc != SSH_AUTH_AGAIN) {
1770
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
1771
0
    }
1772
1773
0
    return rc;
1774
0
fail:
1775
0
    ssh_set_error_oom(session);
1776
0
    ssh_buffer_reinit(session->out_buffer);
1777
1778
0
    return SSH_AUTH_ERROR;
1779
0
}
1780
1781
/* LEGACY */
1782
int ssh_userauth_agent_pubkey(ssh_session session,
1783
                              const char *username,
1784
                              ssh_public_key publickey)
1785
0
{
1786
0
    ssh_key key = NULL;
1787
0
    int rc;
1788
1789
0
    key = ssh_key_new();
1790
0
    if (key == NULL) {
1791
0
        return SSH_AUTH_ERROR;
1792
0
    }
1793
1794
0
    key->type = publickey->type;
1795
0
    key->type_c = ssh_key_type_to_char(key->type);
1796
0
    key->flags = SSH_KEY_FLAG_PUBLIC;
1797
#if defined(HAVE_LIBMBEDCRYPTO)
1798
    key->pk = publickey->rsa_pub;
1799
#elif defined(HAVE_LIBCRYPTO)
1800
    key->key = publickey->key_pub;
1801
#else
1802
    key->rsa = publickey->rsa_pub;
1803
#endif /* HAVE_LIBCRYPTO */
1804
1805
0
    rc = ssh_userauth_agent_publickey(session, username, key);
1806
1807
#if defined(HAVE_LIBMBEDCRYPTO)
1808
    key->pk = NULL;
1809
#elif defined(HAVE_LIBCRYPTO)
1810
    key->key = NULL;
1811
#else
1812
    key->rsa = NULL;
1813
#endif /* HAVE_LIBCRYPTO */
1814
0
    ssh_key_free(key);
1815
1816
0
    return rc;
1817
0
}
1818
1819
ssh_kbdint ssh_kbdint_new(void)
1820
0
{
1821
0
    ssh_kbdint kbd;
1822
1823
0
    kbd = calloc(1, sizeof(struct ssh_kbdint_struct));
1824
0
    if (kbd == NULL) {
1825
0
        return NULL;
1826
0
    }
1827
1828
0
    return kbd;
1829
0
}
1830
1831
1832
void ssh_kbdint_free(ssh_kbdint kbd)
1833
0
{
1834
0
    size_t i, n;
1835
1836
0
    if (kbd == NULL) {
1837
0
        return;
1838
0
    }
1839
1840
0
    SAFE_FREE(kbd->name);
1841
0
    SAFE_FREE(kbd->instruction);
1842
0
    SAFE_FREE(kbd->echo);
1843
1844
0
    n = kbd->nprompts;
1845
0
    if (kbd->prompts) {
1846
0
        for (i = 0; i < n; i++) {
1847
0
            if (kbd->prompts[i] != NULL) {
1848
0
                explicit_bzero(kbd->prompts[i], strlen(kbd->prompts[i]));
1849
0
            }
1850
0
            SAFE_FREE(kbd->prompts[i]);
1851
0
        }
1852
0
        SAFE_FREE(kbd->prompts);
1853
0
    }
1854
1855
0
    n = kbd->nanswers;
1856
0
    if (kbd->answers) {
1857
0
        for (i = 0; i < n; i++) {
1858
0
            if (kbd->answers[i] != NULL) {
1859
0
                explicit_bzero(kbd->answers[i], strlen(kbd->answers[i]));
1860
0
            }
1861
0
            SAFE_FREE(kbd->answers[i]);
1862
0
        }
1863
0
        SAFE_FREE(kbd->answers);
1864
0
    }
1865
1866
0
    SAFE_FREE(kbd);
1867
0
}
1868
1869
void ssh_kbdint_clean(ssh_kbdint kbd)
1870
0
{
1871
0
    size_t i, n;
1872
1873
0
    if (kbd == NULL) {
1874
0
        return;
1875
0
    }
1876
1877
0
    SAFE_FREE(kbd->name);
1878
0
    SAFE_FREE(kbd->instruction);
1879
0
    SAFE_FREE(kbd->echo);
1880
1881
0
    n = kbd->nprompts;
1882
0
    if (kbd->prompts) {
1883
0
        for (i = 0; i < n; i++) {
1884
0
            explicit_bzero(kbd->prompts[i], strlen(kbd->prompts[i]));
1885
0
            SAFE_FREE(kbd->prompts[i]);
1886
0
        }
1887
0
        SAFE_FREE(kbd->prompts);
1888
0
    }
1889
1890
0
    n = kbd->nanswers;
1891
1892
0
    if (kbd->answers) {
1893
0
        for (i = 0; i < n; i++) {
1894
0
            explicit_bzero(kbd->answers[i], strlen(kbd->answers[i]));
1895
0
            SAFE_FREE(kbd->answers[i]);
1896
0
        }
1897
0
        SAFE_FREE(kbd->answers);
1898
0
    }
1899
1900
0
    kbd->nprompts = 0;
1901
0
    kbd->nanswers = 0;
1902
0
}
1903
1904
/*
1905
 * This function sends the first packet as explained in RFC 3066 section 3.1.
1906
 */
1907
static int ssh_userauth_kbdint_init(ssh_session session,
1908
                                    const char *username,
1909
                                    const char *submethods)
1910
0
{
1911
0
    int rc;
1912
1913
0
    if (session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_INIT) {
1914
0
        goto pending;
1915
0
    }
1916
0
    if (session->pending_call_state != SSH_PENDING_CALL_NONE) {
1917
0
        ssh_set_error_invalid(session);
1918
0
        return SSH_ERROR;
1919
0
    }
1920
1921
0
    rc = ssh_userauth_request_service(session);
1922
0
    if (rc == SSH_AGAIN) {
1923
0
        return SSH_AUTH_AGAIN;
1924
0
    }
1925
0
    if (rc != SSH_OK) {
1926
0
        return SSH_AUTH_ERROR;
1927
0
    }
1928
1929
    /* request */
1930
0
    rc = ssh_buffer_pack(session->out_buffer, "bsssss",
1931
0
            SSH2_MSG_USERAUTH_REQUEST,
1932
0
            username ? username : session->opts.username,
1933
0
            "ssh-connection",
1934
0
            "keyboard-interactive",
1935
0
            "", /* lang (ignore it) */
1936
0
            submethods ? submethods : ""
1937
0
    );
1938
0
    if (rc < 0) {
1939
0
        goto fail;
1940
0
    }
1941
1942
1943
0
    session->auth.state = SSH_AUTH_STATE_KBDINT_SENT;
1944
0
    session->pending_call_state = SSH_PENDING_CALL_AUTH_KBDINT_INIT;
1945
1946
0
    SSH_LOG(SSH_LOG_DEBUG,
1947
0
            "Sending keyboard-interactive init request");
1948
1949
0
    rc = ssh_packet_send(session);
1950
0
    if (rc == SSH_ERROR) {
1951
0
        return SSH_AUTH_ERROR;
1952
0
    }
1953
0
pending:
1954
0
    rc = ssh_userauth_get_response(session);
1955
0
    if (rc != SSH_AUTH_AGAIN)
1956
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
1957
0
    return rc;
1958
0
fail:
1959
0
    ssh_set_error_oom(session);
1960
0
    ssh_buffer_reinit(session->out_buffer);
1961
1962
0
    return SSH_AUTH_ERROR;
1963
0
}
1964
1965
/**
1966
 * @internal
1967
 *
1968
 * @brief Send the current challenge response and wait for a reply from the
1969
 *        server.
1970
 *
1971
 * @returns SSH_AUTH_INFO if more info is needed
1972
 * @returns SSH_AUTH_SUCCESS
1973
 * @returns SSH_AUTH_FAILURE
1974
 * @returns SSH_AUTH_PARTIAL
1975
 */
1976
static int ssh_userauth_kbdint_send(ssh_session session)
1977
0
{
1978
0
    uint32_t i;
1979
0
    int rc;
1980
0
    if (session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_SEND)
1981
0
        goto pending;
1982
0
    if (session->pending_call_state != SSH_PENDING_CALL_NONE) {
1983
0
        ssh_set_error_invalid(session);
1984
0
        return SSH_ERROR;
1985
0
    }
1986
0
    rc = ssh_buffer_pack(session->out_buffer, "bd",
1987
0
            SSH2_MSG_USERAUTH_INFO_RESPONSE,
1988
0
            session->kbdint->nprompts);
1989
0
    if (rc < 0) {
1990
0
        goto fail;
1991
0
    }
1992
1993
0
    for (i = 0; i < session->kbdint->nprompts; i++) {
1994
0
        rc = ssh_buffer_pack(session->out_buffer, "s",
1995
0
                session->kbdint->answers && session->kbdint->answers[i] ?
1996
0
                        session->kbdint->answers[i]:"");
1997
0
        if (rc < 0) {
1998
0
            goto fail;
1999
0
        }
2000
0
    }
2001
2002
0
    session->auth.current_method = SSH_AUTH_METHOD_INTERACTIVE;
2003
0
    session->auth.state = SSH_AUTH_STATE_KBDINT_SENT;
2004
0
    session->pending_call_state = SSH_PENDING_CALL_AUTH_KBDINT_SEND;
2005
0
    ssh_kbdint_free(session->kbdint);
2006
0
    session->kbdint = NULL;
2007
2008
0
    SSH_LOG(SSH_LOG_DEBUG,
2009
0
            "Sending keyboard-interactive response packet");
2010
2011
0
    rc = ssh_packet_send(session);
2012
0
    if (rc == SSH_ERROR) {
2013
0
        return SSH_AUTH_ERROR;
2014
0
    }
2015
0
pending:
2016
0
    rc = ssh_userauth_get_response(session);
2017
0
    if (rc != SSH_AUTH_AGAIN)
2018
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
2019
0
    return rc;
2020
0
fail:
2021
0
    ssh_set_error_oom(session);
2022
0
    ssh_buffer_reinit(session->out_buffer);
2023
2024
0
    return SSH_AUTH_ERROR;
2025
0
}
2026
2027
/**
2028
 * @internal
2029
 * @brief handles a SSH_USERAUTH_INFO_REQUEST packet, as used in
2030
 *        keyboard-interactive authentication, and changes the
2031
 *        authentication state.
2032
 */
2033
0
SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) {
2034
0
    ssh_string tmp = NULL;
2035
0
    uint32_t nprompts;
2036
0
    uint32_t i;
2037
0
    int rc;
2038
0
    (void)user;
2039
0
    (void)type;
2040
2041
2042
0
    if (session->kbdint == NULL) {
2043
0
        session->kbdint = ssh_kbdint_new();
2044
0
        if (session->kbdint == NULL) {
2045
0
            ssh_set_error_oom(session);
2046
0
            return SSH_PACKET_USED;
2047
0
        }
2048
0
    } else {
2049
0
        ssh_kbdint_clean(session->kbdint);
2050
0
    }
2051
2052
0
    rc = ssh_buffer_unpack(packet, "ssSd",
2053
0
            &session->kbdint->name, /* name of the "asking" window shown to client */
2054
0
            &session->kbdint->instruction,
2055
0
            &tmp, /* to ignore */
2056
0
            &nprompts
2057
0
            );
2058
2059
    /* We don't care about tmp */
2060
0
    SSH_STRING_FREE(tmp);
2061
2062
0
    if (rc != SSH_OK) {
2063
0
        ssh_set_error(session, SSH_FATAL, "Invalid USERAUTH_INFO_REQUEST msg");
2064
0
        ssh_kbdint_free(session->kbdint);
2065
0
        session->kbdint = NULL;
2066
0
        return SSH_PACKET_USED;
2067
0
    }
2068
2069
0
    SSH_LOG(SSH_LOG_DEBUG,
2070
0
            "%" PRIu32 " keyboard-interactive prompts", nprompts);
2071
0
    if (nprompts > KBDINT_MAX_PROMPT) {
2072
0
        ssh_set_error(session, SSH_FATAL,
2073
0
                "Too much prompts requested by the server: %" PRIu32 " (0x%.4" PRIx32 ")",
2074
0
                nprompts, nprompts);
2075
0
        ssh_kbdint_free(session->kbdint);
2076
0
        session->kbdint = NULL;
2077
2078
0
        return SSH_PACKET_USED;
2079
0
    }
2080
2081
0
    session->kbdint->nprompts = nprompts;
2082
0
    session->kbdint->nanswers = nprompts;
2083
0
    session->kbdint->prompts = calloc(nprompts, sizeof(char *));
2084
0
    if (session->kbdint->prompts == NULL) {
2085
0
        session->kbdint->nprompts = 0;
2086
0
        ssh_set_error_oom(session);
2087
0
        ssh_kbdint_free(session->kbdint);
2088
0
        session->kbdint = NULL;
2089
2090
0
        return SSH_PACKET_USED;
2091
0
    }
2092
2093
0
    session->kbdint->echo = calloc(nprompts, sizeof(unsigned char));
2094
0
    if (session->kbdint->echo == NULL) {
2095
0
        session->kbdint->nprompts = 0;
2096
0
        ssh_set_error_oom(session);
2097
0
        ssh_kbdint_free(session->kbdint);
2098
0
        session->kbdint = NULL;
2099
2100
0
        return SSH_PACKET_USED;
2101
0
    }
2102
2103
0
    for (i = 0; i < nprompts; i++) {
2104
0
        rc = ssh_buffer_unpack(packet, "sb",
2105
0
                &session->kbdint->prompts[i],
2106
0
                &session->kbdint->echo[i]);
2107
0
        if (rc == SSH_ERROR) {
2108
0
            ssh_set_error(session, SSH_FATAL, "Short INFO_REQUEST packet");
2109
0
            ssh_kbdint_free(session->kbdint);
2110
0
            session->kbdint = NULL;
2111
2112
0
            return SSH_PACKET_USED;
2113
0
        }
2114
0
    }
2115
0
    session->auth.state=SSH_AUTH_STATE_INFO;
2116
2117
0
    return SSH_PACKET_USED;
2118
0
}
2119
2120
/**
2121
 * @brief Try to authenticate through the "keyboard-interactive" method.
2122
 *
2123
 * @param[in]  session  The ssh session to use.
2124
 *
2125
 * @param[in]  user     The username to authenticate. You can specify NULL if
2126
 *                      ssh_option_set_username() has been used. You cannot try
2127
 *                      two different logins in a row.
2128
 *
2129
 * @param[in]  submethods Undocumented. Set it to NULL.
2130
 *
2131
 * @returns SSH_AUTH_ERROR:   A serious error happened\n
2132
 *          SSH_AUTH_DENIED:  Authentication failed : use another method\n
2133
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
2134
 *                            have to use another method\n
2135
 *          SSH_AUTH_SUCCESS: Authentication success\n
2136
 *          SSH_AUTH_INFO:    The server asked some questions. Use
2137
 *                            ssh_userauth_kbdint_getnprompts() and such.\n
2138
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
2139
 *                            later.
2140
 *
2141
 * @see ssh_userauth_kbdint_getnprompts()
2142
 * @see ssh_userauth_kbdint_getname()
2143
 * @see ssh_userauth_kbdint_getinstruction()
2144
 * @see ssh_userauth_kbdint_getprompt()
2145
 * @see ssh_userauth_kbdint_setanswer()
2146
 */
2147
int ssh_userauth_kbdint(ssh_session session, const char *user,
2148
                        const char *submethods)
2149
0
{
2150
0
    int rc = SSH_AUTH_ERROR;
2151
2152
0
    if (session == NULL) {
2153
0
        return SSH_AUTH_ERROR;
2154
0
    }
2155
2156
0
    if ((session->pending_call_state == SSH_PENDING_CALL_NONE && session->kbdint == NULL) ||
2157
0
            session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_INIT)
2158
0
        rc = ssh_userauth_kbdint_init(session, user, submethods);
2159
0
    else if (session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_SEND ||
2160
0
            session->kbdint != NULL) {
2161
        /*
2162
         * If we are at this point, it is because session->kbdint exists.
2163
         * It means the user has set some information there we need to send
2164
         * the server and then we need to ack the status (new questions or ok
2165
         * pass in).
2166
         * It is possible that session->kbdint is NULL while we're waiting for
2167
         * a reply, hence the test for the pending call.
2168
         */
2169
0
        rc = ssh_userauth_kbdint_send(session);
2170
0
    } else {
2171
        /* We are here because session->kbdint == NULL & state != NONE.
2172
         * This should not happen
2173
         */
2174
0
        rc = SSH_AUTH_ERROR;
2175
0
        ssh_set_error(session, SSH_FATAL, "Invalid state in %s", __func__);
2176
0
    }
2177
0
    return rc;
2178
0
}
2179
2180
/**
2181
 * @brief Get the number of prompts (questions) the server has given.
2182
 *
2183
 * Once you have called ssh_userauth_kbdint() and received SSH_AUTH_INFO return
2184
 * code, this function can be used to retrieve information about the keyboard
2185
 * interactive authentication questions sent by the remote host.
2186
 *
2187
 * @param[in]  session  The ssh session to use.
2188
 *
2189
 * @returns             The number of prompts.
2190
 */
2191
int ssh_userauth_kbdint_getnprompts(ssh_session session)
2192
0
{
2193
0
    if (session == NULL) {
2194
0
        return SSH_ERROR;
2195
0
    }
2196
0
    if (session->kbdint == NULL) {
2197
0
        ssh_set_error_invalid(session);
2198
0
        return SSH_ERROR;
2199
0
    }
2200
0
    return session->kbdint->nprompts;
2201
0
}
2202
2203
/**
2204
 * @brief Get the "name" of the message block.
2205
 *
2206
 * Once you have called ssh_userauth_kbdint() and received SSH_AUTH_INFO return
2207
 * code, this function can be used to retrieve information about the keyboard
2208
 * interactive authentication questions sent by the remote host.
2209
 *
2210
 * @param[in]  session  The ssh session to use.
2211
 *
2212
 * @returns             The name of the message block. Do not free it.
2213
 */
2214
const char *ssh_userauth_kbdint_getname(ssh_session session)
2215
0
{
2216
0
    if (session == NULL) {
2217
0
        return NULL;
2218
0
    }
2219
0
    if (session->kbdint == NULL) {
2220
0
        ssh_set_error_invalid(session);
2221
0
        return NULL;
2222
0
    }
2223
0
    return session->kbdint->name;
2224
0
}
2225
2226
/**
2227
 * @brief Get the "instruction" of the message block.
2228
 *
2229
 * Once you have called ssh_userauth_kbdint() and received SSH_AUTH_INFO return
2230
 * code, this function can be used to retrieve information about the keyboard
2231
 * interactive authentication questions sent by the remote host.
2232
 *
2233
 * @param[in]  session  The ssh session to use.
2234
 *
2235
 * @returns             The instruction of the message block.
2236
 */
2237
2238
const char *ssh_userauth_kbdint_getinstruction(ssh_session session)
2239
0
{
2240
0
    if (session == NULL)
2241
0
        return NULL;
2242
0
    if (session->kbdint == NULL) {
2243
0
        ssh_set_error_invalid(session);
2244
0
        return NULL;
2245
0
    }
2246
0
    return session->kbdint->instruction;
2247
0
}
2248
2249
/**
2250
 * @brief Get a prompt from a message block.
2251
 *
2252
 * Once you have called ssh_userauth_kbdint() and received SSH_AUTH_INFO return
2253
 * code, this function can be used to retrieve information about the keyboard
2254
 * interactive authentication questions sent by the remote host.
2255
 *
2256
 * @param[in]  session  The ssh session to use.
2257
 *
2258
 * @param[in]  i        The index number of the i'th prompt.
2259
 *
2260
 * @param[out] echo     This is an optional variable. You can obtain a
2261
 *                      boolean if the user input should be echoed or
2262
 *                      hidden. For passwords it is usually hidden.
2263
 *
2264
 * @returns             A pointer to the prompt. Do not free it.
2265
 *
2266
 * @code
2267
 *   const char prompt;
2268
 *   char echo;
2269
 *
2270
 *   prompt = ssh_userauth_kbdint_getprompt(session, 0, &echo);
2271
 *   if (echo) ...
2272
 * @endcode
2273
 */
2274
const char *
2275
ssh_userauth_kbdint_getprompt(ssh_session session, unsigned int i, char *echo)
2276
0
{
2277
0
    if (session == NULL)
2278
0
        return NULL;
2279
0
    if (session->kbdint == NULL) {
2280
0
        ssh_set_error_invalid(session);
2281
0
        return NULL;
2282
0
    }
2283
0
    if (i > session->kbdint->nprompts) {
2284
0
        ssh_set_error_invalid(session);
2285
0
        return NULL;
2286
0
    }
2287
2288
0
    if (echo) {
2289
0
        *echo = (char)session->kbdint->echo[i];
2290
0
    }
2291
2292
0
    return session->kbdint->prompts[i];
2293
0
}
2294
2295
#ifdef WITH_SERVER
2296
/**
2297
 * @brief Get the number of answers the client has given.
2298
 *
2299
 * @param[in]  session  The ssh session to use.
2300
 *
2301
 * @returns             The number of answers.
2302
 */
2303
int ssh_userauth_kbdint_getnanswers(ssh_session session)
2304
0
{
2305
0
    if (session == NULL || session->kbdint == NULL) {
2306
0
        return SSH_ERROR;
2307
0
    }
2308
0
    return session->kbdint->nanswers;
2309
0
}
2310
2311
/**
2312
 * @brief Get the answer to a question from a message block.
2313
 *
2314
 * @param[in]  session  The ssh session to use.
2315
 *
2316
 * @param[in]  i index  The number of the ith answer.
2317
 *
2318
 * @return              The answer string, or NULL if the answer is not
2319
 *                      available. Do not free the string.
2320
 */
2321
const char *ssh_userauth_kbdint_getanswer(ssh_session session, unsigned int i)
2322
0
{
2323
0
    if (session == NULL || session->kbdint == NULL
2324
0
            || session->kbdint->answers == NULL) {
2325
0
        return NULL;
2326
0
    }
2327
0
    if (i >= session->kbdint->nanswers) {
2328
0
        return NULL;
2329
0
    }
2330
2331
0
    return session->kbdint->answers[i];
2332
0
}
2333
#endif
2334
2335
/**
2336
 * @brief Set the answer for a question from a message block.
2337
 *
2338
 * If you have called ssh_userauth_kbdint() and got SSH_AUTH_INFO, this
2339
 * function returns the questions from the server.
2340
 *
2341
 * @param[in]  session  The ssh session to use.
2342
 *
2343
 * @param[in]  i index  The number of the ith prompt.
2344
 *
2345
 * @param[in]  answer   The answer to give to the server. The answer MUST be
2346
 *                      encoded UTF-8. It is up to the server how to interpret
2347
 *                      the value and validate it. However, if you read the
2348
 *                      answer in some other encoding, you MUST convert it to
2349
 *                      UTF-8.
2350
 *
2351
 * @return              0 on success, < 0 on error.
2352
 */
2353
int
2354
ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i,
2355
                              const char *answer)
2356
0
{
2357
0
    if (session == NULL) {
2358
0
        return -1;
2359
0
    }
2360
0
    if (answer == NULL || session->kbdint == NULL ||
2361
0
            i >= session->kbdint->nprompts) {
2362
0
        ssh_set_error_invalid(session);
2363
0
        return -1;
2364
0
    }
2365
2366
0
    if (session->kbdint->answers == NULL) {
2367
0
        session->kbdint->answers = calloc(session->kbdint->nprompts, sizeof(char *));
2368
0
        if (session->kbdint->answers == NULL) {
2369
0
            ssh_set_error_oom(session);
2370
0
            return -1;
2371
0
        }
2372
0
    }
2373
2374
0
    if (session->kbdint->answers[i]) {
2375
0
        explicit_bzero(session->kbdint->answers[i],
2376
0
                strlen(session->kbdint->answers[i]));
2377
0
        SAFE_FREE(session->kbdint->answers[i]);
2378
0
    }
2379
2380
0
    session->kbdint->answers[i] = strdup(answer);
2381
0
    if (session->kbdint->answers[i] == NULL) {
2382
0
        ssh_set_error_oom(session);
2383
0
        return -1;
2384
0
    }
2385
2386
0
    return 0;
2387
0
}
2388
2389
/**
2390
 * @brief Try to authenticate through the "gssapi-with-mic" method.
2391
 *
2392
 * @param[in]  session  The ssh session to use.
2393
 *
2394
 * @returns SSH_AUTH_ERROR:   A serious error happened\n
2395
 *          SSH_AUTH_DENIED:  Authentication failed : use another method\n
2396
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
2397
 *                            have to use another method\n
2398
 *          SSH_AUTH_SUCCESS: Authentication success\n
2399
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
2400
 *                            later.
2401
 */
2402
int ssh_userauth_gssapi(ssh_session session)
2403
0
{
2404
0
    int rc = SSH_AUTH_DENIED;
2405
#ifdef WITH_GSSAPI
2406
    switch(session->pending_call_state) {
2407
    case SSH_PENDING_CALL_NONE:
2408
        break;
2409
    case SSH_PENDING_CALL_AUTH_GSSAPI_MIC:
2410
        goto pending;
2411
    default:
2412
        ssh_set_error(session,
2413
                SSH_FATAL,
2414
                "Wrong state (%d) during pending SSH call",
2415
                session->pending_call_state);
2416
        return SSH_ERROR;
2417
    }
2418
2419
    rc = ssh_userauth_request_service(session);
2420
    if (rc == SSH_AGAIN) {
2421
        return SSH_AUTH_AGAIN;
2422
    } else if (rc == SSH_ERROR) {
2423
        return SSH_AUTH_ERROR;
2424
    }
2425
    SSH_LOG(SSH_LOG_DEBUG, "Authenticating with gssapi-with-mic");
2426
2427
    session->auth.current_method = SSH_AUTH_METHOD_GSSAPI_MIC;
2428
    session->auth.state = SSH_AUTH_STATE_NONE;
2429
    session->pending_call_state = SSH_PENDING_CALL_AUTH_GSSAPI_MIC;
2430
    rc = ssh_gssapi_auth_mic(session);
2431
2432
    if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_DENIED) {
2433
        session->auth.state = SSH_AUTH_STATE_NONE;
2434
        session->pending_call_state = SSH_PENDING_CALL_NONE;
2435
        return rc;
2436
    }
2437
2438
pending:
2439
    rc = ssh_userauth_get_response(session);
2440
    if (rc != SSH_AUTH_AGAIN) {
2441
        session->pending_call_state = SSH_PENDING_CALL_NONE;
2442
    }
2443
#else
2444
0
    (void) session; /* unused */
2445
0
#endif
2446
0
    return rc;
2447
0
}
2448
2449
/** @} */