Coverage Report

Created: 2025-07-01 07:11

/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
8
{
71
8
    int rc;
72
73
8
    rc = ssh_service_request(session, "ssh-userauth");
74
8
    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
8
    return rc;
80
8
}
81
82
static int ssh_auth_response_termination(void *user)
83
158
{
84
158
    ssh_session session = (ssh_session)user;
85
158
    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
158
        case SSH_AUTH_STATE_AUTH_NONE_SENT:
95
158
            return 0;
96
0
        default:
97
0
            return 1;
98
158
    }
99
158
}
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
5
{
146
5
    int rc = SSH_AUTH_ERROR;
147
148
5
    rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER,
149
5
        ssh_auth_response_termination, session);
150
5
    if (rc == SSH_ERROR) {
151
5
        return SSH_AUTH_ERROR;
152
5
    }
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
43
{
200
43
    ssh_string banner = NULL;
201
43
    (void)type;
202
43
    (void)user;
203
204
43
    banner = ssh_buffer_get_ssh_string(packet);
205
43
    if (banner == NULL) {
206
28
        SSH_LOG(SSH_LOG_TRACE,
207
28
                "Invalid SSH_USERAUTH_BANNER packet");
208
28
    } 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
43
    return SSH_PACKET_USED;
217
43
}
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
8
{
412
8
    int rc;
413
414
8
    switch (session->pending_call_state) {
415
8
        case SSH_PENDING_CALL_NONE:
416
8
            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
8
    }
425
426
8
    rc = ssh_userauth_request_service(session);
427
8
    if (rc == SSH_AGAIN) {
428
1
        return SSH_AUTH_AGAIN;
429
7
    } else if (rc == SSH_ERROR) {
430
2
        return SSH_AUTH_ERROR;
431
2
    }
432
433
    /* request */
434
5
    rc = ssh_buffer_pack(session->out_buffer, "bsss",
435
5
            SSH2_MSG_USERAUTH_REQUEST,
436
5
            username ? username : session->opts.username,
437
5
            "ssh-connection",
438
5
            "none"
439
5
            );
440
5
    if (rc < 0) {
441
0
        goto fail;
442
0
    }
443
444
5
    session->auth.current_method = SSH_AUTH_METHOD_NONE;
445
5
    session->auth.state = SSH_AUTH_STATE_AUTH_NONE_SENT;
446
5
    session->pending_call_state = SSH_PENDING_CALL_AUTH_NONE;
447
5
    rc = ssh_packet_send(session);
448
5
    if (rc == SSH_ERROR) {
449
0
        return SSH_AUTH_ERROR;
450
0
    }
451
452
5
pending:
453
5
    rc = ssh_userauth_get_response(session);
454
5
    if (rc != SSH_AUTH_AGAIN) {
455
5
        session->pending_call_state = SSH_PENDING_CALL_NONE;
456
5
    }
457
458
5
    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
5
}
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
10.1k
{
980
10.1k
    struct ssh_agent_state_struct *state = data;
981
982
10.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
10.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 = malloc(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
        ZERO_STRUCTP(session->agent_state);
1036
0
        session->agent_state->state = SSH_AGENT_STATE_NONE;
1037
0
    }
1038
1039
0
    state = session->agent_state;
1040
0
    if (state->pubkey == NULL) {
1041
0
        state->pubkey = ssh_agent_get_first_ident(session, &state->comment);
1042
0
    }
1043
1044
0
    if (state->pubkey == NULL) {
1045
0
        return SSH_AUTH_DENIED;
1046
0
    }
1047
1048
0
    if (session->opts.identities_only) {
1049
        /*
1050
         * Read keys mentioned in the config, so we can check if key from agent
1051
         * is in there.
1052
         */
1053
0
        size_t identityLen = ssh_list_count(session->opts.identity);
1054
0
        size_t certsLen = ssh_list_count(session->opts.certificate);
1055
0
        struct ssh_iterator *it = ssh_list_get_iterator(session->opts.identity);
1056
1057
0
        configKeys = malloc(identityLen * sizeof(ssh_key));
1058
0
        configCerts = malloc((certsLen + identityLen) * sizeof(ssh_key));
1059
0
        if (configKeys == NULL || configCerts == NULL) {
1060
0
            free(configKeys);
1061
0
            free(configCerts);
1062
0
            ssh_set_error_oom(session);
1063
0
            return SSH_AUTH_ERROR;
1064
0
        }
1065
1066
0
        while (it != NULL && configKeysCount < identityLen) {
1067
0
            const char *privkeyFile = it->data;
1068
0
            size_t certPathLen;
1069
0
            char *certFile = NULL;
1070
0
            ssh_key pubkey = NULL;
1071
0
            ssh_key cert = NULL;
1072
1073
            /*
1074
             * Read the private key file listed in the config, but we're only
1075
             * interested in the public key. Don't try to decrypt private key.
1076
             */
1077
0
            rc = ssh_pki_import_pubkey_file(privkeyFile, &pubkey);
1078
0
            if (rc == SSH_OK) {
1079
0
                configKeys[configKeysCount++] = pubkey;
1080
0
            } else {
1081
0
                char *pubkeyFile = NULL;
1082
0
                size_t pubkeyPathLen = strlen(privkeyFile) + sizeof(".pub");
1083
1084
0
                SSH_KEY_FREE(pubkey);
1085
1086
                /*
1087
                * If we couldn't get the public key from the private key file,
1088
                * try a .pub file instead.
1089
                */
1090
0
                pubkeyFile = malloc(pubkeyPathLen);
1091
0
                if (!pubkeyFile) {
1092
0
                    ssh_set_error_oom(session);
1093
0
                    rc = SSH_AUTH_ERROR;
1094
0
                    goto done;
1095
0
                }
1096
0
                snprintf(pubkeyFile, pubkeyPathLen, "%s.pub", privkeyFile);
1097
0
                rc = ssh_pki_import_pubkey_file(pubkeyFile, &pubkey);
1098
0
                free(pubkeyFile);
1099
0
                if (rc == SSH_OK) {
1100
0
                    configKeys[configKeysCount++] = pubkey;
1101
0
                } else if (pubkey) {
1102
0
                    SSH_KEY_FREE(pubkey);
1103
0
                }
1104
0
            }
1105
            /* Now try to see if there is a certificate with default name
1106
             * do not merge it yet with the key as we need to try first the
1107
             * non-certified key */
1108
0
            certPathLen = strlen(privkeyFile) + sizeof("-cert.pub");
1109
0
            certFile = malloc(certPathLen);
1110
0
            if (!certFile) {
1111
0
                ssh_set_error_oom(session);
1112
0
                rc = SSH_AUTH_ERROR;
1113
0
                goto done;
1114
0
            }
1115
0
            snprintf(certFile, certPathLen, "%s-cert.pub", privkeyFile);
1116
0
            rc = ssh_pki_import_cert_file(certFile, &cert);
1117
0
            free(certFile);
1118
0
            if (rc == SSH_OK) {
1119
0
                configCerts[configCertsCount++] = cert;
1120
0
            } else if (cert) {
1121
0
                SSH_KEY_FREE(cert);
1122
0
            }
1123
1124
0
            it = it->next;
1125
0
        }
1126
        /* And now load separately-listed certificates. */
1127
0
        it = ssh_list_get_iterator(session->opts.certificate);
1128
0
        while (it != NULL && configCertsCount < certsLen + identityLen) {
1129
0
            const char *certFile = it->data;
1130
0
            ssh_key cert = NULL;
1131
1132
0
            rc = ssh_pki_import_cert_file(certFile, &cert);
1133
0
            if (rc == SSH_OK) {
1134
0
                configCerts[configCertsCount++] = cert;
1135
0
            } else if (cert) {
1136
0
                SSH_KEY_FREE(cert);
1137
0
            }
1138
1139
0
            it = it->next;
1140
0
        }
1141
0
    }
1142
1143
0
    while (state->pubkey != NULL) {
1144
0
        if (state->state == SSH_AGENT_STATE_NONE) {
1145
0
            SSH_LOG(SSH_LOG_DEBUG,
1146
0
                    "Trying identity %s",
1147
0
                    state->comment);
1148
0
            if (session->opts.identities_only) {
1149
                /* Check if this key is one of the keys listed in the config */
1150
0
                bool found_key = false;
1151
0
                for (i = 0; i < configKeysCount; i++) {
1152
0
                    int cmp = ssh_key_cmp(state->pubkey,
1153
0
                                          configKeys[i],
1154
0
                                          SSH_KEY_CMP_PUBLIC);
1155
0
                    if (cmp == 0) {
1156
0
                        found_key = true;
1157
0
                        break;
1158
0
                    }
1159
0
                }
1160
                /* or in separate certificates */
1161
0
                for (i = 0; i < configCertsCount; i++) {
1162
0
                    int cmp = ssh_key_cmp(state->pubkey,
1163
0
                                          configCerts[i],
1164
0
                                          SSH_KEY_CMP_PUBLIC);
1165
0
                    if (cmp == 0) {
1166
0
                        found_key = true;
1167
0
                        break;
1168
0
                    }
1169
0
                }
1170
1171
0
                if (!found_key) {
1172
0
                    SSH_LOG(SSH_LOG_DEBUG,
1173
0
                            "Identities only is enabled and identity %s was "
1174
0
                            "not listed in config, skipping",
1175
0
                            state->comment);
1176
0
                    SSH_STRING_FREE_CHAR(state->comment);
1177
0
                    state->comment = NULL;
1178
0
                    SSH_KEY_FREE(state->pubkey);
1179
0
                    state->pubkey = ssh_agent_get_next_ident(
1180
0
                        session, &state->comment);
1181
1182
0
                    if (state->pubkey == NULL) {
1183
0
                        rc = SSH_AUTH_DENIED;
1184
0
                    }
1185
0
                    continue;
1186
0
                }
1187
0
            }
1188
0
        }
1189
0
        if (state->state == SSH_AGENT_STATE_NONE ||
1190
0
            state->state == SSH_AGENT_STATE_PUBKEY ||
1191
0
            state->state == SSH_AGENT_STATE_CERT) {
1192
0
            rc = ssh_userauth_try_publickey(session, username, state->pubkey);
1193
0
            if (rc == SSH_AUTH_ERROR) {
1194
0
                ssh_agent_state_free(state);
1195
0
                session->agent_state = NULL;
1196
0
                goto done;
1197
0
            } else if (rc == SSH_AUTH_AGAIN) {
1198
0
                state->state = (state->state == SSH_AGENT_STATE_NONE ?
1199
0
                                SSH_AGENT_STATE_PUBKEY : state->state);
1200
0
                goto done;
1201
0
            } else if (rc != SSH_AUTH_SUCCESS) {
1202
0
                SSH_LOG(SSH_LOG_DEBUG,
1203
0
                        "Public key of %s refused by server",
1204
0
                        state->comment);
1205
0
                if (state->state == SSH_AGENT_STATE_PUBKEY) {
1206
0
                    for (i = 0; i < configCertsCount; i++) {
1207
0
                        int cmp = ssh_key_cmp(state->pubkey,
1208
0
                                              configCerts[i],
1209
0
                                              SSH_KEY_CMP_PUBLIC);
1210
0
                        if (cmp == 0) {
1211
0
                            SSH_LOG(SSH_LOG_DEBUG,
1212
0
                                    "Retry with matching certificate");
1213
0
                            SSH_KEY_FREE(state->pubkey);
1214
0
                            state->pubkey = ssh_key_dup(configCerts[i]);
1215
0
                            state->state = SSH_AGENT_STATE_CERT;
1216
0
                            continue;
1217
0
                        }
1218
0
                    }
1219
0
                }
1220
0
                SSH_STRING_FREE_CHAR(state->comment);
1221
0
                state->comment = NULL;
1222
0
                SSH_KEY_FREE(state->pubkey);
1223
0
                state->pubkey = ssh_agent_get_next_ident(session,
1224
0
                                                         &state->comment);
1225
0
                state->state = SSH_AGENT_STATE_NONE;
1226
0
                continue;
1227
0
            }
1228
1229
0
            SSH_LOG(SSH_LOG_DEBUG,
1230
0
                    "Public key of %s accepted by server",
1231
0
                    state->comment);
1232
0
            state->state = SSH_AGENT_STATE_AUTH;
1233
0
        }
1234
0
        if (state->state == SSH_AGENT_STATE_AUTH) {
1235
0
            rc = ssh_userauth_agent_publickey(session, username, state->pubkey);
1236
0
            if (rc == SSH_AUTH_AGAIN) {
1237
0
                goto done;
1238
0
            }
1239
0
            SSH_STRING_FREE_CHAR(state->comment);
1240
0
            state->comment = NULL;
1241
0
            if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_PARTIAL) {
1242
0
                ssh_agent_state_free(session->agent_state);
1243
0
                session->agent_state = NULL;
1244
0
                goto done;
1245
0
            } else if (rc != SSH_AUTH_SUCCESS) {
1246
0
                SSH_LOG(SSH_LOG_DEBUG,
1247
0
                        "Server accepted public key but refused the signature");
1248
0
                SSH_KEY_FREE(state->pubkey);
1249
0
                state->pubkey = ssh_agent_get_next_ident(session,
1250
0
                                                         &state->comment);
1251
0
                state->state = SSH_AGENT_STATE_NONE;
1252
0
                continue;
1253
0
            }
1254
0
            ssh_agent_state_free (session->agent_state);
1255
0
            session->agent_state = NULL;
1256
0
            rc = SSH_AUTH_SUCCESS;
1257
0
            goto done;
1258
0
        }
1259
0
    }
