Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
86 andreas 1
/*
2
 * Copyright (C) 2022 by Andreas Theofilu <andreas@theosys.at>
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
18
 
88 andreas 19
#include <chrono>
20
#include <thread>
21
 
86 andreas 22
#include "tsocket.h"
23
#include "terror.h"
24
#include "tconfig.h"
89 andreas 25
#include "texcept.h"
86 andreas 26
 
27
#include <string.h>
28
#include <strings.h>
29
#include <sys/socket.h>
30
#include <sys/types.h>
31
#include <unistd.h>
32
#include <stdlib.h>
33
#include <fcntl.h>
34
#include <netinet/in.h>
35
#include <netdb.h>
36
#include <netinet/tcp.h>
37
#include <openssl/err.h>
38
#include <sys/socket.h>
39
#include <arpa/inet.h>
40
#include <signal.h>
41
#include <poll.h>
42
 
43
using std::string;
44
 
45
int _cert_callback(int preverify_ok, X509_STORE_CTX *ctx);
46
 
92 andreas 47
TSocket::TSocket()
48
{
49
    DECL_TRACER("TSocket::TSocket()")
50
}
51
 
86 andreas 52
TSocket::TSocket(const string& host, int port)
53
{
92 andreas 54
    DECL_TRACER("TSocket::TSocket(const std::string& host, int port)");
86 andreas 55
 
56
    mHost = host;
57
    mPort = port;
58
}
59
 
60
TSocket::~TSocket()
61
{
62
    DECL_TRACER("TSocket::~TSocket()");
63
 
64
    close();
65
}
66
 
67
 
68
bool TSocket::connect(bool encrypt)
69
{
88 andreas 70
    DECL_TRACER("TSocket::connect(bool encrypt)");
86 andreas 71
 
72
    struct addrinfo *ainfo = nullptr;
73
    int sock = -1;
74
    int on = 1;
75
    bool retry = true;
76
 
130 andreas 77
    MSG_DEBUG("Trying to connect to host " << mHost << " at port " << mPort);
86 andreas 78
 
79
    if ((ainfo = lookup_host(mHost, mPort)) == nullptr)
80
        return false;
81
 
82
    while (ainfo && retry)
83
    {
84
        sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
85
 
86
        if (sock == -1)
87
        {
93 andreas 88
            MSG_ERROR("[" << mHost << "] Error opening socket: " << strerror(errno));
86 andreas 89
            ainfo = ainfo->ai_next;
90
            continue;
91
        }
92
 
93 andreas 93
        MSG_DEBUG("[" << mHost << "] Socket successfully created.");
86 andreas 94
 
95
        struct timeval tv;
96
 
97
        // FIXME: Make the timeouts configurable!
98
        tv.tv_sec = 10;
99
        tv.tv_usec = 0;
100
 
101
        if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(int)) == -1)
102
        {
93 andreas 103
            MSG_ERROR("[" << mHost << "] Error setting socket options for address reuse: " << strerror(errno));
86 andreas 104
            ::close(sock);
105
            return false;
106
        }
107
 
108
        if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof(struct timeval)) == -1)
109
        {
93 andreas 110
            MSG_ERROR("[" << mHost << "] Error setting socket options for receive: " << strerror(errno));
86 andreas 111
            ::close(sock);
112
            return false;
113
        }
114
 
88 andreas 115
        if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tv, sizeof(struct timeval)) == -1)
116
        {
93 andreas 117
            MSG_ERROR("[" << mHost << "] Error setting socket options for send: " << strerror(errno));
88 andreas 118
            ::close(sock);
119
            return false;
120
        }
121
 
86 andreas 122
        if (::connect(sock, ainfo->ai_addr, ainfo->ai_addrlen) == -1)
123
        {
93 andreas 124
            if (errno != EINPROGRESS)
125
            {
126
                MSG_ERROR("[" << mHost << "] Connect error: " << strerror(errno));
127
                ::close(sock);
128
                mConnected = false;
129
                return false;
130
            }
131
            else
132
            {
130 andreas 133
                MSG_DEBUG("[" << mHost << "] Connection is in progress ...");
93 andreas 134
                mConnected = true;
135
                break;
136
            }
86 andreas 137
        }
138
        else
139
        {
130 andreas 140
            MSG_DEBUG("[" << mHost << "] Successfully connected.");
87 andreas 141
            mConnected = true;
86 andreas 142
            break;
143
        }
144
    }
145
 
134 andreas 146
    if (ainfo->ai_family == AF_INET)
147
    {
148
        char str[INET_ADDRSTRLEN];
149
        struct sockaddr_in addr;
150
        socklen_t len = sizeof(addr);
151
        getsockname(sock, (struct sockaddr *)&addr, &len);
152
        mMyIP.assign(inet_ntop(AF_INET, &(addr.sin_addr), str, INET_ADDRSTRLEN));
153
    }
154
    else
155
    {
156
        char str[INET6_ADDRSTRLEN];
157
        struct sockaddr_in6 addr;
158
        socklen_t len = sizeof(addr);
159
        getsockname(sock, (struct sockaddr *)&addr, &len);
160
        mMyIP.assign(inet_ntop(AF_INET6, &(addr.sin6_addr), str, INET6_ADDRSTRLEN));
161
    }
162
 
163
    MSG_DEBUG("Client IP: " << mMyIP);
164
 
86 andreas 165
    if (ainfo == nullptr)
87 andreas 166
    {
93 andreas 167
        MSG_ERROR("[" << mHost << "] No network interface to connect to target was found!");
87 andreas 168
        mConnected = false;
86 andreas 169
        return false;
87 andreas 170
    }
86 andreas 171
 
172
    if (encrypt)
173
    {
174
        int ret;
175
 
93 andreas 176
        MSG_DEBUG("[" << mHost << "] Initializing SSL connection ...");
86 andreas 177
        mCtx = initCTX();
178
 
179
        if (mCtx == NULL)
180
        {
93 andreas 181
            MSG_ERROR("[" << mHost << "] Error initializing CTX.");
86 andreas 182
            ::close(sock);
87 andreas 183
            mConnected = false;
86 andreas 184
            return false;
185
        }
186
 
187
        mSsl = SSL_new(mCtx);      /* create new SSL connection state */
