libssh2

Форк
0
/
session_fixture.c 
527 строк · 15.0 Кб
1
/* Copyright (C) Alexander Lamaison
2
 * All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms,
5
 * with or without modification, are permitted provided
6
 * that the following conditions are met:
7
 *
8
 *   Redistributions of source code must retain the above
9
 *   copyright notice, this list of conditions and the
10
 *   following disclaimer.
11
 *
12
 *   Redistributions in binary form must reproduce the above
13
 *   copyright notice, this list of conditions and the following
14
 *   disclaimer in the documentation and/or other materials
15
 *   provided with the distribution.
16
 *
17
 *   Neither the name of the copyright holder nor the names
18
 *   of any other contributors may be used to endorse or
19
 *   promote products derived from this software without
20
 *   specific prior written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
23
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
24
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
27
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
34
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
35
 * OF SUCH DAMAGE.
36
 *
37
 * SPDX-License-Identifier: BSD-3-Clause
38
 */
39

40
#include "session_fixture.h"
41
#include "openssh_fixture.h"
42

43
#ifdef HAVE_SYS_SOCKET_H
44
#include <sys/socket.h>
45
#endif
46
#ifdef HAVE_UNISTD_H
47
#include <unistd.h>
48
#endif
49
#ifdef HAVE_SYS_PARAM_H
50
#include <sys/param.h>
51
#endif
52

53
#include <stdio.h>
54
#include <stdlib.h>
55
#include <assert.h>
56

57
static LIBSSH2_SESSION *connected_session = NULL;
58
static libssh2_socket_t connected_socket = LIBSSH2_INVALID_SOCKET;
59

60
static int connect_to_server(void)
61
{
62
    int rc;
63
    connected_socket = open_socket_to_openssh_server();
64
    if(connected_socket == LIBSSH2_INVALID_SOCKET) {
65
        return LIBSSH2_ERROR_SOCKET_NONE;
66
    }
67

68
    rc = libssh2_session_handshake(connected_session, connected_socket);
69
    if(rc) {
70
        print_last_session_error("libssh2_session_handshake");
71
        return libssh2_session_last_errno(connected_session);
72
    }
73

74
    return LIBSSH2_ERROR_NONE;
75
}
76

77
/* List of crypto protocols for which tests are skipped */
78
static char const *skip_crypt[] = {
79
#ifdef LIBSSH2_MBEDTLS
80
    /* Due to a bug with mbedTLS support, these crypt methods fail.
81
       Until that bug is fixed, don't run them there to avoid this
82
       known issue causing red tests.
83
       See: https://github.com/libssh2/libssh2/issues/793
84
     */
85
    "3des-cbc",
86
    "aes128-cbc",
87
    "aes192-cbc",
88
    "aes256-cbc",
89
    "aes128-gcm@openssh.com",
90
    "aes256-gcm@openssh.com",
91
    "rijndael-cbc@lysator.liu.se",
92
#endif
93

94
#if !LIBSSH2_3DES
95
    "3des-cbc",
96
#endif
97

98
#if defined(LIBSSH2_LIBGCRYPT) || defined(LIBSSH2_OS400QC3) || \
99
    defined(LIBSSH2_WINCNG)
100
    /* Support for AES-GCM hasn't been added to these back-ends yet */
101
    "aes128-gcm@openssh.com",
102
    "aes256-gcm@openssh.com",
103
#endif
104

105
    NULL
106
};
107

108
/* List of MAC protocols for which tests are skipped */
109
static char const *skip_mac[] = {
110
#if !LIBSSH2_MD5
111
    "hmac-md5",
112
    "hmac-md5-96",
113
#endif
114
    NULL
115
};
116