1260
1261
0
    ssh_agent_state_free (session->agent_state);
1262
0
    session->agent_state = NULL;
1263
0
done:
1264
0
    for (i = 0; i < configKeysCount; i++) {
1265
0
        ssh_key_free(configKeys[i]);
1266
0
    }
1267
0
    free(configKeys);
1268
0
    for (i = 0; i < configCertsCount; i++) {
1269
0
        ssh_key_free(configCerts[i]);
1270
0
    }
1271
0
    free(configCerts);
1272
0
    return rc;
1273
0
}
1274
1275
enum ssh_auth_auto_state_e {
1276
    SSH_AUTH_AUTO_STATE_NONE = 0,
1277
    SSH_AUTH_AUTO_STATE_PUBKEY,
1278
    SSH_AUTH_AUTO_STATE_KEY_IMPORTED,
1279
    SSH_AUTH_AUTO_STATE_CERTIFICATE_FILE,
1280
    SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION,
1281
    SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED
1282
};
1283
1284
struct ssh_auth_auto_state_struct {
1285
    enum ssh_auth_auto_state_e state;
1286
    struct ssh_iterator *it;
1287
    ssh_key privkey;
1288
    ssh_key pubkey;
1289
    ssh_key cert;
1290
    struct ssh_iterator *cert_it;
1291
};
1292
1293
/**
1294
 * @brief Get the identity that is currently being processed by
1295
 * ssh_userauth_publickey_auto()
1296
 *
1297
 * This is meant to be used by a callback that happens as part of the
1298
 * execution of ssh_userauth_publickey_auto().  The auth_function
1299
 * callback might want to know which key a passphrase is needed for,
1300
 * for example.
1301
 *
1302
 * @param[in]  session     The SSH session.
1303
 *
1304
 * @param[out] value       The value to get into. As a char**, space will be
1305
 *                         allocated by the function for the value, it is
1306
 *                         your responsibility to free the memory using
1307
 *                         ssh_string_free_char().
1308
 *
1309
 * @return  SSH_OK on success, SSH_ERROR on error.
1310
 */
1311
int ssh_userauth_publickey_auto_get_current_identity(ssh_session session,
1312
                                                     char** value)