188
 
189
        if (mSsl == NULL)
190
        {
191
            log_ssl_error();
192
            SSL_CTX_free(mCtx);
193
            ::close(sock);
87 andreas 194
            mConnected = false;
86 andreas 195
            return false;
196
        }
197
 
198
        SSL_set_fd(mSsl, sock);    /* attach the socket descriptor */
199
 
200
        if (TConfig::certCheck())
201
        {
202
            SSL_set_verify(mSsl, SSL_VERIFY_PEER, _cert_callback);
93 andreas 203
            MSG_TRACE("[" << mHost << "] Verify on peer certificate was set.");
86 andreas 204
        }
205
 
206
        while ((ret = SSL_connect(mSsl)) < 0)
207
        {
208
            fd_set fds;
209
            FD_ZERO(&fds);
210
            FD_SET(sock, &fds);
211
 
212
            switch (SSL_get_error(mSsl, ret))
213
            {
214
                case SSL_ERROR_WANT_READ:
215
                    select(sock + 1, &fds, NULL, NULL, NULL);
216
                break;
217
 
218
                case SSL_ERROR_WANT_WRITE:
219
                    select(sock + 1, NULL, &fds, NULL, NULL);
220
                break;
221
 
222
                default:
93 andreas 223
                    MSG_ERROR("[" << mHost << "] Error getting a new SSL handle.");
86 andreas 224
                    SSL_CTX_free(mCtx);
225
                    ::close(sock);
226
                    SSL_free(mSsl);
87 andreas 227
                    mConnected = false;
86 andreas 228
                    return false;
229
            }
230
        }
231
 
232
        if (TConfig::certCheck())
