1 /* zxbusprod.c - Liberty oriented logging facility with log signing and encryption 2 * Copyright (c) 2012-2013 Synergetics (sampo@synergetics.be), All Rights Reserved. 3 * Copyright (c) 2010-2011 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved. 4 * Copyright (c) 2006-2009 Symlabs (symlabs@symlabs.com), All Rights Reserved. 5 * Author: Sampo Kellomaki (sampo@iki.fi) 6 * This is confidential unpublished proprietary source code of the author. 7 * NO WARRANTY, not even implied warranties. Contains trade secrets. 8 * Distribution prohibited unless authorized in writing. 9 * Licensed under Apache License 2.0, see file COPYING. 10 * $Id$ 11 * 12 * 17.8.2012, creted, based on zxlog.c --Sampo 13 * 19.8.2012, added tolerance for CRLF where strictly LF is meant --Sampo 14 * 6.9.2012, added SSL support --Sampo 15 * 9.9.2012, added persist support --Sampo 16 * 30.11.2013, fixed seconds handling re gmtime_r() - found by valgrind --Sampo 17 * 18 * Apart from formatting code, this is effectively a STOMP 1.1 client. Typically 19 * it will talk to zxbusd instances configured using BUS_URL options. 20 * 21 * See also: http://stomp.github.com/stomp-specification-1.1.html (20110331) 22 * Todo: implement anti fragmentation option (tcp CORK (check Nagle algo) or 23 * bundle writes in this code). 24 */ 25 26 #include "platform.h" /* needed on Win32 for pthread_mutex_lock() et al. */ 27 28 #include <fcntl.h> 29 #include <string.h> 30 #include <stdarg.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <errno.h> 34 #include <time.h> 35 #include <sys/types.h> 36 #include <sys/stat.h> 37 #ifdef MINGW 38 # include <winsock.h> 39 # ifndef EINPROGRESS 40 # define EINPROGRESS WSAEINPROGRESS /* Missing in mingw 1.0, 3.0 defines this in errno.h*/ 41 # endif 42 #else 43 # include <netdb.h> 44 # include <netinet/in.h> /* struct sockaddr_in */ 45 #endif 46 47 #ifdef USE_OPENSSL 48 #include <openssl/x509.h> 49 #include <openssl/rsa.h> 50 #include <openssl/evp.h> 51 #include <openssl/aes.h> 52 #include <openssl/ssl.h> 53 #endif 54 55 #include "errmac.h" 56 #include "zxid.h" 57 #include "zxidutil.h" /* for zx_zlib_raw_deflate(), safe_basis_64, and name_from_path */ 58 #include "zxidconf.h" 59 #include "c/zx-data.h" /* Generated. If missing, run `make dep ENA_GEN=1' */ 60 61 #define ZXBUS_BUF_SIZE 4096 62 /* Alias some struct fields for headers that can not be seen together. */ 63 #define receipt host 64 #define rcpt_id host 65 #define acpt_vers vers 66 #define tx_id vers 67 #define session login 68 #define subs_id login 69 #define subsc login 70 #define server pw 71 #define ack pw 72 #define msg_id pw 73 #define heart_bt dest 74 #define zx_rcpt_sig dest 75 76 #define STOMP_MIN_PDU_SIZE (sizeof("ACK\n\n\0\n")-1) 77 extern int zxbus_persist_flag; /* This is defined by option processing of zxbuslist */ 78 int zxbus_verbose = 0; /* This is set by option processing in zxbustailf */ 79 int zxbus_ascii_color = 0; /* Defined in option processing of zxbustailf or zxbuslist */ 80 81 #define SSL_ENCRYPTED_HINT "TLS or SSL connection wanted but other end did not speak protocol.\n" 82 #define ZXBUS_TIME_FMT "%04d%02d%02d-%02d%02d%02d.%03ld" 83 #define ZXBUS_TIME_ARG(t,usec) t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, \ 84 t.tm_hour, t.tm_min, t.tm_sec, usec/1000 85 86 #if 0 87 /*() Allocate memory for logging purposes. 88 * Generally memory allocation goes via zx_alloc() family of functions. However 89 * dues to special requirements of cryptographically implemeted logging, 90 * we maintain this special allocation function (which backends to zx_alloc()). 91 * Among the special features: This function makes sure the buffer size is 92 * rounded up to multiple of nonce to accommodate block ciphers. 93 * 94 * This function is considered internal. Do not use unless you know what you are doing. */ 95 96 /* Called by: zxbus_write_line x3 */ 97 static char* zxbus_alloc_zbuf(zxid_conf* cf, int *zlen, char* zbuf, int len, char* sig, int nonce) 98 { 99 char* p; 100 int siz = nonce + 2 + len + *zlen; 101 ROUND_UP(siz, nonce); /* Round up to block size */ 102 p = ZX_ALLOC(cf->ctx, siz); 103 if (nonce) 104 zx_rand(p, nonce); 105 p[nonce] = (len >> 8) & 0xff; 106 p[nonce+1] = len & 0xff; 107 if (len) { 108 memcpy(p+nonce+2, sig, len); 109 ZX_FREE(cf->ctx, sig); 110 } 111 memcpy(p+nonce+2+len, zbuf, *zlen); 112 ZX_FREE(cf->ctx, zbuf); 113 *zlen += nonce + 2 + len; 114 return p; 115 } 116 117 /*() Write a line to a log, taking care of all formalities of locking and 118 * observing all special options for signing and encryption of the logs. 119 * Not usually called directly (but you can if you want to), this is the 120 * work horse behind zxbus(). 121 * 122 * cf:: ZXID configuration object, used for memory allocation. 123 * c_path:: Path to the log file, as C string 124 * encflags:: Encryption flags. See LOG_ERR or LOG_ACT configuration options in zxidconf.h 125 * n:: length of log data 126 * logbuf:: The data that should be logged 127 */ 128 129 /* Called by: */ 130 void zxbus_write_line(zxid_conf* cf, char* c_path, int encflags, int n, const char* logbuf) 131 { 132 EVP_PKEY* log_sign_pkey; 133 struct rsa_st* rsa_pkey; 134 struct aes_key_st aes_key; 135 int len = 0, blen, zlen; 136 char sigletter = 'P'; 137 char encletter = 'P'; 138 char* p; 139 char* sig = 0; 140 char* zbuf; 141 char* b64; 142 char sigbuf[28+4]; /* Space for "SP " and sha1 */ 143 char keybuf[16]; 144 char ivec[16]; 145 if (n == -2) 146 n = strlen(logbuf); 147 if (encflags & 0x70) { /* Encrypt check */ 148 zbuf = zx_zlib_raw_deflate(cf->ctx, n-1, logbuf, &zlen); 149 switch (encflags & 0x06) { /* Sign check */ 150 case 0x02: /* Sx plain sha1 */ 151 sigletter = 'S'; 152 sig = ZX_ALLOC(cf->ctx, 20); 153 SHA1((unsigned char*)zbuf, zlen, (unsigned char*)sig); 154 len = 20; 155 break; 156 case 0x04: /* Rx RSA-SHA1 signature */ 157 sigletter = 'R'; 158 LOCK(cf->mx, "logsign-wrln"); 159 if (!(log_sign_pkey = cf->log_sign_pkey)) 160 log_sign_pkey = cf->log_sign_pkey = zxid_read_private_key(cf, "logsign-nopw-cert.pem"); 161 UNLOCK(cf->mx, "logsign-wrln"); 162 if (!log_sign_pkey) 163 break; 164 len = zxsig_data(cf->ctx, zlen, zbuf, &sig, log_sign_pkey, "enc log line", 0); 165 break; 166 case 0x06: /* Dx DSA-SHA1 signature */ 167 ERR("DSA-SHA1 sig not implemented in encrypted mode. Use RSA-SHA1 or none. %x", encflags); 168 break; 169 case 0: break; /* Px no signing */ 170 } 171 172 switch (encflags & 0x70) { 173 case 0x10: /* xZ RFC1951 zip + safe base64 */ 174 encletter = 'Z'; 175 zbuf = zxbus_alloc_zbuf(cf, &zlen, zbuf, len, sig, 0); 176 break; 177 case 0x20: /* xA RSA-AES */ 178 encletter = 'A'; 179 zbuf = zxbus_alloc_zbuf(cf, &zlen, zbuf, len, sig, 16); 180 zx_rand(keybuf, 16); 181 AES_set_encrypt_key((unsigned char*)keybuf, 128, &aes_key); 182 memcpy(ivec, zbuf, sizeof(ivec)); 183 AES_cbc_encrypt((unsigned char*)zbuf+16, (unsigned char*)zbuf+16, zlen-16, &aes_key, (unsigned char*)ivec, 1); 184 ROUND_UP(zlen, 16); /* Round up to block size */ 185 186 LOCK(cf->mx, "logenc-wrln"); 187 if (!cf->log_enc_cert) 188 cf->log_enc_cert = zxid_read_cert(cf, "logenc-nopw-cert.pem"); 189 rsa_pkey = zx_get_rsa_pub_from_cert(cf->log_enc_cert, "log_enc_cert"); 190 UNLOCK(cf->mx, "logenc-wrln"); 191 if (!rsa_pkey) 192 break; 193 194 len = RSA_size(rsa_pkey); 195 sig = ZX_ALLOC(cf->ctx, len); 196 if (RSA_public_encrypt(16, (unsigned char*)keybuf, (unsigned char*)sig, rsa_pkey, RSA_PKCS1_OAEP_PADDING) < 0) { 197 ERR("RSA enc fail %x", encflags); 198 zx_report_openssl_err("zxbus rsa enc"); 199 return; 200 } 201 p = ZX_ALLOC(cf->ctx, 2 + len + zlen); 202 p[0] = (len >> 8) & 0xff; 203 p[1] = len & 0xff; 204 memcpy(p+2, sig, len); 205 memcpy(p+2+len, zbuf, zlen); 206 ZX_FREE(cf->ctx, sig); 207 ZX_FREE(cf->ctx, zbuf); 208 zbuf = p; 209 zlen += 2 + len; 210 break; 211 case 0x30: /* xT RSA-3DES */ 212 encletter = 'T'; 213 ERR("Enc not implemented %x", encflags); 214 break; 215 case 0x40: /* xB AES */ 216 encletter = 'B'; 217 zbuf = zxbus_alloc_zbuf(cf, &zlen, zbuf, len, sig, 16); 218 if (!cf->log_symkey[0]) 219 zx_get_symkey(cf, "logenc.key", cf->log_symkey); 220 AES_set_encrypt_key((unsigned char*)cf->log_symkey, 128, &aes_key); 221 memcpy(ivec, zbuf, sizeof(ivec)); 222 AES_cbc_encrypt((unsigned char*)zbuf+16, (unsigned char*)zbuf+16, zlen-16, &aes_key, (unsigned char*)ivec, 1); 223 ROUND_UP(zlen, 16); /* Round up to block size */ 224 break; 225 case 0x50: /* xU 3DES */ 226 encletter = 'U'; 227 ERR("Enc not implemented %x", encflags); 228 break; 229 default: 230 ERR("Enc not implemented %x", encflags); 231 break; 232 } 233 234 blen = SIMPLE_BASE64_LEN(zlen) + 3 + 1; 235 b64 = ZX_ALLOC(cf->ctx, blen); 236 b64[0] = sigletter; 237 b64[1] = encletter; 238 b64[2] = ' '; 239 p = base64_fancy_raw(zbuf, zlen, b64+3, safe_basis_64, 1<<31, 0, 0, '.'); 240 blen = p-b64 + 1; 241 *p = '\n'; 242 write2_or_append_lock_c_path(c_path, 0, 0, blen, b64, "zxbus enc", SEEK_END, O_APPEND); 243 return; 244 } 245 246 /* Plain text, possibly signed. */ 247 248 switch (encflags & 0x06) { 249 case 0x02: /* SP plain sha1 */ 250 strcpy(sigbuf, "SP "); 251 sha1_safe_base64(sigbuf+3, n-1, logbuf); 252 sigbuf[3+27] = ' '; 253 len = 3+27+1; 254 p = sigbuf; 255 break; 256 case 0x04: /* RP RSA-SHA1 signature */ 257 LOCK(cf->mx, "logsign-wrln"); 258 if (!(log_sign_pkey = cf->log_sign_pkey)) 259 log_sign_pkey = cf->log_sign_pkey = zxid_read_private_key(cf, "logsign-nopw-cert.pem"); 260 UNLOCK(cf->mx, "logsign-wrln"); 261 if (!log_sign_pkey) 262 break; 263 zlen = zxsig_data(cf->ctx, n-1, logbuf, &zbuf, log_sign_pkey, "log line", 0); 264 len = SIMPLE_BASE64_LEN(zlen) + 4; 265 sig = ZX_ALLOC(cf->ctx, len); 266 strcpy(sig, "RP "); 267 p = base64_fancy_raw(zbuf, zlen, sig+3, safe_basis_64, 1<<31, 0, 0, '.'); 268 len = p-sig + 1; 269 *p = ' '; 270 p = sig; 271 break; 272 case 0x06: /* DP DSA-SHA1 signature */ 273 ERR("DSA-SHA1 signature not implemented %x", encflags); 274 break; 275 case 0: /* Plain logging, no signing, no encryption. */ 276 len = 5; 277 p = "PP - "; 278 break; 279 } 280 write2_or_append_lock_c_path(c_path, len, p, n, logbuf, "zxbus sig", SEEK_END, O_APPEND); 281 if (sig) 282 ZX_FREE(cf->ctx, sig); 283 } 284 285 /*() Helper function for formatting all kinds of logs. */ 286 287 static int zxbus_fmt(zxid_conf* cf, /* 1 */ 288 int len, char* logbuf, 289 struct timeval* ourts, /* 2 null allowed, will use current time */ 290 struct timeval* srcts, /* 3 null allowed, will use start of unix epoch... */ 291 const char* ipport, /* 4 null allowed, -:- or cf->ipport if not given */ 292 struct zx_str* entid, /* 5 null allowed, - if not given */ 293 struct zx_str* msgid, /* 6 null allowed, - if not given */ 294 struct zx_str* a7nid, /* 7 null allowed, - if not given */ 295 struct zx_str* nid, /* 8 null allowed, - if not given */ 296 const char* sigval, /* 9 null allowed, - if not given */ 297 const char* res, /* 10 */ 298 const char* op, /* 11 */ 299 const char* arg, /* 12 null allowed, - if not given */ 300 const char* fmt, /* 13 null allowed as format, ends the line */ 301 va_list ap) 302 { 303 int n; 304 char* p; 305 char sha1_name[28]; 306 struct tm ot; 307 struct tm st; 308 struct timeval ourtsdefault; 309 struct timeval srctsdefault; 310 311 /* Prepare values */ 312 313 if (!ourts) { 314 ourts = &ourtsdefault; 315 GETTIMEOFDAY(ourts, 0); 316 } 317 if (!srcts) { 318 srcts = &srctsdefault; 319 srctsdefault.tv_sec = 0; 320 srctsdefault.tv_usec = 501000; 321 } 322 GMTIME_R(ourts->tv_sec, ot); 323 GMTIME_R(srcts->tv_sec, st); 324 325 if (entid && entid->len && entid->s) { 326 sha1_safe_base64(sha1_name, entid->len, entid->s); 327 sha1_name[27] = 0; 328 } else { 329 sha1_name[0] = '-'; 330 sha1_name[1] = 0; 331 } 332 333 if (!ipport) { 334 ipport = cf->ipport; 335 if (!ipport) 336 ipport = "-:-"; 337 } 338 339 /* Format */ 340 341 n = snprintf(logbuf, len-3, ZXBUS_TIME_FMT " " ZXBUS_TIME_FMT 342 " %s %s" /* ipport sha1_name-of-ent */ 343 " %.*s" 344 " %.*s" 345 " %.*s" 346 " %s %s %s %s %s ", 347 ZXBUS_TIME_ARG(ot, ourts->tv_usec), ZXBUS_TIME_ARG(st, srcts->tv_usec), 348 ipport, sha1_name, 349 msgid?msgid->len:1, msgid?msgid->s:"-", 350 a7nid?a7nid->len:1, a7nid?a7nid->s:"-", 351 nid?nid->len:1, nid?nid->s:"-", 352 errmac_instance, STRNULLCHKD(sigval), res, op, arg?arg:"-"); 353 logbuf[len-1] = 0; /* must terminate manually as on win32 nul is not guaranteed */ 354 if (n <= 0 || n >= len-3) { 355 if (n < 0) platform_broken_snprintf(n, __FUNCTION__, len-3, "zxbus msg frame"); 356 D("Log buffer too short: %d chars needed", n); 357 if (n <= 0) 358 n = 0; 359 else 360 n = len-3; 361 } else { /* Space left: try printing the format string as well! */ 362 p = logbuf+n; 363 if (fmt && fmt[0]) { 364 n = vsnprintf(p, len-n-2, fmt, ap); 365 logbuf[len-1] = 0; /* must terminate manually as on win32 nul term is not guaranteed */ 366 if (n <= 0 || n >= len-(p-logbuf)-2) { 367 if (n < 0) platform_broken_snprintf(n, __FUNCTION__, len-n-2, fmt); 368 D("Log buffer truncated during format print: %d chars needed", n); 369 if (n <= 0) 370 n = p-logbuf; 371 else 372 n = len-(p-logbuf)-2; 373 } else 374 n += p-logbuf; 375 } else { 376 logbuf[n++] = '-'; 377 } 378 } 379 logbuf[n++] = '\n'; 380 logbuf[n] = 0; 381 /*logbuf[len-1] = 0;*/ 382 return n; 383 } 384 #endif 385 386 /*() Clear current PDU from read buffer, moving the data after 387 * it (i.e. next PDU in buffer) in position to be read. */ 388 389 /* Called by: zxbus_close x3, zxbus_listen_msg x4, zxbus_open_bus_url x2, zxbus_send_cmdf x3 */ 390 static void zxbus_shift_read_buf(zxid_conf* cf, struct zxid_bus_url* bu, struct stomp_hdr* stomp) 391 { 392 if (stomp->end_of_pdu) { 393 memmove(bu->m, stomp->end_of_pdu, bu->ap-stomp->end_of_pdu); 394 bu->ap = bu->m + (bu->ap-stomp->end_of_pdu); 395 D("shifted read_buf(%.*s)", (int)(bu->ap-bu->m), bu->m); 396 } 397 stomp->end_of_pdu = 0; 398 } 399 400 /*() Read and parse a frame from STOMP 1.1 connection (from zxbusd). 401 * Blocks until frame has been read. 402 * 403 * Return:: 1 on success, 0 on failure. 404 * 405 * In case of failure, caller should close the connection. The PDU 406 * data is left in bu->m, possibly with the following pdu as well. The 407 * caller should clean the buffer without loosing the next pdu 408 * fragment before calling this function again. For example: 409 * memmove(bu->m, stomp->end_of_pdu, bu->ap-stomp->end_of_pdu); 410 * bu->ap = bu->m + (bu->ap-stomp->end_of_pdu); 411 * stomp->end_of_pdu = 0; 412 * or by calling 413 * zxbus_shift_read_buf(cf, bu, stomp); 414 * 415 * The parsed headers are returned in the struct stomp_hdr. */ 416 417 /* Called by: zxbus_close, zxbus_listen_msg, zxbus_open_bus_url, zxbus_send_cmdf */ 418 int zxbus_read_stomp(zxid_conf* cf, struct zxid_bus_url* bu, struct stomp_hdr* stomp) 419 { 420 int need = 0, len = 0, got; 421 char* hdr; 422 char* h; 423 char* v; 424 char* p; 425 426 memset(stomp, 0, sizeof(struct stomp_hdr)); 427 428 while (bu->ap - bu->m < ZXBUS_BUF_SIZE) { 429 D("read, already buf(%.*s) need=%d len=%d buf_avail=%d", (int)(bu->ap-bu->m), bu->m, need, (int)(bu->ap-bu->m), (int)(ZXBUS_BUF_SIZE-(bu->ap - bu->m))); 430 if (need || bu->ap == bu->m) { 431 #ifdef USE_OPENSSL 432 if (bu->ssl) { 433 got = SSL_read(bu->ssl, bu->ap, ZXBUS_BUF_SIZE - (bu->ap - bu->m)); 434 if (got < 0) { 435 ERR("SSL_read(%x) bu_%p: (%d) %d %s", bu->fd, bu, got, errno, STRERROR(errno)); 436 zx_report_openssl_err("zxbus_read-ssl"); 437 return 0; 438 } 439 } else { 440 got = recv((SOCKET)bu->fd, bu->ap, ZXBUS_BUF_SIZE - (bu->ap - bu->m), 0); 441 if (got < 0) { 442 ERR("recv(%x) bu_%p: %d %s", bu->fd, bu, errno, STRERROR(errno)); 443 return 0; 444 } 445 } 446 #else 447 got = recv((SOCKET)bu->fd, bu->ap, ZXBUS_BUF_SIZE - (bu->ap - bu->m), 0); 448 if (got < 0) { 449 ERR("recv: %d %s", errno, STRERROR(errno)); 450 return 0; 451 } 452 #endif 453 if (!got) { 454 D("recv: returned empty, gotten=%ld", (long)(bu->ap - bu->m)); 455 return 0; 456 } 457 HEXDUMP("read:", bu->ap, bu->ap+got, /*16*/ 256); 458 bu->ap += got; 459 } 460 for (p = bu->m; p < bu->ap && ONE_OF_2(*p, '\n', '\r'); ++p) ; 461 if (p > bu->m) { 462 /* Wipe out initial newlines */ 463 memmove(bu->m, p, bu->ap - p); 464 bu->ap -= p - bu->m; 465 p = bu->m; 466 } 467 if (bu->ap - p < STOMP_MIN_PDU_SIZE) 468 goto read_more; 469 470 /* Extract command (always in beginning of buf) */ 471 472 hdr = memchr(p, '\n', bu->ap - p); 473 if (!hdr || ++hdr == bu->ap) 474 goto read_more; 475 p = hdr; 476 477 /* Decode headers 478 * 01234 5 6 7 479 * STOMP\n\n\0 480 * ^-p 481 * 01234 5 6 7 8 9 482 * STOMP\r\n\r\n\0 483 * ^-p 484 * STOMP\nhost:foo\n\n\0 485 * ^-p ^-pp 486 * STOMP\r\nhost:foo\r\n\r\n\0 487 * ^-p ^-pp 488 * STOMP\nhost:foo\naccept-version:1.1\n\n\0 489 * ^-p ^-pp ^-ppp 490 * STOMP\r\nhost:foo\r\naccept-version:1.1\r\n\r\n\0 491 * ^-p ^-pp ^-ppp 492 */ 493 494 while (!ONE_OF_2(*p,'\n','\r')) { /* Empty line separates headers from body. */ 495 h = p; 496 p = memchr(p, '\n', bu->ap - p); 497 if (!p || ++p == bu->ap) 498 goto read_more; 499 v = memchr(h, ':', p-h); 500 if (!v) { 501 ERR("Header missing colon. hdr(%.*s)", (int)(bu->ap-h), h); 502 return 0; 503 } 504 ++v; /* skip : */ 505 506 #define HDR(hdr, field, val) } else if (!memcmp(h, hdr, sizeof(hdr)-1)) { if (!stomp->field) stomp->field = (val) 507 508 if (!memcmp(h, "content-length:", sizeof("content-length:")-1)) { 509 if (!stomp->len) stomp->len = len = atoi(v); D("len=%d", stomp->len); 510 HDR("host:", host, v); 511 HDR("receipt:", receipt, v); 512 HDR("receipt-id:", rcpt_id, v); 513 HDR("zx-rcpt-sig:", zx_rcpt_sig, v); 514 HDR("version:", vers, v); 515 HDR("accept-version:", acpt_vers, v); 516 HDR("transaction:", tx_id, v); 517 HDR("login:", login, v); 518 HDR("passcode:", pw, v); 519 HDR("session:", session, v); 520 HDR("id:", subs_id, v); 521 HDR("subscription:", subsc, v); 522 HDR("server:", server, v); 523 HDR("ack:", ack, v); 524 HDR("message-id:", msg_id, v); 525 HDR("destination:", dest, v); 526 HDR("heart-beat:", heart_bt, v); 527 } else if (!memcmp(h, "message:", sizeof("message:")-1)) { /* ignore */ 528 } else if (!memcmp(h, "content-type:", sizeof("content-type:")-1)) { /* ignore */ 529 } else { 530 D("Unknown header(%.*s) ignored.", (int)(p-h), h); 531 } 532 } 533 534 /* Now body */ 535 536 if (*p == '\r') ++p; 537 stomp->body = ++p; 538 539 if (len) { 540 if (len < bu->ap - p) { 541 /* Got complete with content-length */ 542 p += len; 543 if (!*p++) 544 goto done; 545 ERR("No nul to terminate body. %d",0); 546 return 0; 547 } else { 548 goto read_more; 549 } 550 } else { 551 /* Scan until nul */ 552 while (1) { 553 if (bu->ap - p < 1) { /* too little, need more */ 554 goto read_more; 555 } 556 if (!*p++) { 557 stomp->len = p - stomp->body - 1; 558 goto done; 559 } 560 } 561 } 562 read_more: 563 need = 1; 564 continue; 565 } 566 if (bu->ap - bu->m >= ZXBUS_BUF_SIZE) { 567 ERR("PDU does not fit in buffer %d", (int)(bu->ap-bu->m)); 568 return 0; 569 } 570 done: 571 stomp->end_of_pdu = p; 572 return 1; 573 } 574 575 /*() ACK a message to STOMP 1.1 connection. 576 * N.B. ACK is not a command. Thus no RECEIPT is expected from server 577 * end (ACK really is the receipt for MESSAGE sent by server). 578 * 579 * Returns:: zero on failure and 1 on success. */ 580 581 /* Called by: zxbus_listen_msg */ 582 int zxbus_ack_msg(zxid_conf* cf, struct zxid_bus_url* bu, struct stomp_hdr* stompp) 583 { 584 int len; 585 char sigbuf[1024]; 586 char buf[1024]; 587 int subs_id_len, msg_id_len; 588 subs_id_len = strchr(stompp->subs_id, '\n') - stompp->subs_id; 589 msg_id_len = strchr(stompp->msg_id, '\n') - stompp->msg_id; 590 591 zxbus_mint_receipt(cf, sizeof(sigbuf), sigbuf, 592 msg_id_len, stompp->msg_id, 593 -2, stompp->dest, 594 -1, bu->eid, /* entity to which we issue this receipt */ 595 stompp->len, stompp->body); 596 len = snprintf(buf, sizeof(buf), "ACK\nsubscription:%.*s\nmessage-id:%.*s\nzx-rcpt-sig:%s\n\n%c", 597 subs_id_len, stompp->subs_id, msg_id_len, stompp->msg_id, sigbuf, 0); 598 HEXDUMP(" ack:", buf, buf+len, /*16*/ 256); 599 #ifdef USE_OPENSSL 600 if (bu->ssl) 601 SSL_write(bu->ssl, buf, len); 602 else 603 #endif 604 send_all_socket(bu->fd, buf, len); 605 return 1; 606 } 607 608 /*() NACK a message to STOMP 1.1 connection, signalling trouble persisting it. 609 * N.B. NACK is not a command. Thus no RECEIPT is expected from server 610 * end (NACK really is the receipt for MESSAGE sent by server). 611 * 612 * Returns:: zero on failure and 1 on success. */ 613 614 /* Called by: zxbus_listen_msg x2 */ 615 int zxbus_nack_msg(zxid_conf* cf, struct zxid_bus_url* bu, struct stomp_hdr* stompp, const char* errmsg) 616 { 617 int len; 618 char buf[1024]; 619 int subs_id_len, msg_id_len; 620 subs_id_len = strchr(stompp->subs_id, '\n') - stompp->subs_id; 621 msg_id_len = strchr(stompp->msg_id, '\n') - stompp->msg_id; 622 623 len = snprintf(buf, sizeof(buf), "NACK\nsubscription:%.*s\nmessage-id:%.*s\nmessage:%s\n\n%c", 624 subs_id_len, stompp->subs_id, msg_id_len, stompp->msg_id, errmsg, 0); 625 HEXDUMP("nack:", buf, buf+len, /*16*/ 256); 626 #ifdef USE_OPENSSL 627 if (bu->ssl) 628 SSL_write(bu->ssl, buf, len); 629 else 630 #endif 631 send_all_socket(bu->fd, buf, len); 632 return 1; 633 } 634 635 /*() Listen for a MESSAGE from the STOMP 1.1 connection and ACK it. 636 * Returns pointer to the body (which is nul terminated as the 637 * STOMP 1.1 frame ends in nul). Returns NULL on error. 638 * N.B. Depending on situation, you may NOT want automatic ACK. 639 * In that case you should call zxbus_read() and zxbus_ack_msg() 640 * directly and do your persistence in between. 641 * 642 * See also:: zxbus_persist() */ 643 644 /* Called by: zxbuslist_main */ 645 char* zxbus_listen_msg(zxid_conf* cf, struct zxid_bus_url* bu) 646 { 647 struct stomp_hdr stomp; 648 int dest_len; 649 char* dest; 650 char c_path[ZXID_MAX_BUF]; 651 if (zxbus_read_stomp(cf, bu, &stomp)) { 652 if (!memcmp(bu->m, "MESSAGE", sizeof("MESSAGE")-1)) { 653 if (zxbus_persist_flag) { 654 if (!(dest = stomp.dest)) { 655 ERR("SEND MUST specify destination header, i.e. channel to send to. %p", dest); 656 zxbus_nack_msg(cf, bu, &stomp, "no destination channel. server error."); 657 zxbus_shift_read_buf(cf, bu, &stomp); 658 return 0; 659 } 660 dest_len = (char*)memchr(dest, '\n', bu->ap - dest) - dest; /* there will be \n in STOMP header */ 661 DD("persist(%.*s)", dest_len, dest); 662 663 if (!zxbus_persist_msg(cf, sizeof(c_path), c_path, dest_len, dest, bu->ap - bu->m,bu->m)) { 664 zxbus_nack_msg(cf, bu, &stomp, "difficulty in persisting (temporary client/local err)"); 665 zxbus_shift_read_buf(cf, bu, &stomp); 666 return 0; 667 } 668 } 669 if (zxbus_verbose) { 670 if (zxbus_ascii_color>1) { 671 if (zxbus_verbose>1) { 672 fprintf(stdout, "\e[42m%.*s\e[0m\n", (int)(bu->ap - bu->m), bu->m); 673 } else { 674 fprintf(stdout, "\e[42m%.*s\e[0m\n", stomp.len, stomp.body); 675 } 676 } else { 677 if (zxbus_verbose>1) { 678 fprintf(stdout, "%.*s\n", (int)(bu->ap - bu->m), bu->m); 679 } else { 680 fprintf(stdout, "%.*s\n", stomp.len, stomp.body); 681 } 682 } 683 } 684 zxbus_ack_msg(cf, bu, &stomp); 685 zxbus_shift_read_buf(cf, bu, &stomp); 686 return stomp.body; /* normal successful return */ 687 } else { 688 ERR("Unknown command received(%.*s)", (int)(bu->ap - bu->m), bu->m); 689 zxbus_shift_read_buf(cf, bu, &stomp); 690 return 0; 691 } 692 } else { 693 ERR("Read from %s failed.", bu->s); 694 return 0; 695 } 696 } 697 698 #ifdef USE_OPENSSL 699 //int zxbus_cert_verify_cb(X509_STORE_CTX* st_ctx, void* arg) { zxid_conf* cf = arg; return 0; } 700 701 /* Called by: */ 702 static void zx_ssl_info_cb(const SSL *ssl, int where, int ret) 703 { 704 const char *str; 705 706 if ((where & ~SSL_ST_MASK) & SSL_ST_CONNECT) str="SSL_connect"; 707 else if ((where & ~SSL_ST_MASK) & SSL_ST_ACCEPT) str="SSL_accept"; 708 else str="undefined"; 709 710 if (where & SSL_CB_LOOP) { 711 D("%s:%s",str,SSL_state_string_long(ssl)); 712 } else if (where & SSL_CB_ALERT) { 713 str=(where & SSL_CB_READ)?"read":"write"; 714 D("SSL3 alert %s:%s:%s",str,SSL_alert_type_string_long(ret),SSL_alert_desc_string_long(ret)); 715 } else if (where & SSL_CB_EXIT) { 716 if (ret == 0) 717 D("%s:failed in %s",str,SSL_state_string_long(ssl)); 718 else if (ret < 0) 719 D("%s:error in %s",str,SSL_state_string_long(ssl)); 720 } 721 } 722 #endif 723 724 /*() Open a bus_url, i.e. STOMP 1.1 connection to zxbusd. 725 * 726 * return:: 0 on failure, 1 on success. */ 727 728 /* Called by: zxbus_send_cmd, zxbuslist_main */ 729 int zxbus_open_bus_url(zxid_conf* cf, struct zxid_bus_url* bu) 730 { 731 #ifdef USE_OPENSSL 732 X509* peer_cert; 733 zxid_entity* meta; 734 #endif 735 long vfy_err; 736 int len,tls; 737 char buf[1024]; 738 struct hostent* he; 739 struct sockaddr_in sin; 740 struct stomp_hdr stomp; 741 int host_len; 742 char* proto; 743 char* host; 744 char* port; 745 char* local; 746 char* qs; 747 char* eid; 748 char* p; 749 750 /* Parse the bus_url */ 751 752 if (!bu || !bu->s || !*bu->s) { 753 ERR("Null arguments or empty bus_url supplied %p", bu); 754 return 0; 755 } 756 757 host = strstr(bu->s, "://"); 758 if (!host) { 759 ERR("Malformed bus_url(%s): missing protocol field", bu->s); 760 proto = "stomps:"; 761 host = bu->s; 762 } else { 763 proto = bu->s; 764 host += 3; 765 } 766 767 if (!memcmp(proto, "stomps:", sizeof("stomps:")-1)) { 768 tls = 1; 769 } else if (!memcmp(proto, "stomp:", sizeof("stomp:")-1)) { 770 tls = 0; 771 } else { 772 ERR("Unknown protocol(%.*s)", 6, proto); 773 return 0; 774 } 775 776 port = strchr(host, ':'); 777 if (!port) { 778 port = tls ? ":2229/" : ":2228/"; /* ZXID default ports for stomps: and plain stomp: */ 779 local = strchr(host, '/'); 780 if (!local) { 781 qs = strchr(host, '?'); 782 if (!qs) { 783 host_len = strlen(host); 784 } else { 785 host_len = qs-host; 786 } 787 } else { 788 host_len = local-host; 789 qs = strchr(local, '?'); 790 } 791 } else { 792 host_len = port-host; 793 local = strchr(port, '/'); 794 if (!local) { 795 qs = strchr(port, '?'); 796 } else { 797 qs = strchr(local, '?'); 798 } 799 } 800 801 bu->m = bu->ap = ZX_ALLOC(cf->ctx, ZXBUS_BUF_SIZE); 802 803 memcpy(bu->m, host, MIN(host_len, ZXBUS_BUF_SIZE-2)); 804 bu->m[MIN(host_len, ZXBUS_BUF_SIZE-2)] = 0; 805 he = gethostbyname(bu->m); 806 if (!he) { 807 ERR("hostname(%s) did not resolve(%d) bu->s(%s) host_len=%d %d host(%.*s) %p port(%s) %p", bu->m, h_errno, bu->s, host_len, MIN(host_len, ZXBUS_BUF_SIZE-2), host_len, host, host, port, port); 808 exit(5); 809 } 810 811 memset(&sin, 0, sizeof(sin)); 812 sin.sin_family = AF_INET; 813 sin.sin_port = htons(atoi(port+1)); 814 memcpy(&(sin.sin_addr.s_addr), he->h_addr, sizeof(sin.sin_addr.s_addr)); 815 816 if ((bu->fd = (fdtype)socket(AF_INET, SOCK_STREAM, 0)) == (fdtype)-1) { 817 ERR("Unable to create socket(AF_INET, SOCK_STREAM, 0) %d %s", errno, STRERROR(errno)); 818 return 0; 819 } 820 821 #if 0 822 nonblock(bu->fd); 823 if (nkbuf) 824 setkernelbufsizes(bu->fd, nkbuf, nkbuf); 825 #endif 826 827 D("connecting(%x) hs(%s)", bu->fd, bu->s); 828 if ((connect((SOCKET)bu->fd, (struct sockaddr*)&sin, sizeof(sin)) == -1) && (errno != EINPROGRESS)) { 829 ERR("Connection to %s failed: %d %s", bu->s, errno, STRERROR(errno)); 830 goto errout; 831 } 832 833 D("connected(%x) at TCP layer hs(%s)", bu->fd, bu->s); 834 835 if (tls) { 836 #ifdef USE_OPENSSL 837 if (!cf->ssl_ctx) { 838 SSL_load_error_strings(); 839 SSL_library_init(); 840 #if 0 841 cf->ssl_ctx = SSL_CTX_new(SSLv23_method()); 842 #else 843 cf->ssl_ctx = SSL_CTX_new(TLSv1_client_method()); 844 #endif 845 } 846 if (!cf->ssl_ctx) { 847 ERR("TLS/SSL connection to(%s) can not be made. SSL context initialization problem", bu->s); 848 zx_report_openssl_err("open_bus_url-ssl_ctx"); 849 goto errout; 850 } else { 851 if (errmac_debug>1) { 852 D("OpenSSL header-version(%lx) lib-version(%lx)(%s) %s %s %s %s", OPENSSL_VERSION_NUMBER, SSLeay(), SSLeay_version(SSLEAY_VERSION), SSLeay_version(SSLEAY_CFLAGS), SSLeay_version(SSLEAY_BUILT_ON), SSLeay_version(SSLEAY_PLATFORM), SSLeay_version(SSLEAY_DIR)); 853 SSL_CTX_set_info_callback(cf->ssl_ctx, zx_ssl_info_cb); 854 } 855 SSL_CTX_set_mode(cf->ssl_ctx, SSL_MODE_AUTO_RETRY); /* R/W only return when complete. */ 856 /* Verification strategy: do not attempt verification at SSL layer. Instead 857 * check the result afterwards against metadata based cert. */ 858 SSL_CTX_set_verify(cf->ssl_ctx, SSL_VERIFY_NONE,0); 859 //SSL_CTX_set_verify(cf->ssl_ctx, SSL_VERIFY_PEER,0); 860 //SSL_CTX_set_cert_verify_callback(cf->ssl_ctx, zxbus_cert_verify_cb, cf); 861 /*SSL_CTX_load_verify_locations() SSL_CTX_set_client_CA_list(3) SSL_CTX_set_cert_store(3) */ 862 LOCK(cf->mx, "logenc wrln"); 863 if (!cf->enc_cert) 864 cf->enc_cert = zxid_read_cert(cf, "enc-nopw-cert.pem"); 865 if (!cf->enc_pkey) 866 cf->enc_pkey = zxid_read_private_key(cf, "enc-nopw-cert.pem"); 867 UNLOCK(cf->mx, "logenc wrln"); 868 if (!SSL_CTX_use_certificate(cf->ssl_ctx, cf->enc_cert)) { 869 ERR("TLS/SSL connection to(%s) can not be made. SSL certificate problem", bu->s); 870 zx_report_openssl_err("open_bus_url-cert"); 871 goto errout; 872 } 873 if (!SSL_CTX_use_PrivateKey(cf->ssl_ctx, cf->enc_pkey)) { 874 ERR("TLS/SSL connection to(%s) can not be made. SSL private key problem", bu->s); 875 zx_report_openssl_err("open_bus_url-privkey"); 876 goto errout; 877 } 878 if (!SSL_CTX_check_private_key(cf->ssl_ctx)) { 879 ERR("TLS/SSL connection to(%s) can not be made. SSL certificate-private key consistency problem", bu->s); 880 zx_report_openssl_err("open_bus_url-chk-privkey"); 881 goto errout; 882 } 883 /*SSL_CTX_add_extra_chain_cert(cf->ssl_ctx, ca_cert);*/ 884 } 885 bu->ssl = SSL_new(cf->ssl_ctx); 886 if (!bu->ssl) { 887 ERR("TLS/SSL connection to(%s) can not be made. SSL object initialization problem", bu->s); 888 zx_report_openssl_err("open_bus_url-ssl"); 889 goto errout; 890 } 891 if (!SSL_set_fd(bu->ssl, (int)bu->fd)) { 892 ERR("TLS/SSL connection to(%s) can not be made. SSL fd(%x) initialization problem", bu->s, bu->fd); 893 zx_report_openssl_err("open_bus_url-set_fd"); 894 goto sslerrout; 895 } 896 897 switch (vfy_err = SSL_get_error(bu->ssl, SSL_connect(bu->ssl))) { 898 case SSL_ERROR_NONE: break; 899 /*case SSL_ERROR_WANT_ACCEPT: documented, but undeclared */ 900 case SSL_ERROR_WANT_READ: 901 case SSL_ERROR_WANT_CONNECT: 902 case SSL_ERROR_WANT_WRITE: 903 default: 904 ERR("TLS/SSL connection to(%s) can not be made. SSL connect or handshake problem (%ld)", bu->s, vfy_err); 905 zx_report_openssl_err("open_bus_url-ssl_connect"); 906 send((SOCKET)bu->fd, SSL_ENCRYPTED_HINT, sizeof(SSL_ENCRYPTED_HINT)-1, 0); 907 goto sslerrout; 908 } 909 910 if (errmac_debug>1) D("SSL_version(%s) cipher(%s)",SSL_get_version(bu->ssl),SSL_get_cipher(bu->ssl)); 911 912 vfy_err = SSL_get_verify_result(bu->ssl); 913 switch (vfy_err) { 914 case X509_V_OK: break; 915 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: 916 D("TLS/SSL connection to(%s) made, but certificate err. (%ld)", bu->s, vfy_err); 917 zx_report_openssl_err("open_bus_url-verify_res"); 918 break; 919 default: 920 ERR("TLS/SSL connection to(%s) made, but certificate not acceptable. (%ld)", bu->s, vfy_err); 921 zx_report_openssl_err("open_bus_url-verify_res"); 922 goto sslerrout; 923 } 924 925 if (!(peer_cert = SSL_get_peer_certificate(bu->ssl))) { 926 ERR("TLS/SSL connection to(%s) made, but peer did not send certificate", bu->s); 927 zx_report_openssl_err("open_bus_url-peer_cert"); 928 goto sslerrout; 929 } 930 meta = zxid_get_ent(cf, bu->eid); 931 if (!meta) { 932 ERR("Unable to find metadata for eid(%s) in verify peer cert", bu->eid); 933 goto sslerrout; 934 } 935 if (!meta->enc_cert) { 936 ERR("Metadata for eid(%s) does not contain enc cert", bu->eid); 937 goto sslerrout; 938 } 939 if (X509_cmp(meta->enc_cert, peer_cert)) { 940 ERR("Peer certificate does not match metadata for eid(%s)", bu->eid); 941 D("compare: %d", memcmp(meta->enc_cert->sha1_hash, peer_cert->sha1_hash, SHA_DIGEST_LENGTH)); 942 PEM_write_X509(ERRMAC_DEBUG_LOG, peer_cert); 943 goto sslerrout; 944 } 945 /* *** should we free peer_cert? */ 946 /*SSL_get_verify_result(bu->ssl); no need as SSL_VERIFY_PEER causes SSL_connect() to fail. */ 947 #else 948 ERR("TLS/SSL connection to(%s) can not be made. SSL not compiled in", bu->s); 949 goto errout; 950 #endif 951 } 952 953 eid = zxid_my_ent_id_cstr(cf); 954 if (!eid) 955 return 0; 956 for (p = eid; *p; ++p) 957 if (*p == ':') /* deal with colon that is forbidden character in STOMP 1.1 header */ 958 *p = '|'; 959 960 if (cf->bus_pw) { 961 len = snprintf(buf, sizeof(buf)-1, "STOMP\naccept-version:1.1\nhost:%s\nlogin:%s\npasscode:%s\n\n%c", bu->m, eid, cf->bus_pw, 0); 962 } else { 963 len = snprintf(buf, sizeof(buf)-1, "STOMP\naccept-version:1.1\nhost:%s\nlogin:%s\n\n%c", bu->m, eid, 0); 964 } 965 HEXDUMP("conn:", buf, buf+len, /*16*/ 256); 966 #ifdef USE_OPENSSL 967 if (bu->ssl) 968 SSL_write(bu->ssl, buf, len); 969 else 970 #endif 971 send_all_socket(bu->fd, buf, len); 972 973 memset(&stomp, 0, sizeof(struct stomp_hdr)); 974 if (zxbus_read_stomp(cf, bu, &stomp)) { 975 if (!memcmp(bu->m, "CONNECTED", sizeof("CONNECTED")-1)) { 976 zxbus_shift_read_buf(cf, bu, &stomp); 977 D("STOMP got CONNECTED bu-s(%s)", bu->s); 978 return 1; 979 } 980 zxbus_shift_read_buf(cf, bu, &stomp); 981 } 982 ERR("Connection to %s failed. Other end did not send CONNECTED", bu->s); 983 #ifdef USE_OPENSSL 984 sslerrout: 985 if (bu->ssl) { 986 SSL_shutdown(bu->ssl); 987 SSL_free(bu->ssl); 988 bu->ssl = 0; 989 } 990 #endif 991 errout: 992 closesocket((SOCKET)bu->fd); 993 bu->fd = 0; 994 return 0; 995 } 996 997 /*() SEND a STOMP 1.1 DISCONNECT to audit bus and wait for RECEIPT. 998 * 999 * Returns:: zero on failure and 1 on success. Connection is closed in either case. */ 1000 1001 /* Called by: zxbus_close_all */ 1002 int zxbus_close(zxid_conf* cf, struct zxid_bus_url* bu) 1003 { 1004 int len; 1005 char buf[1024]; 1006 struct stomp_hdr stomp; 1007 1008 D("closing(%x) bu_%p", bu->fd, bu); 1009 1010 if (!bu || !bu->s || !bu->s[0] || !bu->fd) 1011 return 0; /* No bus_url configured means audit bus reporting is disabled. */ 1012 1013 /* *** implement intelligent lbfo algo */ 1014 1015 D("disconnecting(%p) bu->s(%s)", bu, bu->s); 1016 1017 len = snprintf(buf, sizeof(buf), "DISCONNECT\nreceipt:%d\n\n%c", bu->cur_rcpt-1, 0); 1018 send_all_socket(bu->fd, buf, len); 1019 1020 memset(&stomp, 0, sizeof(struct stomp_hdr)); 1021 if (zxbus_read_stomp(cf, bu, &stomp)) { 1022 if (!memcmp(bu->m, "RECEIPT", sizeof("RECEIPT")-1)) { 1023 if (atoi(stomp.rcpt_id) == bu->cur_rcpt - 1) { 1024 zxbus_shift_read_buf(cf, bu, &stomp); 1025 D("DISCONNECT got RECEIPT %d", bu->cur_rcpt-1); 1026 #ifdef USE_OPENSSL 1027 if (bu->ssl) { 1028 SSL_shutdown(bu->ssl); 1029 SSL_free(bu->ssl); 1030 bu->ssl = 0; 1031 } 1032 #endif 1033 closesocket((SOCKET)bu->fd); 1034 bu->fd = 0; 1035 return 1; 1036 } else { 1037 ERR("DISCONNECT to %s failed. RECEIPT number(%.*s)=%d mismatch cur_rcpt-1=%d", bu->s, (int)(bu->ap - stomp.rcpt_id), stomp.rcpt_id, atoi(stomp.rcpt_id), bu->cur_rcpt-1); 1038 zxbus_shift_read_buf(cf, bu, &stomp); 1039 goto errout; 1040 } 1041 } else { 1042 ERR("DISCONNECT to %s failed. Other end did not send RECEIPT(%.*s)", bu->s, (int)(bu->ap - bu->m), bu->m); 1043 zxbus_shift_read_buf(cf, bu, &stomp); 1044 } 1045 } else { 1046 ERR("DISCONNECT to %s failed. Other end did not send RECEIPT. Read error. Probably connection drop.", bu->s); 1047 } 1048 errout: 1049 #ifdef USE_OPENSSL 1050 if (bu->ssl) { 1051 SSL_shutdown(bu->ssl); 1052 SSL_free(bu->ssl); 1053 bu->ssl = 0; 1054 } 1055 #endif 1056 closesocket((SOCKET)bu->fd); 1057 bu->fd = 0; 1058 return 0; 1059 } 1060 1061 /*() SEND a STOMP 1.1 DISCONNECT to audit bus and wait for RECEIPT. 1062 * Returns:: nothing. Ignores any errors (but errors cause fd to be closed). */ 1063 1064 /* Called by: zxbuslist_main, zxbustailf_main */ 1065 void zxbus_close_all(zxid_conf* cf) 1066 { 1067 struct zxid_bus_url* bu; 1068 for (bu = cf->bus_url; bu; bu = bu->n) 1069 zxbus_close(cf, bu); 1070 } 1071 1072 /*() Log successful receipt (the message should have been logged earlier separately) 1073 * 1074 * cf:: zxid configuration object 1075 * bu:: URL and eid of the destination audit bus node 1076 * mid:: message ID 1077 * dest:: Destination channel where message was sent 1078 * sha1_buf:: The sha1 over the message as was used to log the message in issue directory 1079 * rcpt_len:: Length of the receipt data returned by remote 1080 * rcpt:: Receipt data returned by remote 1081 * 1082 * Log format is as follows 1083 * R1 YYYYMMDD-HHMMSS.sss URL SHA1-OF-EID MID CHANNEL SHA1-OF-MSG INST O K RCPT receipt_data 1084 * where receipt_data is like 1085 * AB1 https://buslist.zxid.org/?o=B ACK RP 20120923-170431.868 76 3aSMhrZHtsviQnl3jnb8swYuxe_5uRnegGP0_i-hgPD6pzNkLtJdC7_qA7Ry-Iz1_cSDR7L91Oe9qgQZ64CzqC1qb0l5sSVoHNVQAzUWXgXOuHvXEgkMheAoLAUT8SKM_H9cUlPCrgCkVFWPXcLAR2FHAW7sNrGe7Mcm4MFFXqM. 1086 */ 1087 1088 /* Called by: zxbus_send_cmdf */ 1089 static void zxbus_log_receipt(zxid_conf* cf, struct zxid_bus_url* bu, int mid_len, const char* mid, int dest_len, const char* dest, const char* sha1_buf, int rcpt_len, const char* rcpt) 1090 { 1091 int len; 1092 struct tm ot; 1093 struct timeval ourts; 1094 char sha1_name[28]; 1095 char buf[1024]; 1096 char c_path[ZXID_MAX_BUF]; 1097 1098 GETTIMEOFDAY(&ourts, 0); 1099 GMTIME_R(ourts.tv_sec, ot); 1100 sha1_safe_base64(sha1_name, -2, bu->eid); 1101 sha1_name[27] = 0; 1102 1103 if (!mid) 1104 mid_len = 0; 1105 if (mid_len == -1) 1106 mid_len = strlen(mid); 1107 else if (mid_len == -2) 1108 mid_len = strchr(mid, '\n') - mid; 1109 1110 if (!dest) 1111 dest_len = 0; 1112 if (dest_len == -1) 1113 dest_len = strlen(dest); 1114 else if (dest_len == -2) 1115 dest_len = strchr(dest, '\n') - dest; 1116 1117 len = snprintf(buf, sizeof(buf)-1, "R1 " ZXLOG_TIME_FMT " " 1118 " %s %s" /* url sha1_name-of-ent */ 1119 " %.*s %.*s %s" /* mid, sha1 of the message (see zxlog_blob() call), dest */ 1120 " %s %s %s %s" 1121 " %.*s\n", 1122 ZXLOG_TIME_ARG(ot, ourts.tv_usec), 1123 bu->s, sha1_name, 1124 mid_len, mid, dest_len, dest, sha1_buf, 1125 errmac_instance, "O", "K", "RCPT", 1126 rcpt_len, rcpt); 1127 buf[sizeof(buf)-1] = 0; /* must terminate manually as on win32 nul is not guaranteed */ 1128 if (len < 0) platform_broken_snprintf(len, __FUNCTION__, sizeof(buf)-1, "zxbus receipt frame"); 1129 name_from_path(c_path, sizeof(c_path), "%s" ZXID_LOG_DIR "rcpt", cf->cpath); 1130 write2_or_append_lock_c_path(c_path, len, buf, 0,0, "zxbus_send_cmdf",SEEK_END,O_APPEND); 1131 } 1132 1133 /*() Send the specified STOMP 1.1 message to audit bus and wait for RECEIPT. 1134 * Blocks until the transaction completes (or fails). Figures out 1135 * from configuration, which bus daemon to contact (looks at bus_urls). 1136 * The fmt must contain command, headers, and double newline that 1137 * separates the body. 1138 * Will also log the message to /var/zxid/buscli/issue/SUCCINCT/wir/SHA1 1139 * and receipt to /var/zxid/buscli/log/rcpt 1140 * 1141 * return:: zero on failure and 1 on success. */ 1142 1143 /* Called by: zxbus_send_cmd, zxbuslist_main */ 1144 int zxbus_send_cmdf(zxid_conf* cf, struct zxid_bus_url* bu, int body_len, const char* body, const char* fmt, ...) 1145 { 1146 va_list ap; 1147 int len, siglen, ver; 1148 char* eid; 1149 char* dest; 1150 char* rcpt; 1151 char buf[1024]; 1152 char sha1_buf[28]; 1153 struct zx_str sha1_ss; 1154 struct zx_str eid_ss; 1155 struct zx_str* logpath; 1156 struct stomp_hdr stomp; 1157 1158 if (body_len == -1 && body) 1159 body_len = strlen(body); 1160 1161 va_start(ap, fmt); 1162 len = vsnprintf(buf, sizeof(buf), fmt, ap); 1163 va_end(ap); 1164 1165 rcpt = strstr(buf, "\nreceipt:"); 1166 if (rcpt) 1167 rcpt += sizeof("\nreceipt:")-1; 1168 else 1169 rcpt = "\n"; 1170 1171 dest = strstr(buf, "\ndestination:"); 1172 if (dest) 1173 dest += sizeof("\ndestination:")-1; 1174 else 1175 dest = "\n"; 1176 1177 if (cf->log_issue_msg) { 1178 /* Path will be composed of sha1 hash of the data in buf. */ 1179 sha1_safe_base64(sha1_buf, len, buf); 1180 sha1_buf[27] = 0; 1181 sha1_ss.len = 27; 1182 sha1_ss.s = sha1_buf; 1183 eid_ss.len = strlen(bu->eid); 1184 eid_ss.s = bu->eid; 1185 logpath = zxlog_path(cf, &eid_ss, &sha1_ss, ZXLOG_ISSUE_DIR, ZXLOG_WIR_KIND, 1); 1186 if (logpath) { 1187 eid_ss.len = body_len; 1188 eid_ss.s = (char*)body; 1189 zxlog_blob(cf, cf->log_issue_msg, logpath, &eid_ss, "zxbus_send_cmdf"); 1190 zx_str_free(cf->ctx, logpath); 1191 } 1192 } 1193 1194 HEXDUMP(" buf:", buf, buf+len, /*16*/ 256); 1195 if (body) HEXDUMP("body:", body, body+body_len, /*16*/ 256); 1196 1197 #ifdef USE_OPENSSL 1198 if (bu->ssl) { 1199 SSL_write(bu->ssl, buf, len); 1200 if (body) 1201 SSL_write(bu->ssl, body, body_len); 1202 SSL_write(bu->ssl, "\0", 1); 1203 } else { 1204 send_all_socket(bu->fd, buf, len); 1205 if (body) 1206 send_all_socket(bu->fd, body, body_len); 1207 send_all_socket(bu->fd, "\0", 1); 1208 } 1209 #else 1210 send_all_socket(bu->fd, buf, len); 1211 if (body) 1212 send_all_socket(bu->fd, body, body_len); 1213 send_all_socket(bu->fd, "\0", 1); 1214 #endif 1215 1216 memset(&stomp, 0, sizeof(struct stomp_hdr)); 1217 if (zxbus_read_stomp(cf, bu, &stomp)) { 1218 if (!memcmp(bu->m, "RECEIPT", sizeof("RECEIPT")-1)) { 1219 if (atoi(stomp.rcpt_id) == bu->cur_rcpt - 1) { 1220 D("%.*s got RECEIPT %d", 4, buf, bu->cur_rcpt-1); 1221 1222 siglen = stomp.zx_rcpt_sig ? (strchr(stomp.zx_rcpt_sig, '\n') - stomp.zx_rcpt_sig) : 0; 1223 eid = zxid_my_ent_id_cstr(cf); 1224 ver = zxbus_verify_receipt(cf, bu->eid, 1225 siglen, siglen?stomp.zx_rcpt_sig:"", 1226 -2, rcpt, 1227 -2, dest, 1228 -1, eid, /* our eid, the receipt was issued to us */ 1229 body_len, body); 1230 ZX_FREE(cf->ctx, eid); 1231 if (ver != ZXSIG_OK) { 1232 ERR("RECEIPT signature validation failed: %d sig(%.*s) body(%.*s)", ver, siglen, siglen?stomp.zx_rcpt_sig:"", body_len, body); 1233 return 0; 1234 } 1235 1236 if (zxbus_verbose) { 1237 fprintf(stdout, "%.*s(%.*s) got RECEIPT %d\n", 4, buf, body?body_len:0, body?body:"", bu->cur_rcpt-1); 1238 } 1239 if (cf->log_rely_msg) { /* Log the receipt */ 1240 zxbus_log_receipt(cf, bu, -2, rcpt, -2, dest, sha1_buf, siglen, siglen?stomp.zx_rcpt_sig:""); 1241 } 1242 zxbus_shift_read_buf(cf, bu, &stomp); 1243 return 1; /* normal successful return */ 1244 } else { 1245 ERR("Send to %s failed. RECEIPT number(%.*s)=%d mismatch cur_rcpt-1=%d (%s)", bu->s, (int)(bu->ap - stomp.rcpt_id), stomp.rcpt_id, atoi(stomp.rcpt_id), bu->cur_rcpt-1, bu->m); 1246 zxbus_shift_read_buf(cf, bu, &stomp); 1247 goto errout; 1248 } 1249 } else { 1250 ERR("Send to %s failed. Other end did not send RECEIPT(%.*s)", bu->s, (int)(bu->ap - bu->m), bu->m); 1251 zxbus_shift_read_buf(cf, bu, &stomp); 1252 } 1253 } else { 1254 ERR("Send to %s failed. Other end did not send RECEIPT. Read error.", bu->s); 1255 } 1256 errout: 1257 #ifdef USE_OPENSSL 1258 if (bu->ssl) { 1259 SSL_shutdown(bu->ssl); 1260 SSL_free(bu->ssl); 1261 bu->ssl = 0; 1262 } 1263 #endif 1264 closesocket((SOCKET)bu->fd); 1265 bu->fd = 0; 1266 return 0; 1267 } 1268 1269 /*() Send the specified STOMP 1.1 message to audit bus and wait for RECEIPT. 1270 * Blocks until the transaction completes (or fails). Figures out 1271 * from configuration, which bus daemon to contact (looks at bus_urls). 1272 * 1273 * Returns:: zero on failure and 1 on success. */ 1274 1275 /* Called by: zxbus_send, zxbustailf_main */ 1276 int zxbus_send_cmd(zxid_conf* cf, const char* cmd, const char* dest, int n, const char* logbuf) 1277 { 1278 struct zxid_bus_url* bu; 1279 bu = cf->bus_url; 1280 if (!bu || !bu->s || !bu->s[0]) 1281 return 0; /* No bus_url configured means audit bus reporting is disabled. */ 1282 1283 /* *** implement intelligent lbfo algo */ 1284 1285 if (!bu->fd) 1286 zxbus_open_bus_url(cf, bu); 1287 if (!bu->fd) 1288 return 0; 1289 return zxbus_send_cmdf(cf, bu, n, logbuf, "%s\ndestination:%s\nreceipt:%d\ncontent-length:%d\n\n", cmd, dest, bu->cur_rcpt++, n); 1290 } 1291 1292 /*() SEND a STOMP 1.1 message to audit bus and wait for RECEIPT. 1293 * Blocks until the transaction completes (or fails). Figures out 1294 * from configuration, which bus daemon to contact (looks at bus_urls). 1295 * 1296 * Returns:: zero on failure and 1 on success. */ 1297 1298 /* Called by: zxbustailf_main x2 */ 1299 int zxbus_send(zxid_conf* cf, const char* dest, int n, const char* logbuf) 1300 { 1301 return zxbus_send_cmd(cf, "SEND", dest, n, logbuf); 1302 } 1303 1304 #if 0 1305 /*(i) Log to activity and/or error log depending on ~res~ and configuration settings. 1306 * This is the main audit logging function you should call. Please see <<link:../../html/zxid-log.html: zxid-log.pd>> 1307 * for detailed description of the log format and features. See <<link:../../html/zxid-conf.html: zxid-conf.pd>> for 1308 * configuration options governing the logging. (*** check the links) 1309 * 1310 * Proper audit trail is essential for any high value transactions based on SSO. Also 1311 * some SAML protocol Processing Rules, such as duplicate detection, depend on the 1312 * logging. 1313 * 1314 * cf (1):: ZXID configuration object, used for configuration options and memory allocation 1315 * ourts (2):: Timestamp as observed by localhost. Typically the wall clock 1316 * time. See gettimeofday(3) 1317 * srcts (3):: Timestamp claimed by the message to which the log entry pertains 1318 * ipport (4):: IP address and port number from which the message appears to have originated 1319 * entid (5):: Entity ID to which the message pertains, usually the issuer. Null ok. 1320 * msgid (6):: Message ID, can be used for correlation to establish audit trail continuity 1321 * from request to response. Null ok. 1322 * a7nid (7):: Assertion ID, if message contained assertion (outermost and first 1323 * assertion if there are multiple relevant assertions). Null ok. 1324 * nid (8):: Name ID pertaining to the message 1325 * sigval (9):: Signature validation letters 1326 * res (10):: Result letters 1327 * op (11):: Operation code for the message 1328 * arg (12):: Operation specific argument 1329 * fmt, ... :: Free format message conveying additional information 1330 * return:: 0 on success, nonzero on failure (often ignored as zxbus() is very 1331 * robust and rarely fails - and when it does, situation is so hopeless that 1332 * you would not be able to report its failure anyway) 1333 */ 1334 1335 /* Called by: zxid_an_page_cf, zxid_anoint_sso_a7n, zxid_anoint_sso_resp, zxid_chk_sig, zxid_decode_redir_or_post x2, zxid_fed_mgmt_cf, zxid_get_ent_by_sha1_name, zxid_get_ent_ss, zxid_get_meta x2, zxid_idp_dispatch, zxid_idp_select_zxstr_cf_cgi, zxid_idp_soap_dispatch x2, zxid_idp_soap_parse, zxid_parse_conf_raw, zxid_parse_meta, zxid_saml_ok x2, zxid_simple_render_ses, zxid_simple_ses_active_cf, zxid_sp_anon_finalize, zxid_sp_deref_art x5, zxid_sp_dig_sso_a7n x2, zxid_sp_dispatch, zxid_sp_meta, zxid_sp_mni_redir, zxid_sp_mni_soap, zxid_sp_slo_redir, zxid_sp_slo_soap, zxid_sp_soap_dispatch x2, zxid_sp_soap_parse, zxid_sp_sso_finalize x2, zxid_start_sso_url x3 */ 1336 int zxbus(zxid_conf* cf, /* 1 */ 1337 struct timeval* ourts, /* 2 null allowed, will use current time */ 1338 struct timeval* srcts, /* 3 null allowed, will use start of unix epoch + 501 usec */ 1339 const char* ipport, /* 4 null allowed, -:- or cf->ipport if not given */ 1340 struct zx_str* entid, /* 5 null allowed, - if not given */ 1341 struct zx_str* msgid, /* 6 null allowed, - if not given */ 1342 struct zx_str* a7nid, /* 7 null allowed, - if not given */ 1343 struct zx_str* nid, /* 8 null allowed, - if not given */ 1344 const char* sigval, /* 9 null allowed, - if not given */ 1345 const char* res, /* 10 */ 1346 const char* op, /* 11 */ 1347 const char* arg, /* 12 null allowed, - if not given */ 1348 const char* fmt, ...) /* 13 null allowed as format, ends the line w/o further ado */ 1349 { 1350 int n; 1351 char logbuf[1024]; 1352 va_list ap; 1353 1354 /* Avoid computation if logging is hopeless. */ 1355 1356 if (!((cf->log_err_in_act || res[0] == 'K') && cf->log_act) 1357 && !(cf->log_err && res[0] != 'K')) { 1358 return 0; 1359 } 1360 1361 va_start(ap, fmt); 1362 n = zxbus_fmt(cf, sizeof(logbuf), logbuf, 1363 ourts, srcts, ipport, entid, msgid, a7nid, nid, sigval, res, 1364 op, arg, fmt, ap); 1365 va_end(ap); 1366 return zxbus_output(cf, n, logbuf, res); 1367 } 1368 #endif 1369 1370 /* EOF -- zxbusprod.c */ 1371