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