1313
0
{
1314
0
    const char *id = NULL;
1315
1316
0
    if (session == NULL) {
1317
0
        return SSH_ERROR;
1318
0
    }
1319
1320
0
    if (value == NULL) {
1321
0
        ssh_set_error_invalid(session);
1322
0
        return SSH_ERROR;
1323
0
    }
1324
1325
0
    if (session->auth.auto_state != NULL &&
1326
0
        session->auth.auto_state->it != NULL) {
1327
0
        id = session->auth.auto_state->it->data;
1328
0
    }
1329
1330
0
    if (id == NULL) {
1331
0
        return SSH_ERROR;
1332
0
    }
1333
1334
0
    *value = strdup(id);
1335
0
    if (*value == NULL) {
1336
0
        ssh_set_error_oom(session);
1337
0
        return SSH_ERROR;
1338
0
    }
1339
1340
0
    return SSH_OK;
1341
0
}
1342
1343
/**
1344
 * @brief Tries to automatically authenticate with public key and "none"
1345
 *
1346
 * It may fail, for instance it doesn't ask for a password and uses a default
1347
 * asker for passphrases (in case the private key is encrypted).
1348
 *
1349
 * @param[in]  session     The SSH session.
1350
 *
1351
 * @param[in]  username    The username, this SHOULD be NULL.
1352
 *
1353
 * @param[in]  passphrase  Use this passphrase to unlock the privatekey. Use NULL
1354
 *                         if you don't want to use a passphrase or the user
1355
 *                         should be asked.
1356
 *
1357
 * @return  SSH_AUTH_ERROR:   A serious error happened.\n
1358
 *          SSH_AUTH_DENIED:  The server doesn't accept that public key as an
1359
 *                            authentication token. Try another key or another
1360
 *                            method.\n
1361
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
1362
 *                            have to use another method.\n
1363
 *          SSH_AUTH_SUCCESS: Authentication success\n
1364
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
1365
 *                            later.
1366
 *
1367
 * @note Most server implementations do not permit changing the username during
1368
 * authentication. The username should only be set with ssh_options_set() only
1369
 * before you connect to the server.
1370
 *
1371
 * The OpenSSH iterates over the identities and first try the plain public key
1372
 * and then the certificate if it is in place.
1373
 */
1374
int ssh_userauth_publickey_auto(ssh_session session,
1375
                                const char *username,
1376
                                const char *passphrase)
