/* * 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 * * Version: $Revision: 466585 $ * ***************************************************************************/ #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; }