| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /*************************************************************************** |
| * Description: Next generation bi-directional protocol handler. * |
| * Author: Henri Gomez <hgomez@apache.org> * |
| * Version: $Revision$ * |
| ***************************************************************************/ |
| |
| |
| #include "jk_global.h" |
| #include "jk_util.h" |
| #include "jk_map.h" |
| #include "jk_ajp_common.h" |
| #include "jk_ajp14.h" |
| #include "jk_md5.h" |
| |
| /* |
| * Compute the MD5 with ENTROPY / SECRET KEY |
| */ |
| |
| void ajp14_compute_md5(jk_login_service_t *s, jk_logger_t *l) |
| { |
| JK_TRACE_ENTER(l); |
| jk_md5((const unsigned char *)s->entropy, |
| (const unsigned char *)s->secret_key, s->computed_key); |
| |
| if (JK_IS_DEBUG_LEVEL(l)) |
| jk_log(l, JK_LOG_DEBUG, "(%s/%s) -> (%s)", |
| s->entropy, s->secret_key, s->computed_key); |
| JK_TRACE_EXIT(l); |
| } |
| |
| |
| /* |
| * Build the Login Init Command |
| * |
| * +-------------------------+---------------------------+---------------------------+ |
| * | LOGIN INIT CMD (1 byte) | NEGOCIATION DATA (32bits) | WEB SERVER INFO (CString) | |
| * +-------------------------+---------------------------+---------------------------+ |
| * |
| */ |
| |
| int ajp14_marshal_login_init_into_msgb(jk_msg_buf_t *msg, |
| jk_login_service_t *s, jk_logger_t *l) |
| { |
| JK_TRACE_ENTER(l); |
| /* To be on the safe side */ |
| jk_b_reset(msg); |
| |
| /* |
| * LOGIN |
| */ |
| if (jk_b_append_byte(msg, AJP14_LOGINIT_CMD)) { |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| /* |
| * NEGOCIATION FLAGS |
| */ |
| if (jk_b_append_long(msg, s->negociation)) { |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| /* |
| * WEB-SERVER NAME |
| */ |
| if (jk_b_append_string(msg, s->web_server_name)) { |
| jk_log(l, JK_LOG_ERROR, |
| "failed appending the web_server_name string"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| JK_TRACE_EXIT(l); |
| return JK_TRUE; |
| } |
| |
| |
| /* |
| * Decode the Login Seed Command |
| * |
| * +-------------------------+---------------------------+ |
| * | LOGIN SEED CMD (1 byte) | MD5 of entropy (32 chars) | |
| * +-------------------------+---------------------------+ |
| * |
| */ |
| |
| int ajp14_unmarshal_login_seed(jk_msg_buf_t *msg, |
| jk_login_service_t *s, jk_logger_t *l) |
| { |
| JK_TRACE_ENTER(l); |
| |
| if (jk_b_get_bytes |
| (msg, (unsigned char *)s->entropy, AJP14_ENTROPY_SEED_LEN) < 0) { |
| jk_log(l, JK_LOG_ERROR, |
| "can't get seed"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| s->entropy[AJP14_ENTROPY_SEED_LEN] = 0; /* Just to have a CString */ |
| JK_TRACE_EXIT(l); |
| return JK_TRUE; |
| } |
| |
| /* |
| * Build the Login Computed Command |
| * |
| * +-------------------------+---------------------------------------+ |
| * | LOGIN COMP CMD (1 byte) | MD5 of RANDOM + SECRET KEY (32 chars) | |
| * +-------------------------+---------------------------------------+ |
| * |
| */ |
| |
| int ajp14_marshal_login_comp_into_msgb(jk_msg_buf_t *msg, |
| jk_login_service_t *s, jk_logger_t *l) |
| { |
| JK_TRACE_ENTER(l); |
| |
| /* To be on the safe side */ |
| jk_b_reset(msg); |
| |
| /* |
| * LOGIN |
| */ |
| if (jk_b_append_byte(msg, AJP14_LOGCOMP_CMD)) { |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| /* |
| * COMPUTED-SEED |
| */ |
| if (jk_b_append_bytes |
| (msg, (const unsigned char *)s->computed_key, |
| AJP14_COMPUTED_KEY_LEN)) { |
| jk_log(l, JK_LOG_ERROR, |
| "failed appending the COMPUTED MD5 bytes"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| JK_TRACE_EXIT(l); |
| return JK_TRUE; |
| } |
| |
| |
| /* |
| * Decode the LogOk Command |
| * |
| * +--------------------+------------------------+-------------------------------+ |
| * | LOGOK CMD (1 byte) | NEGOCIED DATA (32bits) | SERVLET ENGINE INFO (CString) | |
| * +--------------------+------------------------+-------------------------------+ |
| * |
| */ |
| |
| int ajp14_unmarshal_log_ok(jk_msg_buf_t *msg, |
| jk_login_service_t *s, jk_logger_t *l) |
| { |
| unsigned long nego; |
| char *sname; |
| |
| JK_TRACE_ENTER(l); |
| |
| nego = jk_b_get_long(msg); |
| |
| if (nego == 0xFFFFFFFF) { |
| jk_log(l, JK_LOG_ERROR, |
| "can't get negociated data"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| sname = (char *)jk_b_get_string(msg); |
| |
| if (!sname) { |
| jk_log(l, JK_LOG_ERROR, |
| "can't get servlet engine name"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| if (s->servlet_engine_name) /* take care of removing previously allocated data */ |
| free(s->servlet_engine_name); |
| |
| s->servlet_engine_name = strdup(sname); |
| |
| if (!s->servlet_engine_name) { |
| jk_log(l, JK_LOG_ERROR, |
| "can't malloc servlet engine name"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| JK_TRACE_EXIT(l); |
| return JK_TRUE; |
| } |
| |
| |
| /* |
| * Decode the Log Nok Command |
| * |
| * +---------------------+-----------------------+ |
| * | LOGNOK CMD (1 byte) | FAILURE CODE (32bits) | |
| * +---------------------+-----------------------+ |
| * |
| */ |
| |
| int ajp14_unmarshal_log_nok(jk_msg_buf_t *msg, jk_logger_t *l) |
| { |
| unsigned long status; |
| |
| JK_TRACE_ENTER(l); |
| |
| status = jk_b_get_long(msg); |
| |
| if (status == 0xFFFFFFFF) { |
| jk_log(l, JK_LOG_ERROR, |
| "can't get failure code"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| jk_log(l, JK_LOG_INFO, "Can't Log with servlet engine - code %08lx", |
| status); |
| JK_TRACE_EXIT(l); |
| return JK_TRUE; |
| } |
| |
| |
| /* |
| * Build the Shutdown Cmd |
| * |
| * +-----------------------+---------------------------------------+ |
| * | SHUTDOWN CMD (1 byte) | MD5 of RANDOM + SECRET KEY (32 chars) | |
| * +-----------------------+---------------------------------------+ |
| * |
| */ |
| |
| int ajp14_marshal_shutdown_into_msgb(jk_msg_buf_t *msg, |
| jk_login_service_t *s, jk_logger_t *l) |
| { |
| |
| JK_TRACE_ENTER(l); |
| |
| /* To be on the safe side */ |
| jk_b_reset(msg); |
| |
| /* |
| * SHUTDOWN CMD |
| */ |
| if (jk_b_append_byte(msg, AJP14_SHUTDOWN_CMD)) { |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| /* |
| * COMPUTED-SEED |
| */ |
| if (jk_b_append_bytes |
| (msg, (const unsigned char *)s->computed_key, |
| AJP14_COMPUTED_KEY_LEN)) { |
| jk_log(l, JK_LOG_ERROR, |
| "failed appending the COMPUTED MD5 bytes"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| JK_TRACE_EXIT(l); |
| return JK_TRUE; |
| } |
| |
| /* |
| * Decode the Shutdown Nok Command |
| * |
| * +----------------------+-----------------------+ |
| * | SHUTNOK CMD (1 byte) | FAILURE CODE (32bits) | |
| * +----------------------+-----------------------+ |
| * |
| */ |
| int ajp14_unmarshal_shutdown_nok(jk_msg_buf_t *msg, jk_logger_t *l) |
| { |
| unsigned long status; |
| |
| JK_TRACE_ENTER(l); |
| status = jk_b_get_long(msg); |
| |
| if (status == 0xFFFFFFFF) { |
| jk_log(l, JK_LOG_ERROR, |
| "can't get failure code"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| jk_log(l, JK_LOG_INFO, "Can't shutdown servlet engine - code %08lx", |
| status); |
| JK_TRACE_EXIT(l); |
| return JK_TRUE; |
| } |
| |
| /* |
| * Build the Unknown Packet |
| * |
| * +-----------------------------+---------------------------------+------------------------------+ |
| * | UNKNOWN PACKET CMD (1 byte) | UNHANDLED MESSAGE SIZE (16bits) | UNHANDLED MESSAGE (bytes...) | |
| * +-----------------------------+---------------------------------+------------------------------+ |
| * |
| */ |
| |
| int ajp14_marshal_unknown_packet_into_msgb(jk_msg_buf_t *msg, |
| jk_msg_buf_t *unk, jk_logger_t *l) |
| { |
| JK_TRACE_ENTER(l); |
| |
| /* To be on the safe side */ |
| jk_b_reset(msg); |
| |
| /* |
| * UNKNOWN PACKET CMD |
| */ |
| if (jk_b_append_byte(msg, AJP14_UNKNOW_PACKET_CMD)) { |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| /* |
| * UNHANDLED MESSAGE SIZE |
| */ |
| if (jk_b_append_int(msg, (unsigned short)unk->len)) { |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| /* |
| * UNHANDLED MESSAGE (Question : Did we have to send all the message or only part of) |
| * ( ie: only 1k max ) |
| */ |
| if (jk_b_append_bytes(msg, unk->buf, unk->len)) { |
| jk_log(l, JK_LOG_ERROR, |
| "failed appending the UNHANDLED MESSAGE"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| JK_TRACE_EXIT(l); |
| return JK_TRUE; |
| } |
| |
| /* |
| * Build the Context Query Cmd (autoconf) |
| * |
| * +--------------------------+---------------------------------+ |
| * | CONTEXT QRY CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | |
| * +--------------------------+---------------------------------+ |
| * |
| */ |
| |
| int ajp14_marshal_context_query_into_msgb(jk_msg_buf_t *msg, |
| char *virtual, jk_logger_t *l) |
| { |
| JK_TRACE_ENTER(l); |
| |
| /* To be on the safe side */ |
| jk_b_reset(msg); |
| |
| /* |
| * CONTEXT QUERY CMD |
| */ |
| if (jk_b_append_byte(msg, AJP14_CONTEXT_QRY_CMD)) { |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| /* |
| * VIRTUAL HOST CSTRING |
| */ |
| if (jk_b_append_string(msg, virtual)) { |
| jk_log(l, JK_LOG_ERROR, |
| "failed appending the virtual host string"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| JK_TRACE_EXIT(l); |
| return JK_TRUE; |
| } |
| |
| |
| /* |
| * Decode the Context Info Cmd (Autoconf) |
| * |
| * The Autoconf feature of AJP14, let us know which URL/URI could |
| * be handled by the servlet-engine |
| * |
| * +---------------------------+---------------------------------+----------------------------+-------------------------------+-----------+ |
| * | CONTEXT INFO CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | CONTEXT NAME (CString (*)) | URL1 [\n] URL2 [\n] URL3 [\n] | NEXT CTX. | |
| * +---------------------------+---------------------------------+----------------------------+-------------------------------+-----------+ |
| */ |
| |
| int ajp14_unmarshal_context_info(jk_msg_buf_t *msg, |
| jk_context_t *c, jk_logger_t *l) |
| { |
| char *vname; |
| char *cname; |
| char *uri; |
| |
| vname = (char *)jk_b_get_string(msg); |
| |
| JK_TRACE_ENTER(l); |
| jk_log(l, JK_LOG_DEBUG, |
| "get virtual %s for virtual %s", |
| vname, c->virt); |
| |
| if (!vname) { |
| jk_log(l, JK_LOG_ERROR, |
| "can't get virtual hostname"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| /* Check if we get the correct virtual host */ |
| if (c->virt != NULL && vname != NULL && strcmp(c->virt, vname)) { |
| /* set the virtual name, better to add to a virtual list ? */ |
| |
| if (context_set_virtual(c, vname) == JK_FALSE) { |
| jk_log(l, JK_LOG_ERROR, |
| "can't malloc virtual hostname"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| } |
| |
| for (;;) { |
| |
| cname = (char *)jk_b_get_string(msg); |
| |
| if (!cname) { |
| jk_log(l, JK_LOG_ERROR, |
| "can't get context"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| jk_log(l, JK_LOG_DEBUG, |
| "get context %s for virtual %s", |
| cname, vname); |
| |
| /* grab all contexts up to empty one which indicate end of contexts */ |
| if (!strlen(cname)) |
| break; |
| |
| /* create new context base (if needed) */ |
| |
| if (context_add_base(c, cname) == JK_FALSE) { |
| jk_log(l, JK_LOG_ERROR, |
| "can't add/set context %s", |
| cname); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| for (;;) { |
| |
| uri = (char *)jk_b_get_string(msg); |
| |
| if (!uri) { |
| jk_log(l, JK_LOG_ERROR, |
| "can't get URI"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| if (!strlen(uri)) { |
| jk_log(l, JK_LOG_DEBUG, "No more URI for context %s", cname); |
| break; |
| } |
| |
| jk_log(l, JK_LOG_INFO, |
| "Got URI (%s) for virtualhost %s and context %s", uri, |
| vname, cname); |
| |
| if (context_add_uri(c, cname, uri) == JK_FALSE) { |
| jk_log(l, JK_LOG_ERROR, |
| "can't add/set uri (%s) for context %s", |
| uri, cname); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| } |
| } |
| |
| JK_TRACE_EXIT(l); |
| return JK_TRUE; |
| } |
| |
| |
| /* |
| * Build the Context State Query Cmd |
| * |
| * We send the list of contexts where we want to know state, empty string end context list* |
| * If cname is set, only ask about THIS context |
| * |
| * +----------------------------+----------------------------------+----------------------------+----+ |
| * | CONTEXT STATE CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | CONTEXT NAME (CString (*)) | .. | |
| * +----------------------------+----------------------------------+----------------------------+----+ |
| * |
| */ |
| |
| int ajp14_marshal_context_state_into_msgb(jk_msg_buf_t *msg, |
| jk_context_t *c, |
| char *cname, jk_logger_t *l) |
| { |
| jk_context_item_t *ci; |
| int i; |
| |
| JK_TRACE_ENTER(l); |
| |
| /* To be on the safe side */ |
| jk_b_reset(msg); |
| |
| /* |
| * CONTEXT STATE CMD |
| */ |
| if (jk_b_append_byte(msg, AJP14_CONTEXT_STATE_CMD)) { |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| /* |
| * VIRTUAL HOST CSTRING |
| */ |
| if (jk_b_append_string(msg, c->virt)) { |
| jk_log(l, JK_LOG_ERROR, |
| "failed appending the virtual host string"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| if (cname) { |
| |
| ci = context_find_base(c, cname); |
| |
| if (!ci) { |
| jk_log(l, JK_LOG_ERROR, |
| "unknown context %s", |
| cname); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| /* |
| * CONTEXT CSTRING |
| */ |
| |
| if (jk_b_append_string(msg, cname)) { |
| jk_log(l, JK_LOG_ERROR, |
| "failed appending the context string %s", |
| cname); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| } |
| else { /* Grab all contexts name */ |
| |
| for (i = 0; i < c->size; i++) { |
| |
| /* |
| * CONTEXT CSTRING |
| */ |
| if (jk_b_append_string(msg, c->contexts[i]->cbase)) { |
| jk_log(l, JK_LOG_ERROR, |
| "failed appending the context string %s", |
| c->contexts[i]->cbase); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| } |
| } |
| |
| /* End of context list, an empty string */ |
| |
| if (jk_b_append_string(msg, "")) { |
| jk_log(l, JK_LOG_ERROR, |
| "failed appending end of contexts"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| JK_TRACE_EXIT(l); |
| return JK_TRUE; |
| } |
| |
| |
| /* |
| * Decode the Context State Reply Cmd |
| * |
| * We get update of contexts list, empty string end context list* |
| * |
| * +----------------------------------+---------------------------------+----------------------------+------------------+----+ |
| * | CONTEXT STATE REPLY CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | CONTEXT NAME (CString (*)) | UP/DOWN (1 byte) | .. | |
| * +----------------------------------+---------------------------------+----------------------------+------------------+----+ |
| * |
| */ |
| |
| int ajp14_unmarshal_context_state_reply(jk_msg_buf_t *msg, |
| jk_context_t *c, jk_logger_t *l) |
| { |
| char *vname; |
| char *cname; |
| jk_context_item_t *ci; |
| |
| JK_TRACE_ENTER(l); |
| /* get virtual name */ |
| vname = (char *)jk_b_get_string(msg); |
| |
| if (!vname) { |
| jk_log(l, JK_LOG_ERROR, |
| "can't get virtual hostname"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| /* Check if we speak about the correct virtual */ |
| if (strcmp(c->virt, vname)) { |
| jk_log(l, JK_LOG_ERROR, |
| "incorrect virtual %s instead of %s", |
| vname, c->virt); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| for (;;) { |
| |
| /* get context name */ |
| cname = (char *)jk_b_get_string(msg); |
| |
| if (!cname) { |
| jk_log(l, JK_LOG_ERROR, |
| "can't get context"); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| if (!strlen(cname)) |
| break; |
| |
| ci = context_find_base(c, cname); |
| |
| if (!ci) { |
| jk_log(l, JK_LOG_ERROR, |
| "unknow context %s for virtual %s", |
| cname, vname); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| ci->status = jk_b_get_int(msg); |
| |
| if (JK_IS_DEBUG_LEVEL(l)) |
| jk_log(l, JK_LOG_DEBUG, |
| "updated context %s to state %d", |
| cname, ci->status); |
| } |
| |
| JK_TRACE_EXIT(l); |
| return JK_TRUE; |
| } |
| |
| /* |
| * Decode the Context Update Cmd |
| * |
| * +-----------------------------+---------------------------------+----------------------------+------------------+ |
| * | CONTEXT UPDATE CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | CONTEXT NAME (CString (*)) | UP/DOWN (1 byte) | |
| * +-----------------------------+---------------------------------+----------------------------+------------------+ |
| * |
| */ |
| |
| int ajp14_unmarshal_context_update_cmd(jk_msg_buf_t *msg, |
| jk_context_t *c, jk_logger_t *l) |
| { |
| int rc; |
| JK_TRACE_ENTER(l); |
| rc = ajp14_unmarshal_context_state_reply(msg, c, l); |
| JK_TRACE_EXIT(l); |
| return rc; |
| } |