1377
0
{
1378
0
    ssh_auth_callback auth_fn = NULL;
1379
0
    void *auth_data = NULL;
1380
0
    struct ssh_auth_auto_state_struct *state = NULL;
1381
0
    int rc;
1382
1383
0
    if (session == NULL) {
1384
0
        return SSH_AUTH_ERROR;
1385
0
    }
1386
0
    if (! (session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH)) {
1387
0
        session->auth.supported_methods &= ~SSH_AUTH_METHOD_PUBLICKEY;
1388
0
        return SSH_AUTH_DENIED;
1389
0
    }
1390
0
    if (session->common.callbacks) {
1391
0
        auth_fn = session->common.callbacks->auth_function;
1392
0
        auth_data = session->common.callbacks->userdata;
1393
0
    }
1394
0
    if (!session->auth.auto_state) {
1395
0
        session->auth.auto_state =
1396
0
                calloc(1, sizeof(struct ssh_auth_auto_state_struct));
1397
0
        if (!session->auth.auto_state) {
1398
0
            ssh_set_error_oom(session);
1399
0
            return SSH_AUTH_ERROR;
1400
0
        }
1401
1402
        /* Set state explicitly */
1403
0
        session->auth.auto_state->state = SSH_AUTH_AUTO_STATE_NONE;
1404
0
    }
1405
0
    state = session->auth.auto_state;
1406
0
    if (state->state == SSH_AUTH_AUTO_STATE_NONE) {
1407
        /* Try authentication with ssh-agent first */
1408
0
        rc = ssh_userauth_agent(session, username);
1409
0
        if (rc == SSH_AUTH_SUCCESS ||
1410
0
            rc == SSH_AUTH_PARTIAL ||
1411
0
            rc == SSH_AUTH_AGAIN) {
1412
0
            return rc;
1413
0
        }
1414
0
        state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1415
0
    }
1416
0
    if (state->it == NULL) {
1417
0
        state->it = ssh_list_get_iterator(session->opts.identity);
1418
0
    }
1419
1420
0
    while (state->it != NULL) {
1421
0
        const char *privkey_file = state->it->data;
1422
0
        char pubkey_file[PATH_MAX] = {0};
1423
1424
0
        if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY) {
1425
0
            SSH_LOG(SSH_LOG_DEBUG,
1426
0
                    "Trying to authenticate with %s",
1427
0
                    privkey_file);
1428
0
            state->cert = NULL;
1429
0
            state->privkey = NULL;
1430
0
            state->pubkey = NULL;
1431
1432
#ifdef WITH_PKCS11_URI
1433
            if (ssh_pki_is_uri(privkey_file)) {
1434
                char *pub_uri_from_priv = NULL;
1435
                SSH_LOG(SSH_LOG_INFO,
1436
                        "Authenticating with PKCS #11 URI.");
1437
                pub_uri_from_priv = ssh_pki_export_pub_uri_from_priv_uri(privkey_file);
1438
                if (pub_uri_from_priv == NULL) {
1439
                    return SSH_ERROR;
1440
                } else {
1441
                    snprintf(pubkey_file,
1442
                             sizeof(pubkey_file),
1443
                             "%s",
1444
                             pub_uri_from_priv);
1445
                    SAFE_FREE(pub_uri_from_priv);
1446
                }
1447
            } else
1448
#endif /* WITH_PKCS11_URI */
1449
0
            {
1450
0
                snprintf(pubkey_file,
1451
0
                         sizeof(pubkey_file),
1452
0
                         "%s.pub",
1453
0
                         privkey_file);
1454
0
            }
1455
1456
0
            rc = ssh_pki_import_pubkey_file(pubkey_file, &state->pubkey);
1457
0
            if (rc == SSH_ERROR) {
1458
0
                ssh_set_error(session,
1459
0
                              SSH_FATAL,
1460
0
                              "Failed to import public key: %s",
1461
0
                              pubkey_file);
1462
0
                SAFE_FREE(session->auth.auto_state);
1463
0
                return SSH_AUTH_ERROR;
1464
0
            } else if (rc == SSH_EOF) {
1465
                /* Read the private key and save the public key to file */
1466
0
                rc = ssh_pki_import_privkey_file(privkey_file,
1467
0
                                                 passphrase,
1468
0
                                                 auth_fn,
1469
0
                                                 auth_data,
1470
0
                                                 &state->privkey);
1471
0
                if (rc == SSH_ERROR) {
1472
0
                    ssh_set_error(session,
1473
0
                                  SSH_FATAL,
1474
0
                                  "Failed to read private key: %s",
1475
0
                                  privkey_file);
1476
0
                    state->it = state->it->next;
1477
0
                    continue;
1478
0
                } else if (rc == SSH_EOF) {
1479
                    /* If the file doesn't exist, continue */
1480
0
                    SSH_LOG(SSH_LOG_DEBUG,
1481
0
                            "Private key %s doesn't exist.",
1482
0
                            privkey_file);
1483
0
                    state->it = state->it->next;
1484
0
                    continue;
1485
0
                }
1486
1487
0
                rc = ssh_pki_export_privkey_to_pubkey(state->privkey,
1488
0
                                                      &state->pubkey);
1489
0
                if (rc == SSH_ERROR) {
1490
0
                    SSH_KEY_FREE(state->privkey);
1491
0
                    SAFE_FREE(session->auth.auto_state);
1492
0
                    return SSH_AUTH_ERROR;
1493
0
                }
1494
1495
0
                rc = ssh_pki_export_pubkey_file(state->pubkey, pubkey_file);
1496
0
                if (rc == SSH_ERROR) {
1497
0
                    SSH_LOG(SSH_LOG_TRACE,
1498
0
                            "Could not write public key to file: %s",
1499
0
                            pubkey_file);
1500
0
                }
1501
0
            }
1502
0
            state->state = SSH_AUTH_AUTO_STATE_KEY_IMPORTED;
1503
0
        }
1504
0
        if (state->state == SSH_AUTH_AUTO_STATE_KEY_IMPORTED ||
1505
0
            state->state == SSH_AUTH_AUTO_STATE_CERTIFICATE_FILE ||
1506
0
            state->state == SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION) {
1507
0
            ssh_key k = state->pubkey;
1508
0
            if (state->state != SSH_AUTH_AUTO_STATE_KEY_IMPORTED) {
1509
0
                k = state->cert;
1510
0
            }
1511
0
            rc = ssh_userauth_try_publickey(session, username, k);
1512
0
            if (rc == SSH_AUTH_ERROR) {
1513
0
                SSH_LOG(SSH_LOG_TRACE,
1514
0
                        "Public key authentication error for %s",
1515
0
                        privkey_file);
1516
0
                SSH_KEY_FREE(state->cert);
1517
0
                SSH_KEY_FREE(state->privkey);
1518
0
                SSH_KEY_FREE(state->pubkey);
1519
0
                SAFE_FREE(session->auth.auto_state);
1520
0
                return rc;
1521
0
            } else if (rc == SSH_AUTH_AGAIN) {
1522
0
                return rc;
1523
0
            } else if (rc != SSH_AUTH_SUCCESS) {
1524
0
                int r; /* do not reuse `rc` as it is used to return from here */
1525
0
                SSH_KEY_FREE(state->cert);
1526
0
                SSH_LOG(SSH_LOG_DEBUG,
1527
0
                        "Public key for %s%s refused by server",
1528
0
                        privkey_file,
1529
0
                        (state->state != SSH_AUTH_AUTO_STATE_KEY_IMPORTED
1530
0
                            ? " (with certificate)" : ""));
1531
                /* Try certificate file by appending -cert.pub (if present) */
1532
0
                if (state->state == SSH_AUTH_AUTO_STATE_KEY_IMPORTED) {
1533
0
                    char cert_file[PATH_MAX] = {0};
1534
0
                    ssh_key cert = NULL;
1535
1536
0
                    snprintf(cert_file,
1537
0
                             sizeof(cert_file),
1538
0
                             "%s-cert.pub",
1539
0
                             privkey_file);
1540
0
                    SSH_LOG(SSH_LOG_TRACE,
1541
0
                            "Trying to load the certificate %s (default path)",
1542
0
                            cert_file);
1543
0
                    r = ssh_pki_import_cert_file(cert_file, &cert);
1544
0
                    if (r == SSH_OK) {
1545
                        /* TODO check the pubkey and certs match */
1546
0
                        SSH_LOG(SSH_LOG_TRACE,
1547
0
                                "Certificate loaded %s. Retry the authentication.",
1548
0
                                cert_file);
1549
0
                        state->state = SSH_AUTH_AUTO_STATE_CERTIFICATE_FILE;
1550
0
                        SSH_KEY_FREE(state->cert);
1551
0
                        state->cert = cert;
1552
                        /* try to authenticate with this certificate */
1553
0
                        continue;
1554
0
                    }
1555
                    /* if the file does not exists, try configuration options */
1556
0
                    state->state = SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION;
1557
0
                }
1558
                /* Try certificate files loaded through options */
1559
0
                if (state->state == SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION) {
1560
0
                    SSH_KEY_FREE(state->cert);
1561
0
                    if (state->cert_it == NULL) {
1562
0
                        state->cert_it = ssh_list_get_iterator(session->opts.certificate);
1563
0
                    }
1564
0
                    while (state->cert_it != NULL) {
1565
0
                        const char *cert_file = state->cert_it->data;
1566
0
                        ssh_key cert = NULL;
1567
1568
0
                        SSH_LOG(SSH_LOG_TRACE,
1569
0
                                "Trying to load the certificate %s (options)",
1570
0
                                cert_file);
1571
0
                        r = ssh_pki_import_cert_file(cert_file, &cert);
1572
0
                        if (r == SSH_OK) {
1573
0
                            int cmp = ssh_key_cmp(cert,
1574
0
                                                  state->pubkey,
1575
0
                                                  SSH_KEY_CMP_PUBLIC);
1576
0
                            if (cmp != 0) {
1577
0
                                state->cert_it = state->cert_it->next;
1578
0
                                SSH_KEY_FREE(cert);
1579
0
                                continue; /* with next cert */
1580
0
                            }
1581
0
                            SSH_LOG(SSH_LOG_TRACE,
1582
0
                                    "Found matching certificate %s in options. Retry the authentication.",
1583
0
                                    cert_file);
1584
0
                            state->cert = cert;
1585
0
                            cert = NULL;
1586
0
                            state->state = SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION;
1587
                            /* try to authenticate with this identity */
1588
0
                            break; /* try this cert */
1589
0
                        }
1590
                        /* continue with next identity */
1591
0
                    }
1592
0
                    if (state->cert != NULL) {
1593
0
                        continue; /* retry with the certificate */
1594
0
                    }
1595
0
                }
1596
0
                SSH_KEY_FREE(state->cert);
1597
0
                SSH_KEY_FREE(state->privkey);
1598
0
                SSH_KEY_FREE(state->pubkey);
1599
0
                state->it = state->it->next;
1600
0
                state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1601
0
                continue;
1602
0
            }
1603
0
            state->state = SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED;
1604
0
        }
1605
0
        if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED) {
1606
            /* Public key has been accepted by the server */
1607
0
            if (state->privkey == NULL) {
1608
0
                rc = ssh_pki_import_privkey_file(privkey_file,
1609
0
                                                 passphrase,
1610
0
                                                 auth_fn,
1611
0
                                                 auth_data,
1612
0
                                                 &state->privkey);
1613
0
                if (rc == SSH_ERROR) {
1614
0
                    SSH_KEY_FREE(state->cert);
1615
0
                    SSH_KEY_FREE(state->pubkey);
1616
0
                    ssh_set_error(session,
1617
0
                                  SSH_FATAL,
1618
0
                                  "Failed to read private key: %s",
1619
0
                                  privkey_file);
1620
0
                    state->it = state->it->next;
1621
0
                    state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1622
0
                    continue;
1623
0
                } else if (rc == SSH_EOF) {
1624
                    /* If the file doesn't exist, continue */
1625
0
                    SSH_KEY_FREE(state->cert);
1626
0
                    SSH_KEY_FREE(state->pubkey);
1627
0
                    SSH_LOG(SSH_LOG_DEBUG,
1628
0
                            "Private key %s doesn't exist.",
1629
0
                            privkey_file);
1630
0
                    state->it = state->it->next;
1631
0
                    state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1632
0
                    continue;
1633
0
                }
1634
0
            }
1635
0
            if (state->cert != NULL && !is_cert_type(state->privkey->cert_type)) {
1636
0
                rc = ssh_pki_copy_cert_to_privkey(state->cert, state->privkey);
1637
0
                if (rc != SSH_OK) {
1638
0
                    SSH_KEY_FREE(state->cert);
1639
0
                    SSH_KEY_FREE(state->privkey);
1640
0
                    SSH_KEY_FREE(state->pubkey);
1641
0
                    ssh_set_error(session,
1642
0
                                  SSH_FATAL,
1643
0
                                  "Failed to copy cert to private key");
1644
0
                    state->it = state->it->next;
1645
0
                    state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1646
0
                    continue;
1647
0
                }
1648
0
            }
1649
1650
0
            rc = ssh_userauth_publickey(session, username, state->privkey);
1651
0
            if (rc != SSH_AUTH_AGAIN && rc != SSH_AUTH_DENIED) {
1652
0
                bool cert_used = (state->cert != NULL);
1653
0
                SSH_KEY_FREE(state->cert);
1654
0
                SSH_KEY_FREE(state->privkey);
1655
0
                SSH_KEY_FREE(state->pubkey);
1656
0
                SAFE_FREE(session->auth.auto_state);
1657
0
                if (rc == SSH_AUTH_SUCCESS) {
1658
0
                    SSH_LOG(SSH_LOG_DEBUG,
1659
0
                            "Successfully authenticated using %s%s",
1660
0
                            privkey_file,
1661
0
                            (cert_used ? " and certificate" : ""));
1662
0
                }
1663
0
                return rc;
1664
0
            }
1665
0
            if (rc == SSH_AUTH_AGAIN) {
1666
0
                return rc;
1667
0
            }
1668
1669
0
            SSH_KEY_FREE(state->cert);
1670
0
            SSH_KEY_FREE(state->privkey);
1671
0
            SSH_KEY_FREE(state->pubkey);
1672
1673
0
            SSH_LOG(SSH_LOG_DEBUG,
1674
0
                    "The server accepted the public key but refused the signature");
1675
0
            state->it = state->it->next;
1676
0
            state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
1677
            /* continue */
1678
0
        }