117
LIBSSH2_SESSION *start_session_fixture(int *skipped, int *err)
118
{
119
    int rc;
120

121
    const char *crypt = getenv("FIXTURE_TEST_CRYPT");
122
    const char *mac = getenv("FIXTURE_TEST_MAC");
123

124
    *skipped = 0;
125
    *err = LIBSSH2_ERROR_NONE;
126

127
    if(crypt) {
128
        char const * const *sk;
129
        for(sk = skip_crypt; *sk; ++sk) {
130
            if(strcmp(*sk, crypt) == 0) {
131
                fprintf(stderr, "unsupported crypt algorithm (%s) skipped.\n",
132
                                crypt);
133
                *skipped = 1;
134
                return NULL;
135
            }
136
        }
137
    }
138

139
    if(mac) {
140
        char const * const *sk;
141
        for(sk = skip_mac; *sk; ++sk) {
142
            if(strcmp(*sk, mac) == 0) {
143
                fprintf(stderr, "unsupported MAC algorithm (%s) skipped.\n",
144
                                mac);
145
                *skipped = 1;
146
                return NULL;
147
            }
148
        }
149
    }
150

151
    rc = start_openssh_fixture();
152
    if(rc) {
153
        return NULL;
154
    }
155
    rc = libssh2_init(0);
156
    if(rc) {
157
        fprintf(stderr, "libssh2_init failed (%d)\n", rc);
158
        return NULL;
159
    }
160

161
    connected_session = libssh2_session_init_ex(NULL, NULL, NULL, NULL);
162
    if(!connected_session) {
163
        fprintf(stderr, "libssh2_session_init_ex failed\n");
164
        return NULL;
165
    }
166

167
    if(getenv("FIXTURE_TRACE_ALL_CONNECT")) {
168
        libssh2_trace(connected_session, ~0);
169
        fprintf(stdout, "Trace all enabled for connect_to_server.\n");
170
    }
171
    else if(getenv("FIXTURE_TRACE_ALL")) {
172
        libssh2_trace(connected_session, ~0);
173
        fprintf(stdout, "Trace all enabled.\n");
174
    }
175

176
    /* Override crypt algorithm for the test */
177
    if(crypt) {
178
        if(libssh2_session_method_pref(connected_session,
179
                                       LIBSSH2_METHOD_CRYPT_CS, crypt) ||
180
           libssh2_session_method_pref(connected_session,
181
                                       LIBSSH2_METHOD_CRYPT_SC, crypt)) {
182
            fprintf(stderr, "libssh2_session_method_pref CRYPT failed "
183
                            "(probably disabled in the build): '%s'\n", crypt);
184
            return NULL;
185
        }
186
    }
187

188
    /* Override mac algorithm for the test */
189
    if(mac) {
190
        if(libssh2_session_method_pref(connected_session,
191
                                       LIBSSH2_METHOD_MAC_CS, mac) ||
192
           libssh2_session_method_pref(connected_session,
193
                                       LIBSSH2_METHOD_MAC_SC, mac)) {
194
            fprintf(stderr, "libssh2_session_method_pref MAC failed "
195
                            "(probably disabled in the build): '%s'\n", mac);
196
            return NULL;
197
        }
198
    }
199

200
    libssh2_session_set_blocking(connected_session, 1);
201

202
    rc = connect_to_server();
203
    if(rc != LIBSSH2_ERROR_NONE) {
204
        *err = rc;
205
        return NULL;
206
    }
207

208
    if(getenv("FIXTURE_TRACE_ALL_CONNECT")) {
209
        libssh2_trace(connected_session, 0);
210
    }
211

212
    return connected_session;
213
}
214

215
void print_last_session_error(const char *function)
216
{
217
    if(connected_session) {
218
        char *message;
219
        int rc =
220
            libssh2_session_last_error(connected_session, &message, NULL, 0);
221
        fprintf(stderr, "%s failed (%d): %s\n", function, rc, message);
222
    }
223
    else {
224
        fprintf(stderr, "No session\n");
225
    }
226
}
227

228
void stop_session_fixture(void)
229
{
230
    if(connected_session) {
231
        libssh2_session_disconnect(connected_session, "test ended");
232
        libssh2_session_free(connected_session);
233
        connected_session = NULL;
234
    }
235
    else {
236
        fprintf(stderr, "Cannot stop session - none started\n");
237
    }
238

239
    close_socket_to_openssh_server(connected_socket);
240
    connected_socket = LIBSSH2_INVALID_SOCKET;
241

242
    libssh2_exit();
243

244
    stop_openssh_fixture();
245
}
246

247

248
/* Return a static string that contains a file path relative to the srcdir
249
 * variable, if found. It does so in a way that avoids leaking memory by using
250
 * a fixed number of static buffers.
251
 */
