00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00047 #include <string.h>
00048 
00049 #ifdef _WIN32
00050 #  define WIN32_LEAN_AND_MEAN
00051 #  include <windows.h>
00052 #  include <winsock2.h>
00053 #  include <ws2tcpip.h>
00054 #  define XDMAPI __cdecl
00055 #  define XDMEXP __declspec(dllexport)
00056 #  define socket_t SOCKET
00057 #  define strcasecmp _stricmp
00058 #  ifdef ENABLE_SSL
00059 #    define HAVE_LIBSSL 1
00060 #  endif
00061 #else
00062 #  if HAVE_CONFIG_H
00063 #    include <config.h>
00064 #  endif
00065 #  include <sys/types.h>
00066 #  include <sys/socket.h>
00067 #  include <netdb.h>
00068 #  include <errno.h>
00069 #  define XDMAPI
00070 #  define XDMEXP
00071 #  define socket_t int
00072 #  define closesocket close
00073 #  define INVALID_SOCKET -1
00074 #  define WSAECONNRESET ECONNRESET
00075 #  define WSAGetLastError() errno
00076 #endif
00077 
00078 #include <stddef.h>
00079 #include <string.h>
00080 
00081 #define CNF_SECURE      "xdasd.loggers.netstream.secure"
00082 #define CNF_SERVER      "xdasd.loggers.netstream.server"
00083 #define CNF_PORT        "xdasd.loggers.netstream.port"
00084 
00085 #define XDM_DEF_SRVSTR  "localhost"
00086 #define XDM_DEF_PORTSTR "1468"   
00087 
00089 static void (*s_fplogmsg)(int level, const char * msg, ... ) = 0;
00090 
00092 static char * (*s_fpgetcnfstr)(const char *, char *, size_t *) = 0;
00093 
00095 static socket_t s_skt = INVALID_SOCKET;
00096 static char s_srvstr[512];
00097 static char s_portstr[32];
00098 
00099 #if HAVE_LIBSSL
00100 #  include <openssl/ssl.h>
00101 #  ifdef _WIN32
00102 #    include <openssl/rand.h>
00103 #  endif
00104 #  define CNF_TRUSTFILE "xdasd.loggers.netstream.trustfile"
00105 #  define CNF_KEYFILE   "xdasd.loggers.netstream.keyfile"
00106 #  define CNF_KEYPWD    "xdasd.loggers.netstream.keypwd"
00107 #  define CNF_CIPHERS   "xdasd.loggers.netstream.ciphers"
00108 
00110 static SSL_CTX * s_ctx = 0;
00111 static SSL * s_ssl = 0;
00112 static int s_srvauth_required = 0;
00113 
00126 static int pem_passwd_cb(char * buf, int size, int rwflag, void * passwd)
00127 {
00128    (void)rwflag;  
00129 
00130    *buf = 0;
00131    if (passwd != 0)
00132       strncpy(buf, (char *)passwd, size);
00133    buf[size - 1] = 0;
00134    return strlen(buf);
00135 }
00136 
00149 static SSL_CTX * initialize_ctx(const char * trustfile, 
00150       const char * keyfile, const char * password, 
00151       const char * ciphers)
00152 {
00153    SSL_CTX * ctx;
00154 
00155    
00156    SSL_library_init();
00157    SSL_load_error_strings();
00158    
00159    
00160    ctx = SSL_CTX_new(SSLv23_method());
00161    
00162    
00163    if (keyfile && *keyfile)
00164    {
00165       
00166       if (!SSL_CTX_use_certificate_chain_file(ctx, keyfile))
00167       {
00168          s_fplogmsg(0, "netstream: Can't read certificates from %s.\n", keyfile);
00169          SSL_CTX_free(ctx);
00170          return 0;
00171       }
00172 
00173       
00174       if (password && *password)
00175       {
00176          
00177          SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
00178          SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *)password);
00179       }
00180       
00181       
00182       if (!SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))
00183       {
00184          s_fplogmsg(0, "netstream: Can't read keys from %s.\n", keyfile);
00185          SSL_CTX_free(ctx);
00186          return 0;
00187       }
00188    }
00189 
00190    
00191    if (trustfile && *trustfile)
00192    {
00193       
00194       s_srvauth_required = 1;
00195       if (!SSL_CTX_load_verify_locations(ctx, trustfile, 0))
00196       {
00197          s_fplogmsg(0, "netstream: Can't read CA trust list from %s.\n", trustfile);
00198          SSL_CTX_free(ctx);
00199          return 0;
00200       }
00201    }
00202 
00203    
00204    if (ciphers && *ciphers)
00205    {
00206       
00207       if (!SSL_CTX_set_cipher_list(s_ctx, ciphers))
00208       {
00209          s_fplogmsg(0, "netstream: no requested cipher available.\n");
00210          SSL_CTX_free(ctx);
00211          return 0;
00212       }
00213    }
00214 
00215 #if (OPENSSL_VERSION_NUMBER < 0x00905100L)
00216    SSL_CTX_set_verify_depth(ctx, 1);
00217 #endif
00218    
00219 #ifdef _WIN32
00220    
00221 
00222    RAND_add(trustfile, strlen(trustfile), strlen(trustfile));
00223 #endif
00224 
00225    return ctx;
00226 }
00227 
00239 static int ns_check_cert(SSL * ssl, const char * host)
00240 {
00241    X509 * peer;
00242    char peer_CN[256];
00243    
00244    if (SSL_get_verify_result(ssl) != X509_V_OK)
00245       s_fplogmsg(0, "netstream: Can't verify server (%s) certificate.\n", host);
00246    
00247    
00248 
00249    
00250    
00251    if ((peer = SSL_get_peer_certificate(ssl)) == 0)
00252    {
00253       s_fplogmsg(0, "netstream: Server (%s) presents no certificate.\n", host);
00254       return -1;
00255    }
00256 
00257    
00258    X509_NAME_get_text_by_NID(X509_get_subject_name(peer), 
00259          NID_commonName, peer_CN, 256);
00260    if (strcasecmp(peer_CN, host) != 0)
00261    {
00262       s_fplogmsg(0, "netstream: Common name (%s) doesn't "
00263             "match host name (%s).\n", peer_CN, host);
00264       return -1;
00265    }
00266 
00267    return 0;
00268 }
00269 #endif
00270 
00278 static void ns_disconnect(void)
00279 {
00280 #if HAVE_LIBSSL
00281    if (s_ssl != 0)
00282       SSL_free(s_ssl), s_ssl = 0;
00283 #endif
00284 
00285    if (s_skt != INVALID_SOCKET)
00286       closesocket(s_skt), s_skt = INVALID_SOCKET;
00287 }
00288 
00301 static int ns_connect(const char * host, const char * service)
00302 {
00303    int err;
00304    struct addrinfo hints;
00305    struct addrinfo * alist = 0;
00306 
00307    ns_disconnect();  
00308 
00309    memset(&hints, 0, sizeof(hints));
00310    hints.ai_family = AF_INET;
00311    hints.ai_socktype = SOCK_STREAM;
00312    hints.ai_protocol = IPPROTO_TCP;
00313 
00314    
00315    if ((err = getaddrinfo(host, service, &hints, &alist)) != 0)
00316       s_fplogmsg(0, "netstream: Unable to formulate server address, error %d.\n", err);
00317    else
00318    {
00319       s_skt = socket(alist->ai_family, alist->ai_socktype, alist->ai_protocol);
00320       if (s_skt == INVALID_SOCKET)
00321       {
00322          err = WSAGetLastError();
00323          s_fplogmsg(0, "netstream: socket error %d.\n", err);
00324       }
00325       else 
00326       {
00327          s_fplogmsg(0, "netstream: connecting to %s:%s.\n", host, service);
00328          err = connect(s_skt, (struct sockaddr *)alist->ai_addr, (int)alist->ai_addrlen);
00329          if (err != 0)
00330          {
00331             err = WSAGetLastError();
00332             s_fplogmsg(0, "netstream: connect failed, %d.\n", err);
00333          }
00334       }
00335       freeaddrinfo(alist);
00336    }
00337 
00338 #if HAVE_LIBSSL
00339    if (err != 0 && s_ctx != 0)
00340    {
00341       if ((s_ssl = SSL_new(s_ctx)) == 0)
00342       {
00343          s_fplogmsg(0, "netstream: SSL_new failed.\n");
00344          ns_disconnect();
00345          err = -1;
00346       }
00347       else
00348       {
00349          BIO * sbio;
00350          if ((sbio = BIO_new_socket((int)s_skt, BIO_NOCLOSE)) == 0)
00351          {
00352             s_fplogmsg(0, "netstream: BIO_new_socket failed.\n");
00353             ns_disconnect();
00354             err = -1;
00355          }
00356          else
00357          {
00358             SSL_set_bio(s_ssl, sbio, sbio);
00359             if (SSL_connect(s_ssl) <= 0)
00360             {
00361                s_fplogmsg(0, "netstream: SSL_connect failed, %d.\n", err);
00362                ns_disconnect();
00363                err = -1;
00364             }
00365             else if (s_srvauth_required
00366                   && (err = ns_check_cert(s_ssl, host)) != 0)
00367                ns_disconnect();
00368          }
00369       }
00370    }
00371 #endif
00372 
00373    return err;
00374 }
00375 
00385 static int ns_write(const char * msg, size_t msgsz)
00386 {
00387    int err = 0;
00388    const char * send_api = "send";
00389 
00390 #if HAVE_LIBSSL
00391    if (s_ctx != 0)
00392    {
00393       int r;
00394       send_api = "SSL_write";
00395       if ((r = SSL_write(s_ssl, msg, (int)msgsz)) > 0)
00396           r = SSL_write(s_ssl, "\r\n", 2);
00397       err = SSL_get_error(s_ssl, r);
00398    }
00399    else
00400 #endif
00401    {
00402       if (send(s_skt, msg, (int)msgsz, 0) < 0
00403             || send(s_skt, "\r\n", 2, 0) < 0)
00404          err = WSAGetLastError();
00405    }
00406    if (err != 0)
00407       s_fplogmsg(0, "netstream: %s failed (%d) on record [ %.*s ].\n", 
00408             send_api, err, msgsz, msg);
00409    return err;
00410 }
00411 
00422 XDMEXP int XDMAPI xdm_append(const char ** msgflds)
00423 {
00424    int err;
00425 
00426    
00427    if (s_skt == INVALID_SOCKET)
00428       return -1;
00429 
00430    if ((err = ns_write(msgflds[0], msgflds[33] - msgflds[0] - 2)) != 0)
00431    {
00432       
00433       s_fplogmsg(0, "netstream: attempting to reconnect...\n");
00434       if (ns_connect(s_srvstr, s_portstr) < 0)
00435       {
00436          s_fplogmsg(0, "netstream: reconnect failed, closing stream.\n");
00437          return -1;
00438       }
00439       err = ns_write(msgflds[0], msgflds[33] - msgflds[0] - 2);
00440    }
00441    return err;
00442 }
00443 
00448 XDMEXP void XDMAPI xdm_exit(void)
00449 {
00450    ns_disconnect();
00451 
00452 #if HAVE_LIBSSL
00453    if (s_ctx != 0)
00454       SSL_CTX_free(s_ctx), s_ctx = 0;
00455 #endif
00456 
00457 #ifdef _WIN32
00458    WSACleanup();
00459 #endif
00460 }
00461 
00468 XDMEXP int XDMAPI xdm_init(void (*logmsg)(int level, const char * msg, ... ),
00469       char * (*getcnfstr)(const char *, char *, size_t *))
00470 {
00471    int err;
00472    size_t srvstrsz = sizeof(s_srvstr);
00473    size_t portstrsz = sizeof(s_portstr);
00474 
00475    
00476    s_fplogmsg = logmsg;
00477    s_fpgetcnfstr = getcnfstr;
00478 
00479 #ifdef _WIN32
00480    {
00481       WSADATA wsadata;
00482       if ((err = WSAStartup(MAKEWORD(2, 2), &wsadata)) != 0)
00483       {
00484          s_fplogmsg(0, "netstream: winsock init failed, %d.\n", err);
00485          return err;
00486       }
00487    }
00488 #endif
00489 
00490 #if HAVE_LIBSSL
00491    {
00492       int secure = 0;
00493       char secstr[32];
00494       size_t secstrsz = sizeof(secstr);
00495 
00496       
00497       s_fpgetcnfstr(CNF_SECURE, secstr, &secstrsz);
00498       if (secstrsz != 0)
00499          secure = (toupper(*secstr) == 'Y' || toupper(*secstr) == 'T');
00500 
00501       if (secure)
00502       {
00503          char trustfile[512];
00504          char keyfile[512];
00505          char keypwd[512];
00506          char ciphers[512];
00507          size_t trustfilesz = sizeof(trustfile);
00508          size_t keyfilesz = sizeof(keyfile);
00509          size_t keypwdsz = sizeof(keypwd);
00510          size_t cipherssz = sizeof(ciphers);
00511 
00512          
00513          *trustfile = *keyfile = *keypwd = *ciphers = 0;
00514          s_fpgetcnfstr(CNF_TRUSTFILE, trustfile, &trustfilesz);
00515          s_fpgetcnfstr(CNF_KEYFILE, keyfile, &keyfilesz);
00516          s_fpgetcnfstr(CNF_KEYPWD, keypwd, &keypwdsz);
00517          s_fpgetcnfstr(CNF_CIPHERS, ciphers, &cipherssz);
00518 
00519          
00520          if ((s_ctx = initialize_ctx(trustfile, keyfile, keypwd, ciphers)) == 0)
00521          {
00522             s_fplogmsg(0, "netstream: SSL context initialization failed.\n");
00523             xdm_exit();
00524             return -1;
00525          }
00526       }
00527    }
00528 #endif
00529 
00530    
00531    s_fpgetcnfstr(CNF_SERVER, s_srvstr, &srvstrsz);
00532    if (srvstrsz == 0)
00533       strcpy(s_srvstr, XDM_DEF_SRVSTR);
00534 
00535    s_fpgetcnfstr(CNF_PORT, s_portstr, &portstrsz);
00536    if (portstrsz == 0)
00537       strcpy(s_portstr, XDM_DEF_PORTSTR);
00538 
00539    
00540    if ((err = ns_connect(s_srvstr, s_portstr)) < 0)
00541       xdm_exit();
00542 
00543    return err;
00544 }
00545