1679
0
    }
1680
0
    SSH_LOG(SSH_LOG_WARN,
1681
0
            "Access denied: Tried every public key, none matched");
1682
0
    SAFE_FREE(session->auth.auto_state);
1683
0
    return SSH_AUTH_DENIED;
1684
0
}
1685
1686
/**
1687
 * @brief Try to authenticate by password.
1688
 *
1689
 * This authentication method is normally disabled on SSHv2 server. You should
1690
 * use keyboard-interactive mode.
1691
 *
1692
 * The 'password' value MUST be encoded UTF-8.  It is up to the server how to
1693
 * interpret the password and validate it against the password database.
1694
 * However, if you read the password in some other encoding, you MUST convert
1695
 * the password to UTF-8.
1696
 *
1697
 * @param[in] session   The ssh session to use.
1698
 *
1699
 * @param[in] username  The username, this SHOULD be NULL.
1700
 *
1701
 * @param[in] password  The password to authenticate in UTF-8.
1702
 *
1703
 * @returns SSH_AUTH_ERROR:   A serious error happened.\n
1704
 *          SSH_AUTH_DENIED:  Authentication failed: use another method\n
1705
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
1706
 *                            have to use another method\n
1707
 *          SSH_AUTH_SUCCESS: Authentication success\n
1708
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
1709
 *                            later.
1710
 *
1711
 * @note Most server implementations do not permit changing the username during
1712
 * authentication. The username should only be set with ssh_options_set() only
1713
 * before you connect to the server.
1714
 *
1715
 * @see ssh_userauth_none()
1716
 * @see ssh_userauth_kbdint()
1717
 */
1718
int ssh_userauth_password(ssh_session session,
1719
                          const char *username,
1720
                          const char *password)
1721
0
{
1722
0
    int rc;
1723
1724
0
    switch (session->pending_call_state) {
1725
0
        case SSH_PENDING_CALL_NONE:
1726
0
            break;
1727
0
        case SSH_PENDING_CALL_AUTH_PASSWORD:
1728
0
            goto pending;
1729
0
        default:
1730
0
            ssh_set_error(session,
1731
0
                          SSH_FATAL,
1732
0
                          "Wrong state (%d) during pending SSH call",
1733
0
                          session->pending_call_state);
1734
0
            return SSH_ERROR;
1735
0
    }
1736
1737
0
    rc = ssh_userauth_request_service(session);
1738
0
    if (rc == SSH_AGAIN) {
1739
0
        return SSH_AUTH_AGAIN;
1740
0
    } else if (rc == SSH_ERROR) {
1741
0
        return SSH_AUTH_ERROR;
1742
0
    }
1743
1744
    /* request */
1745
0
    rc = ssh_buffer_pack(session->out_buffer, "bsssbs",
1746
0
            SSH2_MSG_USERAUTH_REQUEST,
1747
0
            username ? username : session->opts.username,
1748
0
            "ssh-connection",
1749
0
            "password",
1750
0
            0, /* false */
1751
0
            password
1752
0
    );
1753
0
    if (rc < 0) {
1754
0
        goto fail;
1755
0
    }
1756
1757
    /* Set the buffer as secure to be explicitly zeroed when freed */
1758
0
    ssh_buffer_set_secure(session->out_buffer);
1759
1760
0
    session->auth.current_method = SSH_AUTH_METHOD_PASSWORD;
1761
0
    session->auth.state = SSH_AUTH_STATE_PASSWORD_AUTH_SENT;
1762
0
    session->pending_call_state = SSH_PENDING_CALL_AUTH_PASSWORD;
1763
0
    rc = ssh_packet_send(session);
1764
0
    if (rc == SSH_ERROR) {
1765
0
        return SSH_AUTH_ERROR;
1766
0
    }
1767
1768
0
pending:
1769
0
    rc = ssh_userauth_get_response(session);
1770
0
    if (rc != SSH_AUTH_AGAIN) {
1771
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
1772
0
    }
1773
1774
0
    return rc;
1775
0
fail:
1776
0
    ssh_set_error_oom(session);
1777
0
    ssh_buffer_reinit(session->out_buffer);
1778
1779
0
    return SSH_AUTH_ERROR;
1780
0
}
1781
1782
/* LEGACY */
1783
int ssh_userauth_agent_pubkey(ssh_session session,
1784
                              const char *username,
1785
                              ssh_public_key publickey)
1786
0
{
1787
0
    ssh_key key = NULL;
1788
0
    int rc;
1789
1790
0
    key = ssh_key_new();
1791
0
    if (key == NULL) {
1792
0
        return SSH_AUTH_ERROR;
1793
0
    }
1794
1795
0
    key->type = publickey->type;
1796
0
    key->type_c = ssh_key_type_to_char(key->type);
1797
0
    key->flags = SSH_KEY_FLAG_PUBLIC;
1798
#if defined(HAVE_LIBMBEDCRYPTO)
1799
    key->pk = publickey->rsa_pub;
1800
#elif defined(HAVE_LIBCRYPTO)
1801
    key->key = publickey->key_pub;
1802
#else
1803
    key->rsa = publickey->rsa_pub;
1804
#endif /* HAVE_LIBCRYPTO */
1805
1806
0
    rc = ssh_userauth_agent_publickey(session, username, key);
1807
1808
#if defined(HAVE_LIBMBEDCRYPTO)
1809
    key->pk = NULL;
1810
#elif defined(HAVE_LIBCRYPTO)
1811
    key->key = NULL;
1812
#else
1813
    key->rsa = NULL;
1814
#endif /* HAVE_LIBCRYPTO */
1815
0
    ssh_key_free(key);
1816
1817
0
    return rc;
1818
0
}
1819
1820
ssh_kbdint ssh_kbdint_new(void)
1821
0
{
1822
0
    ssh_kbdint kbd;
1823
1824
0
    kbd = calloc(1, sizeof(struct ssh_kbdint_struct));
1825
0
    if (kbd == NULL) {
1826
0
        return NULL;
1827
0
    }
1828
1829
0
    return kbd;
1830
0
}
1831
1832
1833
void ssh_kbdint_free(ssh_kbdint kbd)
1834
0
{
1835
0
    size_t i, n;
1836
1837
0
    if (kbd == NULL) {
1838
0
        return;
1839
0
    }
1840
1841
0
    SAFE_FREE(kbd->name);
1842
0
    SAFE_FREE(kbd->instruction);
1843
0
    SAFE_FREE(kbd->echo);
1844
1845
0
    n = kbd->nprompts;
1846
0
    if (kbd->prompts) {
1847
0
        for (i = 0; i < n; i++) {
1848
0
            if (kbd->prompts[i] != NULL) {
1849
0
                explicit_bzero(kbd->prompts[i], strlen(kbd->prompts[i]));
1850
0
            }
1851
0
            SAFE_FREE(kbd->prompts[i]);
1852
0
        }
1853
0
        SAFE_FREE(kbd->prompts);
1854
0
    }
1855
1856
0
    n = kbd->nanswers;
1857
0
    if (kbd->answers) {
1858
0
        for (i = 0; i < n; i++) {
1859
0
            if (kbd->answers[i] != NULL) {
1860
0
                explicit_bzero(kbd->answers[i], strlen(kbd->answers[i]));
1861
0
            }
1862
0
            SAFE_FREE(kbd->answers[i]);
1863
0
        }
1864
0
        SAFE_FREE(kbd->answers);
1865
0
    }
1866
1867
0
    SAFE_FREE(kbd);
1868
0
}
1869
1870
void ssh_kbdint_clean(ssh_kbdint kbd)
1871
0
{
1872
0
    size_t i, n;
1873
1874
0
    if (kbd == NULL) {
1875
0
        return;
1876
0
    }
1877
1878
0
    SAFE_FREE(kbd->name);
1879
0
    SAFE_FREE(kbd->instruction);
1880
0
    SAFE_FREE(kbd->echo);
1881
1882
0
    n = kbd->nprompts;
1883
0
    if (kbd->prompts) {
1884
0
        for (i = 0; i < n; i++) {
1885
0
            explicit_bzero(kbd->prompts[i], strlen(kbd->prompts[i]));
1886
0
            SAFE_FREE(kbd->prompts[i]);
1887
0
        }
1888
0
        SAFE_FREE(kbd->prompts);
1889
0
    }
1890
1891
0
    n = kbd->nanswers;
1892
1893
0
    if (kbd->answers) {
1894
0
        for (i = 0; i < n; i++) {
1895
0
            explicit_bzero(kbd->answers[i], strlen(kbd->answers[i]));
1896
0
            SAFE_FREE(kbd->answers[i]);
1897
0
        }
1898
0
        SAFE_FREE(kbd->answers);
1899
0
    }
1900
1901
0
    kbd->nprompts = 0;
1902
0
    kbd->nanswers = 0;
1903
0
}
1904
1905
/*
1906
 * This function sends the first packet as explained in RFC 3066 section 3.1.
1907
 */
