static void uwsgi_crypto_logger_setup_encryption(struct uwsgi_crypto_logger_conf *uclc) { if (!uwsgi.ssl_initialized) { uwsgi_ssl_init(); } uclc->encrypt_ctx = uwsgi_malloc(sizeof(EVP_CIPHER_CTX)); EVP_CIPHER_CTX_init(uclc->encrypt_ctx); const EVP_CIPHER *cipher = EVP_get_cipherbyname(uclc->algo); if (!cipher) { uwsgi_log_safe("[uwsgi-logcrypto] unable to find algorithm/cipher\n"); exit(1); } int cipher_len = EVP_CIPHER_key_length(cipher); size_t s_len = strlen(uclc->secret); if ((unsigned int) cipher_len > s_len) { char *secret_tmp = uwsgi_malloc(cipher_len); memcpy(secret_tmp, uclc->secret, s_len); memset(secret_tmp + s_len, 0, cipher_len - s_len); uclc->secret = secret_tmp; } int iv_len = EVP_CIPHER_iv_length(cipher); size_t s_iv_len = 0; if (uclc->iv) { s_iv_len = strlen(uclc->iv); } if ((unsigned int) iv_len > s_iv_len) { char *secret_tmp = uwsgi_malloc(iv_len); memcpy(secret_tmp, uclc->iv, s_iv_len); memset(secret_tmp + s_iv_len, '0', iv_len - s_iv_len); uclc->iv = secret_tmp; } if (EVP_EncryptInit_ex(uclc->encrypt_ctx, cipher, NULL, (const unsigned char *) uclc->secret, (const unsigned char *) uclc->iv) <= 0) { uwsgi_error_safe("uwsgi_crypto_logger_setup_encryption()/EVP_EncryptInit_ex()"); exit(1); } }
ssize_t uwsgi_graylog2_logger(struct uwsgi_logger *ul, char *message, size_t len) { size_t i; if (!ul->configured) { if (!uwsgi.choosen_logger_arg) { uwsgi_log_safe("invalid graylog2 syntax\n"); exit(1); } ul->fd = socket(AF_INET, SOCK_DGRAM, 0); if (ul->fd < 0) { uwsgi_error_safe("socket()"); exit(1); } uwsgi_socket_nb(ul->fd); char *comma = strchr(uwsgi.choosen_logger_arg, ','); if (!comma) { uwsgi_log_safe("invalid graylog2 syntax\n"); exit(1); } g2c.host = comma + 1; *comma = 0; char *colon = strchr(uwsgi.choosen_logger_arg, ':'); if (!colon) { uwsgi_log_safe("invalid graylog2 syntax\n"); exit(1); } ul->addr_len = socket_to_in_addr(uwsgi.choosen_logger_arg, colon, 0, &ul->addr.sa_in); *comma = ','; ul->configured = 1; } g2c.escaped_len = 0; int truncated = 0; char *ptr = g2c.escaped_buf; uLongf destLen = MAX_GELF; for(i=0;i<len;i++) { if (message[i] == '\\') { *ptr ++= '\\'; g2c.escaped_len++; } else if (message[i] == '"') { *ptr ++= '\\'; g2c.escaped_len++; } *ptr ++= message[i]; g2c.escaped_len++; if (!truncated) { if (g2c.escaped_len == 128) { truncated = 1; } else if (g2c.escaped_len > 128) { truncated = 2; } } } if (truncated) truncated = 128 - (truncated-1); else (truncated = g2c.escaped_len); int rlen = snprintf(g2c.json_buf, MAX_GELF, "{ \"version\": \"1.0\", \"host\": \"%s\", \"short_message\": \"%.*s\", \"full_message\": \"%.*s\", \"timestamp\": %d, \"level\": 5, \"facility\": \"uWSGI-%s\" }", g2c.host, truncated, g2c.escaped_buf, (int)g2c.escaped_len, g2c.escaped_buf, (int) time(NULL), UWSGI_VERSION); if (rlen > 0) { if (compressBound((uLong) rlen) <= MAX_GELF) { if (compress((Bytef *) g2c.buffer, &destLen, (Bytef *) g2c.json_buf, (uLong) rlen) == Z_OK) { return sendto(ul->fd, g2c.buffer, destLen, 0, (const struct sockaddr *) &ul->addr, ul->addr_len); } } } return -1; }
static ssize_t uwsgi_crypto_logger(struct uwsgi_logger *ul, char *message, size_t len) { struct uwsgi_crypto_logger_conf *uclc = (struct uwsgi_crypto_logger_conf *) ul->data; if (!ul->configured) { uclc = uwsgi_calloc(sizeof(struct uwsgi_crypto_logger_conf)); if (uwsgi_kvlist_parse(ul->arg, strlen(ul->arg), ',', '=', "addr", &uclc->addr, "algo", &uclc->algo, "secret", &uclc->secret, "iv", &uclc->iv, "prefix", &uclc->prefix, NULL)) { uwsgi_log_safe("[uwsgi-logcrypto] unable to parse options\n"); exit(1); } if (!uclc->addr || !uclc->algo || !uclc->secret) { uwsgi_log_safe("[uwsgi-logcrypto] you have to specify at least addr,algo and secret options\n"); exit(1); } if (uclc->prefix) { uclc->prefix_len = strlen(uclc->prefix); } char *colon = strchr(uclc->addr, ':'); if (!colon) { uwsgi_log_safe("[uwsgi-logcrypto] invalid UDP address\n"); exit(1); } ul->addr_len = socket_to_in_addr(uclc->addr, colon, 0, &ul->addr.sa_in); ul->fd = socket(AF_INET, SOCK_DGRAM, 0); if (ul->fd < 0) { uwsgi_error_safe("uwsgi_crypto_logger()/socket()"); exit(1); } uwsgi_crypto_logger_setup_encryption(uclc); ul->data = uclc; ul->configured = 1; } struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); if (uwsgi_buffer_num64(ub, uwsgi_micros())) goto error; if (uwsgi_buffer_append(ub, " ", 1)) goto error; if (uclc->prefix) { if (uwsgi_buffer_append(ub, uclc->prefix, uclc->prefix_len)) goto error; if (uwsgi_buffer_append(ub, " ", 1)) goto error; } if (uwsgi_buffer_append(ub, message, len)) goto error; // let's encrypt the message unsigned char *encrypted = uwsgi_malloc(ub->pos + EVP_MAX_BLOCK_LENGTH); if (EVP_EncryptInit_ex(uclc->encrypt_ctx, NULL, NULL, NULL, NULL) <= 0) { uwsgi_error_safe("[uwsgi-logcrypto] EVP_EncryptInit_ex()"); free(encrypted); goto error; } int e_len = 0; if (EVP_EncryptUpdate(uclc->encrypt_ctx, encrypted, &e_len, (unsigned char *) ub->buf, ub->pos) <= 0) { uwsgi_error("[uwsgi-logcrypto] EVP_EncryptUpdate()"); free(encrypted); goto error; } int tmplen = 0; if (EVP_EncryptFinal_ex(uclc->encrypt_ctx, encrypted + e_len, &tmplen) <= 0) { uwsgi_error("[uwsgi-logcrypto] EVP_EncryptFinal_ex()"); free(encrypted); goto error; } uwsgi_buffer_destroy(ub); ssize_t rlen = sendto(ul->fd, encrypted, e_len + tmplen, 0, (struct sockaddr *) &ul->addr.sa_in, ul->addr_len); free(encrypted); return rlen; error: uwsgi_buffer_destroy(ub); return -1; }
ssize_t uwsgi_rsyslog_logger(struct uwsgi_logger *ul, char *message, size_t len) { char buf[MAX_SYSLOG_PKT]; char ctime_storage[26]; time_t current_time; int portn = 514; int rlen; if (!ul->configured) { if (!ul->arg) { uwsgi_log_safe("invalid rsyslog syntax\n"); exit(1); } ul->fd = socket(AF_INET, SOCK_DGRAM, 0); if (ul->fd < 0) { uwsgi_error_safe("socket()"); exit(1); } uwsgi_socket_nb(ul->fd); char *comma = strchr(ul->arg, ','); if (comma) { ul->data = comma+1; *comma = 0; } else { ul->data = uwsgi_concat2(uwsgi.hostname," uwsgi"); } char *port = strchr(ul->arg, ':'); if (port) { portn = atoi(port+1); *port = 0; } ul->addr_len = socket_to_in_addr(ul->arg, NULL, portn, &ul->addr.sa_in); if (port) *port = ':'; if (comma) *comma = ','; ul->configured = 1; } current_time = uwsgi_now(); // drop newline if (message[len-1] == '\n') len--; #ifdef __sun__ ctime_r(¤t_time, ctime_storage, 26); #else ctime_r(¤t_time, ctime_storage); #endif rlen = snprintf(buf, MAX_SYSLOG_PKT, "<29>%.*s %s: %.*s", 15, ctime_storage+4, (char *) ul->data, (int) len, message); if (rlen > 0) { return sendto(ul->fd, buf, rlen, 0, (const struct sockaddr *) &ul->addr, ul->addr_len); } return -1; }
// create the logpipe void create_logpipe(void) { #if defined(SOCK_SEQPACKET) && defined(__linux__) if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, uwsgi.shared->worker_log_pipe)) { #else if (socketpair(AF_UNIX, SOCK_DGRAM, 0, uwsgi.shared->worker_log_pipe)) { #endif uwsgi_error("socketpair()\n"); exit(1); } uwsgi_socket_nb(uwsgi.shared->worker_log_pipe[0]); uwsgi_socket_nb(uwsgi.shared->worker_log_pipe[1]); if (uwsgi.shared->worker_log_pipe[1] != 1) { if (dup2(uwsgi.shared->worker_log_pipe[1], 1) < 0) { uwsgi_error("dup2()"); exit(1); } } if (dup2(1, 2) < 0) { uwsgi_error("dup2()"); exit(1); } } #ifdef UWSGI_ZEROMQ // the zeromq logger ssize_t uwsgi_zeromq_logger(struct uwsgi_logger *ul, char *message, size_t len) { if (!ul->configured) { if (!ul->arg) { uwsgi_log_safe("invalid zeromq syntax\n"); exit(1); } void *ctx = uwsgi_zeromq_init(); ul->data = zmq_socket(ctx, ZMQ_PUSH); if (ul->data == NULL) { uwsgi_error_safe("zmq_socket()"); exit(1); } if (zmq_connect(ul->data, ul->arg) < 0) { uwsgi_error_safe("zmq_connect()"); exit(1); } ul->configured = 1; } zmq_msg_t msg; if (zmq_msg_init_size(&msg, len) == 0) { memcpy(zmq_msg_data(&msg), message, len); #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) zmq_sendmsg(ul->data, &msg, 0); #else zmq_send(ul->data, &msg, 0); #endif zmq_msg_close(&msg); } return 0; } #endif // log to the specified file or udp address void logto(char *logfile) { int fd; #ifdef UWSGI_UDP char *udp_port; struct sockaddr_in udp_addr; udp_port = strchr(logfile, ':'); if (udp_port) { udp_port[0] = 0; if (!udp_port[1] || !logfile[0]) { uwsgi_log("invalid udp address\n"); exit(1); } fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { uwsgi_error("socket()"); exit(1); } memset(&udp_addr, 0, sizeof(struct sockaddr_in)); udp_addr.sin_family = AF_INET; udp_addr.sin_port = htons(atoi(udp_port + 1)); char *resolved = uwsgi_resolve_ip(logfile); if (resolved) { udp_addr.sin_addr.s_addr = inet_addr(resolved); } else { udp_addr.sin_addr.s_addr = inet_addr(logfile); } if (connect(fd, (const struct sockaddr *) &udp_addr, sizeof(struct sockaddr_in)) < 0) { uwsgi_error("connect()"); exit(1); } } else { #endif if (uwsgi.log_truncate) { fd = open(logfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP); } else { fd = open(logfile, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP); } if (fd < 0) { uwsgi_error_open(logfile); exit(1); } uwsgi.logfile = logfile; if (uwsgi.chmod_logfile_value) { if (chmod(uwsgi.logfile, uwsgi.chmod_logfile_value)) { uwsgi_error("chmod()"); } } #ifdef UWSGI_UDP } #endif /* stdout */ if (fd != 1) { if (dup2(fd, 1) < 0) { uwsgi_error("dup2()"); exit(1); } close(fd); } /* stderr */ if (dup2(1, 2) < 0) { uwsgi_error("dup2()"); exit(1); } }