Subversion Repositories tpanel

Rev

Rev 472 | Details | Compare with Previous | Last modification | View Log | RSS feed

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