1908
static int ssh_userauth_kbdint_init(ssh_session session,
1909
                                    const char *username,
1910
                                    const char *submethods)
1911
0
{
1912
0
    int rc;
1913
1914
0
    if (session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_INIT) {
1915
0
        goto pending;
1916
0
    }
1917
0
    if (session->pending_call_state != SSH_PENDING_CALL_NONE) {
1918
0
        ssh_set_error_invalid(session);
1919
0
        return SSH_ERROR;
1920
0
    }
1921
1922
0
    rc = ssh_userauth_request_service(session);
1923
0
    if (rc == SSH_AGAIN) {
1924
0
        return SSH_AUTH_AGAIN;
1925
0
    }
1926
0
    if (rc != SSH_OK) {
1927
0
        return SSH_AUTH_ERROR;
1928
0
    }
1929
1930
    /* request */
1931
0
    rc = ssh_buffer_pack(session->out_buffer, "bsssss",
1932
0
            SSH2_MSG_USERAUTH_REQUEST,
1933
0
            username ? username : session->opts.username,
1934
0
            "ssh-connection",
1935
0
            "keyboard-interactive",
1936
0
            "", /* lang (ignore it) */
1937
0
            submethods ? submethods : ""
1938
0
    );
1939
0
    if (rc < 0) {
1940
0
        goto fail;
1941
0
    }
1942
1943
1944
0
    session->auth.state = SSH_AUTH_STATE_KBDINT_SENT;
1945
0
    session->pending_call_state = SSH_PENDING_CALL_AUTH_KBDINT_INIT;
1946
1947
0
    SSH_LOG(SSH_LOG_DEBUG,
1948
0
            "Sending keyboard-interactive init request");
1949
1950
0
    rc = ssh_packet_send(session);
1951
0
    if (rc == SSH_ERROR) {
1952
0
        return SSH_AUTH_ERROR;
1953
0
    }
1954
0
pending:
1955
0
    rc = ssh_userauth_get_response(session);
1956
0
    if (rc != SSH_AUTH_AGAIN)
1957
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
1958
0
    return rc;
1959
0
fail:
1960
0
    ssh_set_error_oom(session);
1961
0
    ssh_buffer_reinit(session->out_buffer);
1962
1963
0
    return SSH_AUTH_ERROR;
1964
0
}
1965
1966
/**
1967
 * @internal
1968
 *
1969
 * @brief Send the current challenge response and wait for a reply from the
1970
 *        server.
1971
 *
1972
 * @returns SSH_AUTH_INFO if more info is needed
1973
 * @returns SSH_AUTH_SUCCESS
1974
 * @returns SSH_AUTH_FAILURE
1975
 * @returns SSH_AUTH_PARTIAL
1976
 */
1977
static int ssh_userauth_kbdint_send(ssh_session session)
1978
0
{
1979
0
    uint32_t i;
1980
0
    int rc;
1981
0
    if (session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_SEND)
1982
0
        goto pending;
1983
0
    if (session->pending_call_state != SSH_PENDING_CALL_NONE) {
1984
0
        ssh_set_error_invalid(session);
1985
0
        return SSH_ERROR;
1986
0
    }
1987
0
    rc = ssh_buffer_pack(session->out_buffer, "bd",
1988
0
            SSH2_MSG_USERAUTH_INFO_RESPONSE,
1989
0
            session->kbdint->nprompts);
1990
0
    if (rc < 0) {
1991
0
        goto fail;
1992
0
    }
1993
1994
0
    for (i = 0; i < session->kbdint->nprompts; i++) {
1995
0
        rc = ssh_buffer_pack(session->out_buffer, "s",
1996
0
                session->kbdint->answers && session->kbdint->answers[i] ?
1997
0
                        session->kbdint->answers[i]:"");
1998
0
        if (rc < 0) {
1999
0
            goto fail;
2000
0
        }
2001
0
    }
2002
2003
0
    session->auth.current_method = SSH_AUTH_METHOD_INTERACTIVE;
2004
0
    session->auth.state = SSH_AUTH_STATE_KBDINT_SENT;
2005
0
    session->pending_call_state = SSH_PENDING_CALL_AUTH_KBDINT_SEND;
2006
0
    ssh_kbdint_free(session->kbdint);
2007
0
    session->kbdint = NULL;
2008
2009
0
    SSH_LOG(SSH_LOG_DEBUG,
2010
0
            "Sending keyboard-interactive response packet");
2011
2012
0
    rc = ssh_packet_send(session);
2013
0
    if (rc == SSH_ERROR) {
2014
0
        return SSH_AUTH_ERROR;
2015
0
    }
2016
0
pending:
2017
0
    rc = ssh_userauth_get_response(session);
2018
0
    if (rc != SSH_AUTH_AGAIN)
2019
0
        session->pending_call_state = SSH_PENDING_CALL_NONE;
2020
0
    return rc;
2021
0
fail:
2022
0
    ssh_set_error_oom(session);
2023
0
    ssh_buffer_reinit(session->out_buffer);
2024
2025
0
    return SSH_AUTH_ERROR;
2026
0
}
2027
2028
/**
2029
 * @internal
2030
 * @brief handles a SSH_USERAUTH_INFO_REQUEST packet, as used in
2031
 *        keyboard-interactive authentication, and changes the
2032
 *        authentication state.
2033
 */