233
        {
234
            if (SSL_get_peer_certificate(mSsl))
235
            {
93 andreas 236
                MSG_DEBUG("[" << mHost << "] Result of peer certificate verification is checked ...");
86 andreas 237
 
93 andreas 238
                if (SSL_get_verify_result(mSsl) != X509_V_OK)
86 andreas 239
                {
93 andreas 240
                    MSG_ERROR("[" << mHost << "] Error verifiying peer.");
86 andreas 241
                    SSL_CTX_free(mCtx);
242
                    ::close(sock);
243
                    SSL_free(mSsl);
87 andreas 244
                    mConnected = false;
86 andreas 245
                    return false;
246
                }
247
 
93 andreas 248
                MSG_TRACE("[" << mHost << "] Certificate was valid.");
86 andreas 249
            }
250
            else
93 andreas 251
                MSG_WARNING("[" << mHost << "] Peer offered no or invalid certificate!");
86 andreas 252
        }
253
 
254
        mEncrypted = true;
255
    }
256
 
257
    mSockfd = sock;
258
    return true;
259
}
260
 
261
bool TSocket::connect(const string& host, int port, bool encrypt)
262
{
88 andreas 263
    DECL_TRACER("TSocket::connect(const string&, int port, bool encrypt)");
86 andreas 264
 
265
    if (host.empty() || port < 1)
266
    {
88 andreas 267
        MSG_ERROR("CONNECT: Invalid credentials! (HOST: " << (host.empty() ? "<none>" : host) << ", PORT: " << port << ")");
86 andreas 268
        return false;
269
    }
270
 
271
    if (mConnected && host == mHost && port == mPort)
87 andreas 272
    {
130 andreas 273
        MSG_DEBUG("[" << mHost << "] Already connected.");
86 andreas 274
        return true;
87 andreas 275
    }
86 andreas 276
 
277
    if (mConnected)
89 andreas 278
        close();
86 andreas 279
 
280
    mHost = host;
281
    mPort = port;
282
    return connect(encrypt);
283
}
284
 
93 andreas 285
bool TSocket::isSockValid()
286
{
287
    DECL_TRACER("TSocket::isSockValid()");
288
 
289
    if (!mConnected || mSockfd <= 0)
290
        return false;
291
 
292
    int optval;
293
    socklen_t optlen = sizeof(optval);
294
 
295
    int res = getsockopt(mSockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen);
296
 
297
    if (optval == 0 && res == 0)
298
        return true;
299
 
300
    if (res != 0)
301
    {
302
        MSG_ERROR("[" << mHost << "] Network error: " << strerror(errno));
303
    }
304
 
305
    return false;
306
}
307
 
112 andreas 308
size_t TSocket::receive(char* buffer, size_t size, bool doPoll)
86 andreas 309
{
310
    DECL_TRACER("TSocket::receive(char* buffer, size_t size)");
311
 
312
    int proto = 0;
88 andreas 313
    bool retry = false;
314
    std::chrono::system_clock::time_point end = std::chrono::system_clock::now() + std::chrono::seconds(10);
86 andreas 315
 
92 andreas 316
    if (!mConnected || buffer == nullptr || (mEncrypted && mSsl == nullptr))
94 andreas 317
        return npos;
86 andreas 318
 
319
    if (!mEncrypted)
320
        proto = 0;
321
    else
322
        proto = 1;
323
 
87 andreas 324
    struct pollfd pfd;
88 andreas 325
    int nfds = 1;       // Only one entry in structure
87 andreas 326
 
327
    pfd.fd = mSockfd;
328
    pfd.events = POLLIN;
329
 
88 andreas 330
    int s = 0;
331
 
332
    do
86 andreas 333
    {
112 andreas 334
        if (doPoll)
335
            s = poll(&pfd, nfds, 10000);    // FIXME: Make the timeout configurable.
336
        else
337
            s = 1;
88 andreas 338
 
339
        if (s < 0)
87 andreas 340
        {
93 andreas 341
            close();
342
            XCEPTNETWORK("[" + mHost + "] Poll error on read: " + strerror(errno));
88 andreas 343
        }
344
 
345
        if (s == 0)
346
        {
347
            if (std::chrono::system_clock::now() < end)
97 andreas 348
            {
88 andreas 349
                retry = true;
97 andreas 350
                MSG_DEBUG("looping ...");
351
            }
88 andreas 352
            else
93 andreas 353
            {
354
                errno = ETIMEDOUT;
88 andreas 355
                retry = false;
93 andreas 356
            }
88 andreas 357
        }
358
        else
359
        {
87 andreas 360
            switch (proto)
361
            {
362
                case 0: return read(mSockfd, buffer, size);
363
                case 1: return SSL_read(mSsl, buffer, size);
364
            }
365
        }
86 andreas 366
    }
88 andreas 367
    while (retry);
368
 
94 andreas 369
    return npos;
88 andreas 370
}
371
 
