static ret_t digest_HA2 (cherokee_validator_t *validator, cherokee_buffer_t *buf, cherokee_connection_t *conn) { ret_t ret; const char *method; cuint_t method_len; /* Sanity check */ if (cherokee_buffer_is_empty (&validator->uri)) return ret_deny; ret = cherokee_http_method_to_string (conn->header.method, &method, &method_len); if (unlikely (ret != ret_ok)) return ret; cherokee_buffer_ensure_size (buf, method_len + 1 + validator->uri.len); cherokee_buffer_add (buf, method, method_len); cherokee_buffer_add_str (buf, ":"); cherokee_buffer_add_buffer (buf, &validator->uri); cherokee_buffer_encode_md5_digest (buf); return ret_ok; }
ret_t cherokee_handler_proxy_conn_new (cherokee_handler_proxy_conn_t **pconn) { CHEROKEE_NEW_STRUCT (n, handler_proxy_conn); /* Socket stuff */ cherokee_socket_init (&n->socket); n->post.sent = 0; n->post.do_buf_sent = true; cherokee_buffer_init (&n->post.buf_temp); cherokee_buffer_init (&n->header_in_raw); cherokee_buffer_ensure_size (&n->header_in_raw, 512); n->poll_ref = NULL; n->keepalive_in = false; n->size_in = 0; n->sent_out = 0; n->enc = pconn_enc_none; *pconn = n; return ret_ok; }
ret_t cherokee_buffer_add_fsize (cherokee_buffer_t *buf, CST_OFFSET size) { ret_t ret; int remain; const char ord[] = "KMGTPE"; const char *o = ord; ret = cherokee_buffer_ensure_size (buf, buf->len + 8); if (unlikely (ret != ret_ok)) return ret; if (size < 973) return cherokee_buffer_add_ulong10 (buf, (culong_t)size); do { remain = (int)(size & 1023); size >>= 10; if (size >= 973) { ++o; continue; } if (size < 9 || (size == 9 && remain < 973)) { if ((remain = ((remain * 5) + 256) / 512) >= 10) ++size, remain = 0; return cherokee_buffer_add_va_fixed (buf, "%d.%d%c", (int) size, remain, *o); } if (remain >= 512) ++size; return cherokee_buffer_add_va_fixed (buf, "%3d%c", (int) size, *o); } while (1); return ret_ok; }
ret_t cherokee_logger_writer_new (cherokee_logger_writer_t **writer) { CHEROKEE_NEW_STRUCT(n,logger_writer); INIT_LIST_HEAD (&n->listed); n->type = cherokee_logger_writer_syslog; n->fd = -1; n->max_bufsize = DEFAULT_LOGGER_MAX_BUFSIZE; cherokee_buffer_init (&n->command); cherokee_buffer_init (&n->filename); cherokee_buffer_init (&n->buffer); cherokee_buffer_ensure_size (&n->buffer, n->max_bufsize); n->priv = malloc (sizeof(priv_t)); if (n->priv == NULL) { cherokee_buffer_mrproper (&n->buffer); free(n); return ret_nomem; } CHEROKEE_MUTEX_INIT (&PRIV(n)->mutex, NULL); n->initialized = false; *writer = n; return ret_ok; }
ret_t cherokee_handler_zeromq_new (cherokee_handler_t **hdl, void *cnt, cherokee_module_props_t *props) { CHEROKEE_NEW_STRUCT (n, handler_zeromq); /* Init the base class object */ cherokee_handler_init_base (HANDLER(n), cnt, HANDLER_PROPS(props), PLUGIN_INFO_HANDLER_PTR(zeromq)); MODULE(n)->init = (handler_func_init_t) cherokee_handler_zeromq_init; MODULE(n)->free = (module_func_free_t) zeromq_free; HANDLER(n)->read_post = (handler_func_read_post_t) cherokee_handler_zeromq_read_post; HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_zeromq_add_headers; HANDLER(n)->step = (handler_func_step_t) cherokee_handler_zeromq_step; /* Supported features */ HANDLER(n)->support = hsupport_nothing; cherokee_buffer_init (&n->output); cherokee_buffer_ensure_size (&n->output, 2097152); n->encoder = NULL; *hdl = HANDLER(n); return ret_ok; }
/* WARNING: all parameters MUST be valid, * NULL pointers lead to a crash. */ ret_t cherokee_socket_bufread (cherokee_socket_t *socket, cherokee_buffer_t *buf, size_t count, size_t *pcnt_read) { ret_t ret; char *starting; /* Read */ ret = cherokee_buffer_ensure_size (buf, buf->len + count + 2); if (unlikely(ret < ret_ok)) return ret; starting = buf->buf + buf->len; ret = cherokee_socket_read (socket, starting, count, pcnt_read); if (*pcnt_read > 0) { buf->len += *pcnt_read; buf->buf[buf->len] = '\0'; } TRACE (ENTRIES",bufread", "read fd=%d count=%d ret=%d read=%d\n", socket->socket, count, ret, *pcnt_read); return ret; }
/* * Ensure there is enough (addlen) free space left in the buffer. */ ret_t cherokee_buffer_ensure_addlen (cherokee_buffer_t *buf, size_t addlen) { if (buf->len + addlen < buf->size) return ret_ok; return cherokee_buffer_ensure_size (buf, ((size_t)buf->len + addlen + 1)); }
static ret_t escape_string (cherokee_buffer_t *buffer, const char *s, cuint_t len, cherokee_dwriter_lang_t lang) { char c; cuint_t i, j; cherokee_buffer_ensure_size (buffer, len*2); for (i=0,j=0; i<len; i++) { c = s[i]; switch (c) { case '\n': buffer->buf[j++] = '\\'; buffer->buf[j++] = 'n'; break; case '\r': buffer->buf[j++] = '\\'; buffer->buf[j++] = 'r'; break; case '\t': buffer->buf[j++] = '\\'; buffer->buf[j++] = 't'; break; case '\b': buffer->buf[j++] = '\\'; buffer->buf[j++] = 'b'; break; case '\f': buffer->buf[j++] = '\\'; buffer->buf[j++] = 'f'; break; case '\\': buffer->buf[j++] = '\\'; buffer->buf[j++] = '\\'; break; case '/': if (lang == dwriter_json) buffer->buf[j++] = '\\'; buffer->buf[j++] = '/'; break; case '"': buffer->buf[j++] = '\\'; buffer->buf[j++] = '"'; break; default: buffer->buf[j++] = c; } } buffer->buf[j] = '\0'; buffer->len = j; return ret_ok; }
ret_t cherokee_validator_digest_response (cherokee_validator_t *validator, char *A1, cherokee_buffer_t *buf, cherokee_connection_t *conn) { ret_t ret; cherokee_buffer_t a2 = CHEROKEE_BUF_INIT; /* A1 has to be in string of length 32: * MD5_digest(user":"******":"passwd) */ /* Sanity checks */ if (A1 == NULL) return ret_deny; if (cherokee_buffer_is_empty (&validator->nonce)) return ret_deny; /* Build A2 */ ret = digest_HA2 (validator, &a2, conn); if (ret != ret_ok) goto error; /* Build the final string */ cherokee_buffer_ensure_size (buf, 32 + a2.len + validator->nonce.len + 4); cherokee_buffer_add (buf, A1, 32); cherokee_buffer_add_str (buf, ":"); cherokee_buffer_add_buffer (buf, &validator->nonce); cherokee_buffer_add_str (buf, ":"); if (!cherokee_buffer_is_empty (&validator->qop)) { if (!cherokee_buffer_is_empty (&validator->nc)) cherokee_buffer_add_buffer (buf, &validator->nc); cherokee_buffer_add_str (buf, ":"); if (!cherokee_buffer_is_empty (&validator->cnonce)) cherokee_buffer_add_buffer (buf, &validator->cnonce); cherokee_buffer_add_str (buf, ":"); cherokee_buffer_add_buffer (buf, &validator->qop); cherokee_buffer_add_str (buf, ":"); } cherokee_buffer_add_buffer (buf, &a2); cherokee_buffer_encode_md5_digest (buf); cherokee_buffer_mrproper (&a2); return ret_ok; error: cherokee_buffer_mrproper (&a2); return ret; }
ret_t cherokee_buffer_read_file (cherokee_buffer_t *buf, char *filename) { int r, f; ret_t ret; struct stat info; /* Stat() the file */ r = cherokee_stat (filename, &info); if (r != 0) return ret_error; /* Is a regular file? */ if (S_ISREG(info.st_mode) == 0) return ret_error; /* Maybe get memory */ ret = cherokee_buffer_ensure_size (buf, buf->len + info.st_size + 1); if (unlikely (ret != ret_ok)) return ret; /* Open the file */ f = cherokee_open (filename, O_RDONLY | O_BINARY, 0); if (f < 0) { LOG_ERRNO(errno, cherokee_err_error, CHEROKEE_ERROR_BUFFER_OPEN_FILE, filename); return ret_error; } cherokee_fd_set_closexec (f); /* Read the content */ r = read (f, buf->buf + buf->len, info.st_size); if (r < 0) { buf->buf[buf->len] = '\0'; cherokee_fd_close(f); return ret_error; } /* Close it and exit */ cherokee_fd_close(f); buf->len += r; buf->buf[buf->len] = '\0'; return ret_ok; }
ret_t cherokee_logger_ncsa_init_base (cherokee_logger_ncsa_t *logger, cherokee_virtual_server_t *vsrv, cherokee_config_node_t *config) { ret_t ret; cherokee_config_node_t *subconf; static int callback_init = 0; /* Init the local buffers */ cherokee_buffer_init (&logger->now_dtm); cherokee_buffer_init (&logger->referer); cherokee_buffer_init (&logger->useragent); cherokee_buffer_ensure_size (&logger->now_dtm, 64); cherokee_buffer_ensure_size (&logger->referer, 1024); cherokee_buffer_ensure_size (&logger->useragent, 512); /* Init the logger writer */ ret = cherokee_config_node_get (config, "access", &subconf); if (ret != ret_ok) { LOG_CRITICAL (CHEROKEE_ERROR_LOGGER_NO_KEY, "access"); return ret_error; } ret = cherokee_server_get_log_writer (VSERVER_SRV(vsrv), subconf, &logger->writer_access); if (ret != ret_ok) { return ret_error; } /* Callback init */ if (callback_init == 0) { cherokee_buffer_init (&now); cherokee_bogotime_add_callback (bogotime_callback, logger, 1); } return ret_ok; }
ret_t cherokee_buffer_multiply (cherokee_buffer_t *buf, int num) { int i, initial_size; initial_size = buf->len; cherokee_buffer_ensure_size (buf, buf->len * num + 1); for (i=0; i<num; i++) { cherokee_buffer_add (buf, buf->buf, initial_size); } return ret_ok; }
static int openssl_sni_servername_cb (SSL *ssl, int *ad, void *arg) { ret_t ret; int re; const char *servername; cherokee_connection_t *conn; cherokee_buffer_t tmp; cherokee_server_t *srv = SRV(arg); cherokee_virtual_server_t *vsrv = NULL; UNUSED(ad); /* Get the pointer to the socket */ conn = SSL_get_app_data (ssl); if (unlikely (conn == NULL)) { LOG_ERROR (CHEROKEE_ERROR_SSL_SOCKET, ssl); return SSL_TLSEXT_ERR_ALERT_FATAL; } cherokee_buffer_init(&tmp); cherokee_buffer_ensure_size(&tmp, 40); /* Read the SNI server name */ servername = SSL_get_servername (ssl, TLSEXT_NAMETYPE_host_name); if (servername == NULL) { /* Set the server name to the IP address if we couldn't get the host name via SNI */ cherokee_socket_ntop (&conn->socket, tmp.buf, tmp.size); TRACE (ENTRIES, "No SNI: Did not provide a server name, using IP='%s' as servername.\n", tmp.buf); } else { cherokee_buffer_add (&tmp, servername, strlen(servername)); TRACE (ENTRIES, "SNI: Switching to servername='%s'\n", servername); } /* Look up and change the vserver */ ret = cherokee_cryptor_libssl_find_vserver(ssl, srv, &tmp, conn); if (ret != ret_ok) { re = SSL_TLSEXT_ERR_NOACK; } else { re = SSL_TLSEXT_ERR_OK; } cherokee_buffer_mrproper (&tmp); return re; }
ret_t cherokee_validator_digest_check (cherokee_validator_t *validator, cherokee_buffer_t *passwd, cherokee_connection_t *conn) { ret_t ret; int re = -1; cherokee_buffer_t a1 = CHEROKEE_BUF_INIT; cherokee_buffer_t buf = CHEROKEE_BUF_INIT; /* Sanity check */ if (cherokee_buffer_is_empty (&validator->user) || cherokee_buffer_is_empty (&validator->realm)) return ret_deny; /* Build A1 */ cherokee_buffer_ensure_size (&a1, validator->user.len + 1 + validator->realm.len + 1 + passwd->len); cherokee_buffer_add_buffer (&a1, &validator->user); cherokee_buffer_add_str (&a1, ":"); cherokee_buffer_add_buffer (&a1, &validator->realm); cherokee_buffer_add_str (&a1, ":"); cherokee_buffer_add_buffer (&a1, passwd); cherokee_buffer_encode_md5_digest (&a1); /* Build a possible response */ ret = cherokee_validator_digest_response (validator, a1.buf, &buf, conn); if (unlikely(ret != ret_ok)) goto go_out; /* Compare and return */ re = cherokee_buffer_cmp_buf (&conn->validator->response, &buf); go_out: cherokee_buffer_mrproper (&a1); cherokee_buffer_mrproper (&buf); return (re == 0) ? ret_ok : ret_deny; }
ret_t cherokee_buffer_add_va_list (cherokee_buffer_t *buf, const char *format, va_list args) { int len; int estimation; int size; ret_t ret; va_list args2; va_copy (args2, args); /* Estimate resulting formatted string length. */ estimation = cherokee_estimate_va_length (format, args); if (unlikely (estimation) < 0) { LOG_ERROR (CHEROKEE_ERROR_BUFFER_NEG_ESTIMATION, format, estimation); return ret_error; } /* Ensure enough size for buffer. */ ret = cherokee_buffer_ensure_size (buf, buf->len + estimation + 2); if (unlikely (ret != ret_ok)) { return ret; } /* Format the string into the buffer. * NOTE: len does NOT include '\0', size includes '\0' (len + 1) */ size = buf->size - buf->len; if (unlikely (size < 1)) { LOG_ERROR (CHEROKEE_ERROR_BUFFER_NO_SPACE, format, size, estimation); return ret_error; } len = vsnprintf (buf->buf + buf->len, size, format, args2); #if 0 if (unlikely (estimation < len)) { LOG_ERROR (CHEROKEE_ERROR_BUFFER_BAD_ESTIMATION, format, buf->buf + buf->len, estimation, len, size); } #endif if (unlikely (len < 0)) return ret_error; /* At this point buf-size is always greater than buf-len, thus size > 0. */ if (len >= size) { LOG_ERROR (CHEROKEE_ERROR_BUFFER_AVAIL_SIZE, estimation, len, size, format); cherokee_buffer_ensure_size (buf, buf->len + len + 2); size = buf->size - buf->len; len = vsnprintf (buf->buf + buf->len, size, format, args2); if (unlikely (len < 0)) return ret_error; if (unlikely (len >= size)) return ret_error; } buf->len += len; return ret_ok; }
ret_t cherokee_request_header_build_string (cherokee_request_header_t *request, cherokee_buffer_t *buf, cherokee_buffer_t *tmp1, cherokee_buffer_t *tmp2) { ret_t ret; const char *ptr; cuint_t len; cherokee_url_t *url = REQUEST_URL(request); /* 200 bytes should be enough for a small header */ cherokee_buffer_ensure_size (buf, 200); /* Add main request line: * GET /dir/object HTTP/1.1 */ ret = cherokee_http_method_to_string (request->method, &ptr, &len); if (ret != ret_ok) return ret; ret = cherokee_buffer_add (buf, ptr, len); if (ret != ret_ok) return ret; cherokee_buffer_add_str (buf, " "); /* Check if the requests goes through a proxy */ if (request->proxy) { cherokee_buffer_add_str (buf, "http://"); cherokee_buffer_add_buffer (buf, URL_HOST(url)); } cherokee_buffer_add_buffer (buf, URL_REQUEST(url)); switch (REQUEST_VERSION(request)) { case http_version_11: cherokee_buffer_add_str (buf, " HTTP/1.1" CRLF); break; case http_version_10: cherokee_buffer_add_str (buf, " HTTP/1.0" CRLF); break; default: SHOULDNT_HAPPEN; return ret_error; } /* Add "Host:" header - in HTTP/1.1 */ if (REQUEST_VERSION(request) == http_version_11) { cherokee_buffer_add_str (buf, "Host: "); cherokee_buffer_add_buffer (buf, URL_HOST(url)); cherokee_buffer_add_str (buf, CRLF); } /* Post information */ if (request->post_len != 0) { /* "Content-Length: " FMT_OFFSET CRLF, request->post_len; */ cherokee_buffer_add_str (buf, "Content-Length: "); cherokee_buffer_add_ullong10 (buf, (cullong_t) request->post_len); cherokee_buffer_add_str (buf, CRLF); } /* Add "Connection:" header */ if (REQUEST_KEEPALIVE(request)) { cherokee_buffer_add_str (buf, "Connection: Keep-Alive"CRLF); } else { cherokee_buffer_add_str (buf, "Connection: close"CRLF); } /* Authentication */ if (! cherokee_buffer_is_empty (&request->user) || ! cherokee_buffer_is_empty (&request->password)) { cherokee_buffer_clean (tmp1); cherokee_buffer_clean (tmp2); cherokee_buffer_add_buffer (tmp1, &request->user); cherokee_buffer_add_char (tmp1, ':'); cherokee_buffer_add_buffer (tmp1, &request->password); cherokee_buffer_encode_base64 (tmp1, tmp2); cherokee_buffer_add_str (buf, "Authorization: Basic "); cherokee_buffer_add_buffer (buf, tmp2); cherokee_buffer_add_str (buf, CRLF); } /* Extra headers */ if (! cherokee_buffer_is_empty (&request->extra_headers)) { cherokee_buffer_add_buffer (buf, &request->extra_headers); } /* Finish the header */ cherokee_buffer_add_str (buf, CRLF); return ret_ok; }
ret_t cherokee_spawner_spawn (cherokee_buffer_t *binary, cherokee_buffer_t *user, uid_t uid, gid_t gid, int env_inherited, char **envp, cherokee_logger_writer_t *error_writer, pid_t *pid_ret) { #ifdef HAVE_SYSV_SEMAPHORES char **n; int *pid_shm; int pid_prev; int k; int phase; int envs = 0; cherokee_buffer_t tmp = CHEROKEE_BUF_INIT; #define ALIGN4(buf) \ while (buf.len & 0x3) { \ cherokee_buffer_add_char (&buf, '\0'); \ } /* Check it's initialized */ if ((! _active) || (cherokee_spawn_shared.mem == NULL)) { TRACE (ENTRIES, "Spawner is not active. Returning: %s\n", binary->buf); return ret_deny; } /* Lock the monitor mutex */ k = CHEROKEE_MUTEX_TRY_LOCK (&spawning_mutex); if (k) { return ret_eagain; } /* Build the string * The first character of each block is a mark. */ cherokee_buffer_ensure_size (&tmp, SPAWN_SHARED_LEN); /* 1.- Executable */ phase = 0xF0; cherokee_buffer_add (&tmp, (char *)&phase, sizeof(int)); cherokee_buffer_add (&tmp, (char *)&binary->len, sizeof(int)); cherokee_buffer_add_buffer (&tmp, binary); cherokee_buffer_add_char (&tmp, '\0'); ALIGN4 (tmp); /* 2.- UID & GID */ phase = 0xF1; cherokee_buffer_add (&tmp, (char *)&phase, sizeof(int)); cherokee_buffer_add (&tmp, (char *)&user->len, sizeof(int)); cherokee_buffer_add_buffer (&tmp, user); cherokee_buffer_add_char (&tmp, '\0'); ALIGN4(tmp); cherokee_buffer_add (&tmp, (char *)&uid, sizeof(uid_t)); cherokee_buffer_add (&tmp, (char *)&gid, sizeof(gid_t)); /* 3.- Environment */ phase = 0xF2; cherokee_buffer_add (&tmp, (char *)&phase, sizeof(int)); for (n=envp; *n; n++) { envs ++; } cherokee_buffer_add (&tmp, (char *)&env_inherited, sizeof(int)); cherokee_buffer_add (&tmp, (char *)&envs, sizeof(int)); for (n=envp; *n; n++) { int len = strlen(*n); cherokee_buffer_add (&tmp, (char *)&len, sizeof(int)); cherokee_buffer_add (&tmp, *n, len); cherokee_buffer_add_char (&tmp, '\0'); ALIGN4(tmp); } /* 4.- Error log */ phase = 0xF3; cherokee_buffer_add (&tmp, (char *)&phase, sizeof(int)); write_logger (&tmp, error_writer); ALIGN4 (tmp); /* 5.- PID (will be rewritten by the other side) */ phase = 0xF4; cherokee_buffer_add (&tmp, (char *)&phase, sizeof(int)); pid_shm = (int *) (((char *)cherokee_spawn_shared.mem) + tmp.len); k = *pid_ret; pid_prev = *pid_ret; cherokee_buffer_add (&tmp, (char *)&k, sizeof(int)); /* Copy it to the shared memory */ if (unlikely (tmp.len > SPAWN_SHARED_LEN)) { goto error; } memcpy (cherokee_spawn_shared.mem, tmp.buf, tmp.len); cherokee_buffer_mrproper (&tmp); /* Wake up the spawning thread */ sem_unlock (cherokee_spawn_sem, SEM_LAUNCH_START); /* Wait for the PID */ sem_adquire (cherokee_spawn_sem, SEM_LAUNCH_READY); if (*pid_shm == -1) { TRACE(ENTRIES, "Could not get the PID of: '%s'\n", binary->buf); goto error; } if (*pid_shm == pid_prev) { TRACE(ENTRIES, "Could not the new PID, previously it was %d\n", pid_prev); goto error; } TRACE(ENTRIES, "Successfully launched PID=%d\n", *pid_shm); *pid_ret = *pid_shm; CHEROKEE_MUTEX_UNLOCK (&spawning_mutex); return ret_ok; error: CHEROKEE_MUTEX_UNLOCK (&spawning_mutex); return ret_error; #else return ret_not_found; #endif /* HAVE_SYSV_SEMAPHORES */ }
ret_t cherokee_logger_writer_configure (cherokee_logger_writer_t *writer, cherokee_config_node_t *config) { ret_t ret; cherokee_buffer_t *tmp = NULL; /* Check the type */ ret = config_read_type (config, &writer->type); if (ret != ret_ok) { return ret; } /* Extra properties */ switch (writer->type) { case cherokee_logger_writer_file: ret = cherokee_config_node_read (config, "filename", &tmp); if (ret != ret_ok) { LOG_ERROR (CHEROKEE_ERROR_LOGGER_WRITER_READ, "file"); return ret_error; } cherokee_buffer_add_buffer (&writer->filename, tmp); break; case cherokee_logger_writer_pipe: ret = cherokee_config_node_read (config, "command", &tmp); if (ret != ret_ok) { LOG_ERROR (CHEROKEE_ERROR_LOGGER_WRITER_READ, "exec"); return ret_error; } cherokee_buffer_add_buffer (&writer->command, tmp); break; default: break; } /* Reside the internal buffer if needed */ ret = cherokee_config_node_read (config, "bufsize", &tmp); if (ret == ret_ok) { int buf_len; ret = cherokee_atoi (tmp->buf, &buf_len); if (ret != ret_ok) { return ret_error; } if (buf_len < LOGGER_MIN_BUFSIZE) buf_len = LOGGER_MIN_BUFSIZE; else if (buf_len > LOGGER_MAX_BUFSIZE) buf_len = LOGGER_MAX_BUFSIZE; cherokee_buffer_mrproper (&writer->buffer); cherokee_buffer_init (&writer->buffer); ret = cherokee_buffer_ensure_size (&writer->buffer, buf_len); if (ret != ret_ok) { LOG_ERROR (CHEROKEE_ERROR_LOGGER_WRITER_ALLOC, writer->max_bufsize); return ret_nomem; } writer->max_bufsize = (size_t)buf_len; } return ret_ok; }