2034
0
SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) {
2035
0
    ssh_string tmp = NULL;
2036
0
    uint32_t nprompts;
2037
0
    uint32_t i;
2038
0
    int rc;
2039
0
    (void)user;
2040
0
    (void)type;
2041
2042
2043
0
    if (session->kbdint == NULL) {
2044
0
        session->kbdint = ssh_kbdint_new();
2045
0
        if (session->kbdint == NULL) {
2046
0
            ssh_set_error_oom(session);
2047
0
            return SSH_PACKET_USED;
2048
0
        }
2049
0
    } else {
2050
0
        ssh_kbdint_clean(session->kbdint);
2051
0
    }
2052
2053
0
    rc = ssh_buffer_unpack(packet, "ssSd",
2054
0
            &session->kbdint->name, /* name of the "asking" window shown to client */
2055
0
            &session->kbdint->instruction,
2056
0
            &tmp, /* to ignore */
2057
0
            &nprompts
2058
0
            );
2059
2060
    /* We don't care about tmp */
2061
0
    SSH_STRING_FREE(tmp);
2062
2063
0
    if (rc != SSH_OK) {
2064
0
        ssh_set_error(session, SSH_FATAL, "Invalid USERAUTH_INFO_REQUEST msg");
2065
0
        ssh_kbdint_free(session->kbdint);
2066
0
        session->kbdint = NULL;
2067
0
        return SSH_PACKET_USED;
2068
0
    }
2069
2070
0
    SSH_LOG(SSH_LOG_DEBUG,
2071
0
            "%" PRIu32 " keyboard-interactive prompts", nprompts);
2072
0
    if (nprompts > KBDINT_MAX_PROMPT) {
2073
0
        ssh_set_error(session, SSH_FATAL,
2074
0
                "Too much prompts requested by the server: %" PRIu32 " (0x%.4" PRIx32 ")",
2075
0
                nprompts, nprompts);
2076
0
        ssh_kbdint_free(session->kbdint);
2077
0
        session->kbdint = NULL;
2078
2079
0
        return SSH_PACKET_USED;
2080
0
    }
2081
2082
0
    session->kbdint->nprompts = nprompts;
2083
0
    session->kbdint->nanswers = nprompts;
2084
0
    session->kbdint->prompts = calloc(nprompts, sizeof(char *));
2085
0
    if (session->kbdint->prompts == NULL) {
2086
0
        session->kbdint->nprompts = 0;
2087
0
        ssh_set_error_oom(session);
2088
0
        ssh_kbdint_free(session->kbdint);
2089
0
        session->kbdint = NULL;
2090
2091
0
        return SSH_PACKET_USED;
2092
0
    }
2093
2094
0
    session->kbdint->echo = calloc(nprompts, sizeof(unsigned char));
2095
0
    if (session->kbdint->echo == NULL) {
2096
0
        session->kbdint->nprompts = 0;
2097
0
        ssh_set_error_oom(session);
2098
0
        ssh_kbdint_free(session->kbdint);
2099
0
        session->kbdint = NULL;
2100
2101
0
        return SSH_PACKET_USED;
2102
0
    }
2103
2104
0
    for (i = 0; i < nprompts; i++) {
2105
0
        rc = ssh_buffer_unpack(packet, "sb",
2106
0
                &session->kbdint->prompts[i],
2107
0
                &session->kbdint->echo[i]);
2108
0
        if (rc == SSH_ERROR) {
2109
0
            ssh_set_error(session, SSH_FATAL, "Short INFO_REQUEST packet");
2110
0
            ssh_kbdint_free(session->kbdint);
2111
0
            session->kbdint = NULL;
2112
2113
0
            return SSH_PACKET_USED;
2114
0
        }
2115
0
    }
2116
0
    session->auth.state=SSH_AUTH_STATE_INFO;
2117
2118
0
    return SSH_PACKET_USED;
2119
0
}
2120
2121
/**
2122
 * @brief Try to authenticate through the "keyboard-interactive" method.
2123
 *
2124
 * @param[in]  session  The ssh session to use.
2125
 *
2126
 * @param[in]  user     The username to authenticate. You can specify NULL if
2127
 *                      ssh_option_set_username() has been used. You cannot try
2128
 *                      two different logins in a row.
2129
 *
2130
 * @param[in]  submethods Undocumented. Set it to NULL.
2131
 *
2132
 * @returns SSH_AUTH_ERROR:   A serious error happened\n
2133
 *          SSH_AUTH_DENIED:  Authentication failed : use another method\n
2134
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
2135
 *                            have to use another method\n
2136
 *          SSH_AUTH_SUCCESS: Authentication success\n
2137
 *          SSH_AUTH_INFO:    The server asked some questions. Use
2138
 *                            ssh_userauth_kbdint_getnprompts() and such.\n
2139
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
2140
 *                            later.
2141
 *
2142
 * @see ssh_userauth_kbdint_getnprompts()
2143
 * @see ssh_userauth_kbdint_getname()
2144
 * @see ssh_userauth_kbdint_getinstruction()
2145
 * @see ssh_userauth_kbdint_getprompt()
2146
 * @see ssh_userauth_kbdint_setanswer()
2147
 */
2148
int ssh_userauth_kbdint(ssh_session session, const char *user,
2149
                        const char *submethods)
2150
0
{
2151
0
    int rc = SSH_AUTH_ERROR;
2152
2153
0
    if (session == NULL) {
2154
0
        return SSH_AUTH_ERROR;
2155
0
    }
2156
2157
0
    if ((session->pending_call_state == SSH_PENDING_CALL_NONE && session->kbdint == NULL) ||
2158
0
            session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_INIT)
2159
0
        rc = ssh_userauth_kbdint_init(session, user, submethods);
2160
0
    else if (session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_SEND ||
2161
0
            session->kbdint != NULL) {
2162
        /*
2163
         * If we are at this point, it is because session->kbdint exists.
2164
         * It means the user has set some information there we need to send
2165
         * the server and then we need to ack the status (new questions or ok
2166
         * pass in).
2167
         * It is possible that session->kbdint is NULL while we're waiting for
2168
         * a reply, hence the test for the pending call.
2169
         */
2170
0
        rc = ssh_userauth_kbdint_send(session);
2171
0
    } else {
2172
        /* We are here because session->kbdint == NULL & state != NONE.
2173
         * This should not happen
2174
         */
2175
0
        rc = SSH_AUTH_ERROR;
2176
0
        ssh_set_error(session, SSH_FATAL, "Invalid state in %s", __func__);
2177
0
    }
2178
0
    return rc;
2179
0
}
2180
2181
/**
2182
 * @brief Get the number of prompts (questions) the server has given.
2183
 *
2184
 * Once you have called ssh_userauth_kbdint() and received SSH_AUTH_INFO return
2185
 * code, this function can be used to retrieve information about the keyboard
2186
 * interactive authentication questions sent by the remote host.
2187
 *
2188
 * @param[in]  session  The ssh session to use.
2189
 *
2190
 * @returns             The number of prompts.
2191
 */
2192
int ssh_userauth_kbdint_getnprompts(ssh_session session)
2193
0
{
2194
0
    if (session == NULL) {
2195
0
        return SSH_ERROR;
2196
0
    }
2197
0
    if (session->kbdint == NULL) {
2198
0
        ssh_set_error_invalid(session);
2199
0
        return SSH_ERROR;
2200
0
    }
2201
0
    return session->kbdint->nprompts;
2202
0
}
2203
2204
/**
2205
 * @brief Get the "name" of the message block.
2206
 *
2207
 * Once you have called ssh_userauth_kbdint() and received SSH_AUTH_INFO return
2208
 * code, this function can be used to retrieve information about the keyboard
2209
 * interactive authentication questions sent by the remote host.
2210
 *
2211
 * @param[in]  session  The ssh session to use.
2212
 *
2213
 * @returns             The name of the message block. Do not free it.
2214
 */
2215
const char *ssh_userauth_kbdint_getname(ssh_session session)
2216
0
{
2217
0
    if (session == NULL) {
2218
0
        return NULL;
2219
0
    }
2220
0
    if (session->kbdint == NULL) {
2221
0
        ssh_set_error_invalid(session);
2222
0
        return NULL;
2223
0
    }
2224
0
    return session->kbdint->name;
2225
0
}
2226
2227
/**
2228
 * @brief Get the "instruction" of the message block.
2229
 *
2230
 * Once you have called ssh_userauth_kbdint() and received SSH_AUTH_INFO return
2231
 * code, this function can be used to retrieve information about the keyboard
2232
 * interactive authentication questions sent by the remote host.
2233
 *
2234
 * @param[in]  session  The ssh session to use.
2235
 *
2236
 * @returns             The instruction of the message block.
2237
 */