372
size_t TSocket::readAbsolut(char *buffer, size_t size)
373
{
374
    DECL_TRACER("TSocket::readAbsolut(char *buffer, size_t size)");
375
 
92 andreas 376
    if (!mConnected || buffer == nullptr || !size)
94 andreas 377
        return npos;
88 andreas 378
 
379
    size_t rest = size;
380
    char *buf = new char[size + 1];
381
    char *p = buffer;
89 andreas 382
    std::chrono::system_clock::time_point end = std::chrono::system_clock::now() + std::chrono::seconds(10);
88 andreas 383
 
384
    while (rest && mConnected)
87 andreas 385
    {
88 andreas 386
        size_t rec = receive(buf, rest);
387
 
94 andreas 388
        if (rec != npos && rec > 0)
88 andreas 389
        {
390
            rest -= rec;
391
            memmove(p, buf, rec);
392
            p += rec;
89 andreas 393
            end = std::chrono::system_clock::now() + std::chrono::seconds(10);
88 andreas 394
        }
89 andreas 395
        else if (std::chrono::system_clock::now() >= end)
396
        {
93 andreas 397
            string message = "[" + mHost + "] Read: ";
88 andreas 398
 
89 andreas 399
            if (!mEncrypted)
93 andreas 400
            {
401
                if (errno)
402
                    message.append(strerror(errno));
403
                else
404
                    message.append("Timeout on reading");
405
            }
89 andreas 406
            else
407
            {
408
                log_ssl_error();
409
                message.append("Read error!");
410
            }
411
 
412
            close();
93 andreas 413
            delete[] buf;
414
            buf = nullptr;
415
#ifdef __ANDROID__
416
            MSG_ERROR(message);
417
            return -1;
418
#else
89 andreas 419
            XCEPTNETWORK(message);
93 andreas 420
#endif
89 andreas 421
        }
422
 
88 andreas 423
        if (rest)
424
            std::this_thread::sleep_for(std::chrono::microseconds(1000));
87 andreas 425
    }
86 andreas 426
 
93 andreas 427
    if (buf)
428
        delete[] buf;
429
 
89 andreas 430
    return (size - rest);
86 andreas 431
}
432
 
433
size_t TSocket::send(char* buffer, size_t size)
434
{
435
    DECL_TRACER("TSocket::send(char* buffer, size_t size)");
436
 
437
    int proto = 0;
93 andreas 438
    bool retry = false;
439
    std::chrono::system_clock::time_point end = std::chrono::system_clock::now() + std::chrono::seconds(10);
86 andreas 440
 
88 andreas 441
    if (!mConnected || buffer == nullptr || (mEncrypted && mSsl == nullptr))
94 andreas 442
        return npos;
86 andreas 443
 
444
    if (!mEncrypted)
445
        proto = 0;
446
    else
447
        proto = 1;
448
 
93 andreas 449
    struct pollfd pfd;
450
    int nfds = 1;       // Only one entry in structure
451
 
452
    pfd.fd = mSockfd;
453
    pfd.events = POLLOUT;
454
 
455
    int s = 0;
456
 
457
    do
86 andreas 458
    {
93 andreas 459
        s = poll(&pfd, nfds, 10000);    // FIXME: Make the timeout configurable.
460
 
461
        if (s < 0)
462
        {
463
            close();
464
            XCEPTNETWORK("[" + mHost + "] Poll error on write: " + strerror(errno));
465
        }
466
 
467
        if (s == 0)
468
        {
469
            if (std::chrono::system_clock::now() < end)
470
                retry = true;
471
            else
472
            {
473
                retry = false;
474
                errno = ETIMEDOUT;
475
            }
476
        }
477
        else
478
        {
479
            switch (proto)
480
            {
481
                case 0: return write(mSockfd, buffer, size);
482
                case 1: return SSL_write(mSsl, buffer, size);
483
            }
484
        }
86 andreas 485
    }
93 andreas 486
    while (retry);
86 andreas 487
 
94 andreas 488
    return npos;
86 andreas 489
}
490
 