252
#define NUMPATHS 32
253
const char *srcdir_path(const char *file)
254
{
255
#ifdef _WIN32
256
    static char filepath[NUMPATHS][_MAX_PATH];
257
#else
258
    static char filepath[NUMPATHS][MAXPATHLEN];
259
#endif
260
    static int curpath;
261
    char *p = getenv("srcdir");
262
    if(curpath >= NUMPATHS) {
263
        fprintf(stderr, "srcdir_path ran out of filepath slots.\n");
264
    }
265
    assert(curpath < NUMPATHS);
266
    if(p) {
267
        /* Ensure the final string is nul-terminated on Windows */
268
        filepath[curpath][sizeof(filepath[0]) - 1] = 0;
269
        snprintf(filepath[curpath], sizeof(filepath[0]) - 1, "%s/%s",
270
                 p, file);
271
    }
272
    else {
273
        /* Ensure the final string is nul-terminated on Windows */
274
        filepath[curpath][sizeof(filepath[0]) - 1] = 0;
275
        snprintf(filepath[curpath], sizeof(filepath[0]) - 1, "%s",
276
                 file);
277
    }
278

279
    return filepath[curpath++];
280
}
281

282
static const char *kbd_password;
283

284
static void kbd_callback(const char *name, int name_len,
285
                         const char *instruct, int instruct_len,
286
                         int num_prompts,
287
                         const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
288
                         LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
289
                         void **abstract)
290
{
291
    int i;
292
    (void)abstract;
293

294
    fprintf(stdout, "Kb-int name: %.*s\n", name_len, name);
295
    fprintf(stdout, "Kb-int instruction: %.*s\n", instruct_len, instruct);
296
    for(i = 0; i < num_prompts; ++i) {
297
        fprintf(stdout, "Kb-int prompt %d: %.*s\n", i,
298
                (int)prompts[i].length, prompts[i].text);
299
    }
300

301
    if(num_prompts == 1) {
302
        responses[0].text = strdup(kbd_password);
303
        responses[0].length = (unsigned int)strlen(kbd_password);
304
    }
305
}
306

307
int test_auth_keyboard(LIBSSH2_SESSION *session, int flags,
308
                       const char *username,
309
                       const char *password)
310
{
311
    int rc;
312

313
    const char *userauth_list =
314
        libssh2_userauth_list(session, username,
315
                              (unsigned int)strlen(username));
316
    if(!userauth_list) {
317
        print_last_session_error("libssh2_userauth_list");
318
        return 1;
319
    }
320

321
    if(!strstr(userauth_list, "keyboard-interactive")) {
322
        fprintf(stderr,
323
                "'keyboard-interactive' was expected in userauth list: %s\n",
324
                userauth_list);
325
        return 1;
326
    }
327

328
    kbd_password = password;
329

330
    rc = libssh2_userauth_keyboard_interactive_ex(session, username,
331
                                                (unsigned int)strlen(username),
332
                                                  kbd_callback);
333

334
    kbd_password = NULL;
335

336
    if((flags & TEST_AUTH_SHOULDFAIL) != 0) {
337
        if(rc == 0) {
338
            fprintf(stderr, "Keyboard-interactive auth succeeded "
339
                            "with wrong response\n");
340
            return 1;
341
        }
342
    }
343
    else {
344
        if(rc) {
345
            print_last_session_error(
346
                "libssh2_userauth_keyboard_interactive_ex");
347
            return 1;
348
        }
349
    }
350

351
    return 0;
352
}
353

354
int test_auth_password(LIBSSH2_SESSION *session, int flags,
355
                       const char *username,
356
                       const char *password)
357
{
358
    int rc;
359

360
    const char *userauth_list =
361
        libssh2_userauth_list(session, username,
362
                              (unsigned int)strlen(username));
363
    if(!userauth_list) {
364
        print_last_session_error("libssh2_userauth_list");
365
        return 1;
366
    }
367

368
    if(!strstr(userauth_list, "password")) {
369
        fprintf(stderr, "'password' was expected in userauth list: %s\n",
370
                userauth_list);
371
        return 1;
372
    }
373

374
    rc = libssh2_userauth_password_ex(session, username,
375
                                      (unsigned int)strlen(username),
376
                                      password,
377
                                      (unsigned int)strlen(password),
378
                                      NULL);
379

380
    if((flags & TEST_AUTH_SHOULDFAIL) != 0) {
381
        if(rc == 0) {
382
            fprintf(stderr, "Password auth succeeded with wrong password\n");
383
            return 1;
384
        }
385
    }
386
    else {
387
        if(rc) {
388
            print_last_session_error("libssh2_userauth_password_ex");
389
            return 1;
390
        }
391

392
        if(libssh2_userauth_authenticated(session) == 0) {
393
            fprintf(stderr, "Password auth appeared to succeed but "
394
                            "libssh2_userauth_authenticated returned 0\n");
395
            return 1;
396
        }
397
    }
398

399
    return 0;
400
}
401