2238
2239
const char *ssh_userauth_kbdint_getinstruction(ssh_session session)
2240
0
{
2241
0
    if (session == NULL)
2242
0
        return NULL;
2243
0
    if (session->kbdint == NULL) {
2244
0
        ssh_set_error_invalid(session);
2245
0
        return NULL;
2246
0
    }
2247
0
    return session->kbdint->instruction;
2248
0
}
2249
2250
/**
2251
 * @brief Get a prompt from a message block.
2252
 *
2253
 * Once you have called ssh_userauth_kbdint() and received SSH_AUTH_INFO return
2254
 * code, this function can be used to retrieve information about the keyboard
2255
 * interactive authentication questions sent by the remote host.
2256
 *
2257
 * @param[in]  session  The ssh session to use.
2258
 *
2259
 * @param[in]  i        The index number of the i'th prompt.
2260
 *
2261
 * @param[out] echo     This is an optional variable. You can obtain a
2262
 *                      boolean if the user input should be echoed or
2263
 *                      hidden. For passwords it is usually hidden.
2264
 *
2265
 * @returns             A pointer to the prompt. Do not free it.
2266
 *
2267
 * @code
2268
 *   const char prompt;
2269
 *   char echo;
2270
 *
2271
 *   prompt = ssh_userauth_kbdint_getprompt(session, 0, &echo);
2272
 *   if (echo) ...
2273
 * @endcode
2274
 */
2275
const char *
2276
ssh_userauth_kbdint_getprompt(ssh_session session, unsigned int i, char *echo)
2277
0
{
2278
0
    if (session == NULL)
2279
0
        return NULL;
2280
0
    if (session->kbdint == NULL) {
2281
0
        ssh_set_error_invalid(session);
2282
0
        return NULL;
2283
0
    }
2284
0
    if (i > session->kbdint->nprompts) {
2285
0
        ssh_set_error_invalid(session);
2286
0
        return NULL;
2287
0
    }
2288
2289
0
    if (echo) {
2290
0
        *echo = (char)session->kbdint->echo[i];
2291
0
    }
2292
2293
0
    return session->kbdint->prompts[i];
2294
0
}
2295
2296
#ifdef WITH_SERVER
2297
/**
2298
 * @brief Get the number of answers the client has given.
2299
 *
2300
 * @param[in]  session  The ssh session to use.
2301
 *
2302
 * @returns             The number of answers.
2303
 */
2304
int ssh_userauth_kbdint_getnanswers(ssh_session session)
2305
0
{
2306
0
    if (session == NULL || session->kbdint == NULL) {
2307
0
        return SSH_ERROR;
2308
0
    }
2309
0
    return session->kbdint->nanswers;
2310
0
}
2311
2312
/**
2313
 * @brief Get the answer to a question from a message block.
2314
 *
2315
 * @param[in]  session  The ssh session to use.
2316
 *
2317
 * @param[in]  i index  The number of the ith answer.
2318
 *
2319
 * @return              The answer string, or NULL if the answer is not
2320
 *                      available. Do not free the string.
2321
 */
2322
const char *ssh_userauth_kbdint_getanswer(ssh_session session, unsigned int i)
2323
0
{
2324
0
    if (session == NULL || session->kbdint == NULL
2325
0
            || session->kbdint->answers == NULL) {
2326
0
        return NULL;
2327
0
    }
2328
0
    if (i >= session->kbdint->nanswers) {
2329
0
        return NULL;
2330
0
    }
2331
2332
0
    return session->kbdint->answers[i];
2333
0
}
2334
#endif
2335
2336
/**
2337
 * @brief Set the answer for a question from a message block.
2338
 *
2339
 * If you have called ssh_userauth_kbdint() and got SSH_AUTH_INFO, this
2340
 * function returns the questions from the server.
2341
 *
2342
 * @param[in]  session  The ssh session to use.
2343
 *
2344
 * @param[in]  i index  The number of the ith prompt.
2345
 *
2346
 * @param[in]  answer   The answer to give to the server. The answer MUST be
2347
 *                      encoded UTF-8. It is up to the server how to interpret
2348
 *                      the value and validate it. However, if you read the
2349
 *                      answer in some other encoding, you MUST convert it to
2350
 *                      UTF-8.
2351
 *
2352
 * @return              0 on success, < 0 on error.
2353
 */
2354
int
2355
ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i,
2356
                              const char *answer)
2357
0
{
2358
0
    if (session == NULL) {
2359
0
        return -1;
2360
0
    }
2361
0
    if (answer == NULL || session->kbdint == NULL ||
2362
0
            i >= session->kbdint->nprompts) {
2363
0
        ssh_set_error_invalid(session);
2364
0
        return -1;
2365
0
    }
2366
2367
0
    if (session->kbdint->answers == NULL) {
2368
0
        session->kbdint->answers = calloc(session->kbdint->nprompts, sizeof(char *));
2369
0
        if (session->kbdint->answers == NULL) {
2370
0
            ssh_set_error_oom(session);
2371
0
            return -1;
2372
0
        }
2373
0
    }
2374
2375
0
    if (session->kbdint->answers[i]) {
2376
0
        explicit_bzero(session->kbdint->answers[i],
2377
0
                strlen(session->kbdint->answers[i]));
2378
0
        SAFE_FREE(session->kbdint->answers[i]);
2379
0
    }
2380
2381
0
    session->kbdint->answers[i] = strdup(answer);
2382
0
    if (session->kbdint->answers[i] == NULL) {
2383
0
        ssh_set_error_oom(session);
2384
0
        return -1;
2385
0
    }
2386
2387
0
    return 0;
2388
0
}
2389
2390
/**
2391
 * @brief Try to authenticate through the "gssapi-with-mic" method.
2392
 *
2393
 * @param[in]  session  The ssh session to use.
2394
 *
2395
 * @returns SSH_AUTH_ERROR:   A serious error happened\n
2396
 *          SSH_AUTH_DENIED:  Authentication failed : use another method\n
2397
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
2398
 *                            have to use another method\n
2399
 *          SSH_AUTH_SUCCESS: Authentication success\n
2400
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
2401
 *                            later.
2402
 */
2403
int ssh_userauth_gssapi(ssh_session session)
2404
0
{
2405
0
    int rc = SSH_AUTH_DENIED;
2406
#ifdef WITH_GSSAPI
2407
    switch(session->pending_call_state) {
2408
    case SSH_PENDING_CALL_NONE:
2409
        break;
2410
    case SSH_PENDING_CALL_AUTH_GSSAPI_MIC:
2411
        goto pending;
2412
    default:
2413
        ssh_set_error(session,
2414
                SSH_FATAL,
2415
                "Wrong state (%d) during pending SSH call",
2416
                session->pending_call_state);
2417
        return SSH_ERROR;
2418
    }
2419
2420
    rc = ssh_userauth_request_service(session);
2421
    if (rc == SSH_AGAIN) {
2422
        return SSH_AUTH_AGAIN;
2423
    } else if (rc == SSH_ERROR) {
2424
        return SSH_AUTH_ERROR;
2425
    }
2426
    SSH_LOG(SSH_LOG_DEBUG, "Authenticating with gssapi-with-mic");
2427
2428
    session->auth.current_method = SSH_AUTH_METHOD_GSSAPI_MIC;
2429
    session->auth.state = SSH_AUTH_STATE_NONE;
2430
    session->pending_call_state = SSH_PENDING_CALL_AUTH_GSSAPI_MIC;
2431
    rc = ssh_gssapi_auth_mic(session);
2432
2433
    if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_DENIED) {
2434
        session->auth.state = SSH_AUTH_STATE_NONE;
2435
        session->pending_call_state = SSH_PENDING_CALL_NONE;
2436
        return rc;
2437
    }
2438
2439
pending:
2440
    rc = ssh_userauth_get_response(session);
2441
    if (rc != SSH_AUTH_AGAIN) {
2442
        session->pending_call_state = SSH_PENDING_CALL_NONE;
2443
    }
2444
#else
2445
0
    (void) session; /* unused */
2446
0
#endif
2447
0
    return rc;
2448
0
}
2449
2450
/** @} */