491
bool TSocket::close()
492
{
493
    DECL_TRACER("TSocket::close()");
494
 
89 andreas 495
    bool status = true;
496
 
86 andreas 497
    if (!mConnected)
498
        return true;
499
 
87 andreas 500
    if (mEncrypted && mSsl)
86 andreas 501
    {
87 andreas 502
        SSL_free(mSsl);
503
        mSsl = nullptr;
86 andreas 504
    }
505
 
93 andreas 506
    if (!isSockValid())
507
    {
508
        mConnected = false;
509
 
510
        if (mEncrypted && mCtx)
511
        {
512
            SSL_CTX_free(mCtx);
513
            mCtx = nullptr;
514
        }
515
 
516
        mSockfd = -1;
517
        mEncrypted = false;
518
        return false;
519
    }
520
 
87 andreas 521
    if (shutdown(mSockfd, SHUT_RDWR) != 0)
522
    {
93 andreas 523
        MSG_ERROR("[" << mHost << "] Error shutting down connection: " << strerror(errno));
89 andreas 524
        status = false;
87 andreas 525
    }
526
 
527
    mConnected = false;
528
 
86 andreas 529
    if (::close(mSockfd) != 0)
530
    {
93 andreas 531
        MSG_ERROR("[" << mHost << "] Error closing a socket: " << strerror(errno));
89 andreas 532
        status = false;
86 andreas 533
    }
534
 
88 andreas 535
    mSockfd = -1;
536
 
87 andreas 537
    if (mEncrypted && mCtx)
538
    {
539
        SSL_CTX_free(mCtx);
540
        mCtx = nullptr;
541
    }
542
 
86 andreas 543
    mEncrypted = false;
89 andreas 544
    return status;
86 andreas 545
}
546
 
547
struct addrinfo *TSocket::lookup_host (const string& host, int port)
548
{
88 andreas 549
    DECL_TRACER("TSocket::lookup_host (const string& host, int port)");
86 andreas 550
 
551
    struct addrinfo *res;
552
    struct addrinfo hints;
553
    char sport[16];
554
 
555
    memset (&hints, 0, sizeof (hints));
556
    hints.ai_family = AF_INET;
557
    hints.ai_protocol = IPPROTO_TCP;
558
    hints.ai_socktype = SOCK_STREAM;
559
    hints.ai_flags = AI_CANONNAME;
560
    snprintf(sport, sizeof(sport), "%d", port);
561
    int ret = 0;
562
 
563
    if ((ret = getaddrinfo (host.c_str(), sport, &hints, &res)) != 0)
564
    {
93 andreas 565
        MSG_ERROR("[" << mHost << "] Getaddrinfo: " << gai_strerror(ret));
86 andreas 566
        return nullptr;
567
    }
568
 
569
    return res;
570
}
571
 
572
void TSocket::initSSL()
573
{
88 andreas 574
    DECL_TRACER("TSocket::initSSL()");
86 andreas 575
 
576
    if (mSSLInitialized)
577
        return;
578
 
235 andreas 579
#if OPENSSL_API_COMPAT < 0x010100000
86 andreas 580
    SSL_library_init();
235 andreas 581
#endif
185 andreas 582
#if OPENSSL_SHLIB_VERSION < 3
86 andreas 583
    ERR_load_BIO_strings();
185 andreas 584
#endif
235 andreas 585
#if OPENSSL_API_COMPAT < 0x010100000
86 andreas 586
    ERR_load_crypto_strings();
587
    SSL_load_error_strings();
235 andreas 588
#endif
86 andreas 589
    mSSLInitialized = true;
590
}
591
 