402
static int read_file(const char *path, char **out_buffer, size_t *out_len)
403
{
404
    FILE *fp;
405
    char *buffer;
406
    ssize_t len;
407

408
    if(!out_buffer || !out_len || !path) {
409
        fprintf(stderr, "invalid params.\n");
410
        return 1;
411
    }
412

413
    *out_buffer = NULL;
414
    *out_len = 0;
415

416
    fp = fopen(path, "r");
417

418
    if(!fp) {
419
        fprintf(stderr, "File could not be read: %s\n", path);
420
        return 1;
421
    }
422

423
    fseek(fp, 0L, SEEK_END);
424
    len = ftell(fp);
425
    if(len < 0) {
426
        fclose(fp);
427
        fprintf(stderr, "Could not determine input size of: %s\n", path);
428
        return 1;
429
    }
430
    rewind(fp);
431

432
    buffer = calloc(1, (size_t)len + 1);
433
    if(!buffer) {
434
        fclose(fp);
435
        fprintf(stderr, "Could not alloc memory.\n");
436
        return 1;
437
    }
438

439
    if(1 != fread(buffer, (size_t)len, 1, fp)) {
440
        fclose(fp);
441
        free(buffer);
442
        fprintf(stderr, "Could not read file into memory.\n");
443
        return 1;
444
    }
445

446
    fclose(fp);
447

448
    *out_buffer = buffer;
449
    *out_len = (size_t)len;
450

451
    return 0;
452
}
453

454
int test_auth_pubkey(LIBSSH2_SESSION *session, int flags,
455
                     const char *username,
456
                     const char *password,
457
                     const char *fn_pub,
458
                     const char *fn_priv)
459
{
460
    int rc;
461
    const char *userauth_list;
462

463
    /* Ignore our hard-wired Dockerfile user when not running under Docker */
464
    if(!openssh_fixture_have_docker() && strcmp(username, "libssh2") == 0) {
465
        username = getenv("USER");
466
        if(!username) {
467
#ifdef _WIN32
468
            username = getenv("USERNAME");
469
#else
470
            username = getenv("LOGNAME");
471
#endif
472
        }
473
    }
474

475
    userauth_list = libssh2_userauth_list(session, username,
476
                                          (unsigned int)strlen(username));
477
    if(!userauth_list) {
478
        print_last_session_error("libssh2_userauth_list");
479
        return 1;
480
    }
481

482
    if(!strstr(userauth_list, "publickey")) {
483
        fprintf(stderr, "'publickey' was expected in userauth list: %s\n",
484
                userauth_list);
485
        return 1;
486
    }
487

488
    if((flags & TEST_AUTH_FROMMEM) != 0) {
489
        char *buffer = NULL;
490
        size_t len = 0;
491

492
        if(read_file(srcdir_path(fn_priv), &buffer, &len)) {
493
            fprintf(stderr, "Reading key file failed.\n");
494
            return 1;
495
        }
496

497
        rc = libssh2_userauth_publickey_frommemory(session,
498
                                                   username, strlen(username),
499
                                                   NULL, 0,
500
                                                   buffer, len,
501
                                                   NULL);
502

503
        free(buffer);
504
    }
505
    else {
506
        rc = libssh2_userauth_publickey_fromfile_ex(session, username,
507
                                                (unsigned int)strlen(username),
508
                                                    srcdir_path(fn_pub),
509
                                                    srcdir_path(fn_priv),
510
                                                    password);
511
    }
512

513
    if((flags & TEST_AUTH_SHOULDFAIL) != 0) {
514
        if(rc == 0) {
515
            fprintf(stderr, "Public-key auth succeeded with wrong key\n");
516
            return 1;
517
        }
518
    }
519
    else {
520
        if(rc) {
521
            print_last_session_error("libssh2_userauth_publickey_fromfile_ex");
522
            return 1;
523
        }
524
    }
525

526
    return 0;
527
}
528

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.