592
SSL_CTX *TSocket::initCTX()
593
{
88 andreas 594
    DECL_TRACER("TSocket::initCTX()");
86 andreas 595
 
596
    SSL_CTX *ctx;
88 andreas 597
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
86 andreas 598
    const SSL_METHOD *method = TLS_client_method();
88 andreas 599
#else
86 andreas 600
    const SSL_METHOD *method = TLSv1_2_client_method();
88 andreas 601
#endif
86 andreas 602
    ctx = SSL_CTX_new(method);   /* Create new context */
603
 
604
    if ( ctx == NULL )
605
    {
606
        log_ssl_error();
607
        return NULL;
608
    }
609
 
610
    char *cert_check = getenv("CERT_CHECK");
611
 
612
    if (cert_check && strcmp(cert_check, "ON") == 0)
613
    {
614
        char *cert_path = getenv("CERT_PATH");
615
        char *cert_chain = getenv("CERT_CHAIN");
616
        char *cert_file = getenv("CERT_FILE");
617
        char *cert_type = getenv("CERT_TYPE");
618
 
619
        if (cert_path == NULL)
620
        {
621
            MSG_WARNING("Missing environment variable \"CERT_PATH\" defining the path to the cerificates.");
622
            return ctx;
623
        }
624
 
625
        if (cert_chain == NULL)
626
        {
627
            MSG_WARNING("Certificate check is enabled but no certificate chain file is set! No certificate verification was made.");
628
            return ctx;
629
        }
630
 
631
        SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, _cert_callback);
632
 
633
        if (cert_type == NULL)
634
            cert_type = (char *)"PEM";
635
 
636
        if (SSL_CTX_load_verify_locations(ctx, cert_chain, cert_path) != 1)
637
        {
638
            MSG_ERROR("Error with certificate " << cert_path << "/" << cert_chain);
639
            log_ssl_error();
640
            SSL_CTX_free(ctx);
641
            return NULL;
642
        }
643
 
644
        int type = SSL_FILETYPE_PEM;
645
 
646
        if (strcmp(cert_type, "ASN1") == 0)
647
            type = SSL_FILETYPE_ASN1;
648
 
649
        if (cert_file && SSL_CTX_use_certificate_file(ctx, cert_file, type) != 1)
650
        {
651
            MSG_ERROR("Error with certificate " << cert_file);
652
            log_ssl_error();
653
            SSL_CTX_free(ctx);
654
            return NULL;
655
        }
656
    }
657
 
658
    return ctx;
659
}
660
 
661
void TSocket::log_ssl_error()
662
{
88 andreas 663
    DECL_TRACER("TSocket::log_ssl_error()");
86 andreas 664
    unsigned long int err;
665
    char errstr[512];
666
 
667
    while ((err = ERR_get_error()) != 0)
668
    {
669
        ERR_error_string_n(err, &errstr[0], sizeof(errstr));
670
        MSG_ERROR(errstr);
671
    }
672
}
673
 
674
/*
675
 * Callback fuction for SSL connections.
676
 */
677
int _cert_callback(int preverify_ok, X509_STORE_CTX *ctx)
678
{
679
    DECL_TRACER("_cert_callback(int preverify_ok, X509_STORE_CTX *ctx)");
680
 
681
    char    buf[256];
682
    X509   *err_cert;
683
    int     err, depth;
684
 
685
    err_cert = X509_STORE_CTX_get_current_cert(ctx);
686
    err = X509_STORE_CTX_get_error(ctx);
687
    depth = X509_STORE_CTX_get_error_depth(ctx);
688
 
689
    /*
690
     * Retrieve the pointer to the SSL of the connection currently treated
691
     * and the application specific data stored into the SSL object.
692
     */
88 andreas 693
    X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
86 andreas 694
    X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
695
 
696
    if (!preverify_ok)
697
    {
698
        MSG_WARNING("verify error:num=" << err << ":" << X509_verify_cert_error_string(err) << ":depth=" << depth << ":" << buf);
699
    }
700
 
701
    /*
702
     * At this point, err contains the last verification error. We can use
703
     * it for something special
704
     */
705
    if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT))
706
    {
707
        X509_NAME_oneline(X509_get_issuer_name(err_cert), buf, 256);
708
        MSG_WARNING("issuer= " << buf);
709
    }
710
 
711
    return preverify_ok;
712
}