1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "ajp.h"
18
19APLOG_USE_MODULE(proxy_ajp);
20
21#define AJP_MSG_DUMP_BYTES_PER_LINE 16
22/* 2 hex digits plus space plus one char per dumped byte */
23/* plus prefix plus separator plus '\0' */
24#define AJP_MSG_DUMP_PREFIX_LENGTH  strlen("XXXX    ")
25#define AJP_MSG_DUMP_LINE_LENGTH    ((AJP_MSG_DUMP_BYTES_PER_LINE * \
26                                    strlen("XX .")) + \
27                                    AJP_MSG_DUMP_PREFIX_LENGTH + \
28                                    strlen(" - ") + 1)
29
30static char *hex_table = "0123456789ABCDEF";
31
32/**
33 * Dump the given number of bytes on an AJP Message
34 *
35 * @param pool      pool to allocate from
36 * @param msg       AJP Message to dump
37 * @param err       error string to display
38 * @param count     the number of bytes to dump
39 * @param buf       buffer pointer for dump message
40 * @return          APR_SUCCESS or error
41 */
42apr_status_t ajp_msg_dump(apr_pool_t *pool, ajp_msg_t *msg, char *err,
43                          apr_size_t count, char **buf)
44{
45    apr_size_t  i, j;
46    char        *current;
47    apr_size_t  bl, rl;
48    apr_byte_t  x;
49    apr_size_t  len = msg->len;
50    apr_size_t  line_len;
51
52    /* Display only first "count" bytes */
53    if (len > count)
54        len = count;
55         /* First the space needed for the first line */
56    bl = strlen(err) + 3 * (strlen(" XXX=") + 20) + 1 +
57         /* Now for the data lines */
58         (len + 15) / 16 * AJP_MSG_DUMP_LINE_LENGTH;
59    *buf = apr_palloc(pool, bl);
60    if (!*buf)
61        return APR_ENOMEM;
62    apr_snprintf(*buf, bl,
63                 "%s pos=%" APR_SIZE_T_FMT
64                 " len=%" APR_SIZE_T_FMT " max=%" APR_SIZE_T_FMT "\n",
65                 err, msg->pos, msg->len, msg->max_size);
66    current = *buf + strlen(*buf);
67    for (i = 0; i < len; i += AJP_MSG_DUMP_BYTES_PER_LINE) {
68        /* Safety check: do we have enough buffer for another line? */
69        rl = bl - (current - *buf);
70        if (AJP_MSG_DUMP_LINE_LENGTH > rl) {
71            *(current - 1) = '\0';
72            return APR_ENOMEM;
73        }
74        apr_snprintf(current, rl, "%.4lx    ", (unsigned long)i);
75        current += AJP_MSG_DUMP_PREFIX_LENGTH;
76        line_len = len - i;
77        if (line_len > AJP_MSG_DUMP_BYTES_PER_LINE) {
78            line_len = AJP_MSG_DUMP_BYTES_PER_LINE;
79        }
80        for (j = 0; j < line_len; j++) {
81             x = msg->buf[i + j];
82
83            *current++ = hex_table[x >> 4];
84            *current++ = hex_table[x & 0x0f];
85            *current++ = ' ';
86        }
87        *current++ = ' ';
88        *current++ = '-';
89        *current++ = ' ';
90        for (j = 0; j < line_len; j++) {
91            x = msg->buf[i + j];
92
93            if (x > 0x20 && x < 0x7F) {
94                *current++ = x;
95            }
96            else {
97                *current++ = '.';
98            }
99        }
100        *current++ = '\n';
101    }
102    *(current - 1) = '\0';
103
104    return APR_SUCCESS;
105}
106
107/**
108 * Log an AJP message
109 *
110 * @param request   The current request
111 * @param msg       AJP Message to dump
112 * @param err       error string to display
113 * @return          APR_SUCCESS or error
114 */
115apr_status_t ajp_msg_log(request_rec *r, ajp_msg_t *msg, char *err)
116{
117    int level;
118    apr_size_t count;
119    char *buf, *next;
120    apr_status_t rc = APR_SUCCESS;
121
122    if (APLOGrtrace7(r)) {
123        level = APLOG_TRACE7;
124        count = 1024;
125        if (APLOGrtrace8(r)) {
126            level = APLOG_TRACE8;
127            count = AJP_MAX_BUFFER_SZ;
128        }
129        rc = ajp_msg_dump(r->pool, msg, err, count, &buf);
130        if (rc == APR_SUCCESS) {
131            while ((next = ap_strchr(buf, '\n'))) {
132                *next = '\0';
133                ap_log_rerror(APLOG_MARK, level, 0, r, "%s", buf);
134                buf = next + 1;
135            }
136            ap_log_rerror(APLOG_MARK, level, 0, r, "%s", buf);
137        }
138    }
139    return rc;
140}
141
142/**
143 * Check a new AJP Message by looking at signature and return its size
144 *
145 * @param msg       AJP Message to check
146 * @param len       Pointer to returned len
147 * @return          APR_SUCCESS or error
148 */
149apr_status_t ajp_msg_check_header(ajp_msg_t *msg, apr_size_t *len)
150{
151    apr_byte_t *head = msg->buf;
152    apr_size_t msglen;
153
154    if (!((head[0] == 0x41 && head[1] == 0x42) ||
155          (head[0] == 0x12 && head[1] == 0x34))) {
156
157        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(01080)
158                      "ajp_msg_check_header() got bad signature %02x%02x",
159                      head[0], head[1]);
160
161        return AJP_EBAD_SIGNATURE;
162    }
163
164    msglen  = ((head[2] & 0xff) << 8);
165    msglen += (head[3] & 0xFF);
166
167    if (msglen > msg->max_size) {
168        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(01081)
169                     "ajp_msg_check_header() incoming message is "
170                     "too big %" APR_SIZE_T_FMT ", max is %" APR_SIZE_T_FMT,
171                     msglen, msg->max_size);
172        return AJP_ETOBIG;
173    }
174
175    msg->len = msglen + AJP_HEADER_LEN;
176    msg->pos = AJP_HEADER_LEN;
177    *len     = msglen;
178
179    return APR_SUCCESS;
180}
181
182/**
183 * Reset an AJP Message
184 *
185 * @param msg       AJP Message to reset
186 * @return          APR_SUCCESS or error
187 */
188apr_status_t ajp_msg_reset(ajp_msg_t *msg)
189{
190    msg->len = AJP_HEADER_LEN;
191    msg->pos = AJP_HEADER_LEN;
192
193    return APR_SUCCESS;
194}
195
196/**
197 * Reuse an AJP Message
198 *
199 * @param msg       AJP Message to reuse
200 * @return          APR_SUCCESS or error
201 */
202apr_status_t ajp_msg_reuse(ajp_msg_t *msg)
203{
204    apr_byte_t *buf;
205    apr_size_t max_size;
206
207    buf = msg->buf;
208    max_size = msg->max_size;
209    memset(msg, 0, sizeof(ajp_msg_t));
210    msg->buf = buf;
211    msg->max_size = max_size;
212    msg->header_len = AJP_HEADER_LEN;
213    ajp_msg_reset(msg);
214    return APR_SUCCESS;
215}
216
217/**
218 * Mark the end of an AJP Message
219 *
220 * @param msg       AJP Message to end
221 * @return          APR_SUCCESS or error
222 */
223apr_status_t ajp_msg_end(ajp_msg_t *msg)
224{
225    apr_size_t len = msg->len - AJP_HEADER_LEN;
226
227    if (msg->server_side) {
228        msg->buf[0] = 0x41;
229        msg->buf[1] = 0x42;
230    }
231    else {
232        msg->buf[0] = 0x12;
233        msg->buf[1] = 0x34;
234    }
235
236    msg->buf[2] = (apr_byte_t)((len >> 8) & 0xFF);
237    msg->buf[3] = (apr_byte_t)(len & 0xFF);
238
239    return APR_SUCCESS;
240}
241
242static APR_INLINE int ajp_log_overflow(ajp_msg_t *msg, const char *context)
243{
244    ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
245                 "%s(): BufferOverflowException %" APR_SIZE_T_FMT
246                 " %" APR_SIZE_T_FMT,
247                 context, msg->pos, msg->len);
248    return AJP_EOVERFLOW;
249}
250
251/**
252 * Add an unsigned 32bits value to AJP Message
253 *
254 * @param msg       AJP Message to get value from
255 * @param value     value to add to AJP Message
256 * @return          APR_SUCCESS or error
257 */
258apr_status_t ajp_msg_append_uint32(ajp_msg_t *msg, apr_uint32_t value)
259{
260    apr_size_t len = msg->len;
261
262    if ((len + 4) > msg->max_size) {
263        return ajp_log_overflow(msg, "ajp_msg_append_uint32");
264    }
265
266    msg->buf[len]     = (apr_byte_t)((value >> 24) & 0xFF);
267    msg->buf[len + 1] = (apr_byte_t)((value >> 16) & 0xFF);
268    msg->buf[len + 2] = (apr_byte_t)((value >> 8) & 0xFF);
269    msg->buf[len + 3] = (apr_byte_t)(value & 0xFF);
270
271    msg->len += 4;
272
273    return APR_SUCCESS;
274}
275
276/**
277 * Add an unsigned 16bits value to AJP Message
278 *
279 * @param msg       AJP Message to get value from
280 * @param value     value to add to AJP Message
281 * @return          APR_SUCCESS or error
282 */
283apr_status_t ajp_msg_append_uint16(ajp_msg_t *msg, apr_uint16_t value)
284{
285    apr_size_t len = msg->len;
286
287    if ((len + 2) > msg->max_size) {
288        return ajp_log_overflow(msg, "ajp_msg_append_uint16");
289    }
290
291    msg->buf[len]     = (apr_byte_t)((value >> 8) & 0xFF);
292    msg->buf[len + 1] = (apr_byte_t)(value & 0xFF);
293
294    msg->len += 2;
295
296    return APR_SUCCESS;
297}
298
299/**
300 * Add an unsigned 8bits value to AJP Message
301 *
302 * @param msg       AJP Message to get value from
303 * @param value     value to add to AJP Message
304 * @return          APR_SUCCESS or error
305 */
306apr_status_t ajp_msg_append_uint8(ajp_msg_t *msg, apr_byte_t value)
307{
308    apr_size_t len = msg->len;
309
310    if ((len + 1) > msg->max_size) {
311        return ajp_log_overflow(msg, "ajp_msg_append_uint8");
312    }
313
314    msg->buf[len] = value;
315    msg->len += 1;
316
317    return APR_SUCCESS;
318}
319
320/**
321 *  Add a String in AJP message, and transform the String in ASCII
322 *  if convert is set and we're on an EBCDIC machine
323 *
324 * @param msg       AJP Message to get value from
325 * @param value     Pointer to String
326 * @param convert   When set told to convert String to ASCII
327 * @return          APR_SUCCESS or error
328 */
329apr_status_t ajp_msg_append_string_ex(ajp_msg_t *msg, const char *value,
330                                      int convert)
331{
332    apr_size_t len;
333
334    if (value == NULL) {
335        return(ajp_msg_append_uint16(msg, 0xFFFF));
336    }
337
338    len = strlen(value);
339    if ((msg->len + len + 3) > msg->max_size) {
340        return ajp_log_overflow(msg, "ajp_msg_append_cvt_string");
341    }
342
343    /* ignore error - we checked once */
344    ajp_msg_append_uint16(msg, (apr_uint16_t)len);
345
346    /* We checked for space !!  */
347    memcpy(msg->buf + msg->len, value, len + 1); /* including \0 */
348
349    if (convert) {
350        /* convert from EBCDIC if needed */
351        ap_xlate_proto_to_ascii((char *)msg->buf + msg->len, len + 1);
352    }
353
354    msg->len += len + 1;
355
356    return APR_SUCCESS;
357}
358
359/**
360 * Add a Byte array to AJP Message
361 *
362 * @param msg       AJP Message to get value from
363 * @param value     Pointer to Byte array
364 * @param valuelen  Byte array len
365 * @return          APR_SUCCESS or error
366 */
367apr_status_t ajp_msg_append_bytes(ajp_msg_t *msg, const apr_byte_t *value,
368                                  apr_size_t valuelen)
369{
370    if (! valuelen) {
371        return APR_SUCCESS; /* Shouldn't we indicate an error ? */
372    }
373
374    if ((msg->len + valuelen) > msg->max_size) {
375        return ajp_log_overflow(msg, "ajp_msg_append_bytes");
376    }
377
378    /* We checked for space !!  */
379    memcpy(msg->buf + msg->len, value, valuelen);
380    msg->len += valuelen;
381
382    return APR_SUCCESS;
383}
384
385/**
386 * Get a 32bits unsigned value from AJP Message
387 *
388 * @param msg       AJP Message to get value from
389 * @param rvalue    Pointer where value will be returned
390 * @return          APR_SUCCESS or error
391 */
392apr_status_t ajp_msg_get_uint32(ajp_msg_t *msg, apr_uint32_t *rvalue)
393{
394    apr_uint32_t value;
395
396    if ((msg->pos + 3) > msg->len) {
397        return ajp_log_overflow(msg, "ajp_msg_get_uint32");
398    }
399
400    value  = ((msg->buf[(msg->pos++)] & 0xFF) << 24);
401    value |= ((msg->buf[(msg->pos++)] & 0xFF) << 16);
402    value |= ((msg->buf[(msg->pos++)] & 0xFF) << 8);
403    value |= ((msg->buf[(msg->pos++)] & 0xFF));
404
405    *rvalue = value;
406    return APR_SUCCESS;
407}
408
409
410/**
411 * Get a 16bits unsigned value from AJP Message
412 *
413 * @param msg       AJP Message to get value from
414 * @param rvalue    Pointer where value will be returned
415 * @return          APR_SUCCESS or error
416 */
417apr_status_t ajp_msg_get_uint16(ajp_msg_t *msg, apr_uint16_t *rvalue)
418{
419    apr_uint16_t value;
420
421    if ((msg->pos + 1) > msg->len) {
422        return ajp_log_overflow(msg, "ajp_msg_get_uint16");
423    }
424
425    value  = ((msg->buf[(msg->pos++)] & 0xFF) << 8);
426    value += ((msg->buf[(msg->pos++)] & 0xFF));
427
428    *rvalue = value;
429    return APR_SUCCESS;
430}
431
432/**
433 * Peek a 16bits unsigned value from AJP Message, position in message
434 * is not updated
435 *
436 * @param msg       AJP Message to get value from
437 * @param rvalue    Pointer where value will be returned
438 * @return          APR_SUCCESS or error
439 */
440apr_status_t ajp_msg_peek_uint16(ajp_msg_t *msg, apr_uint16_t *rvalue)
441{
442    apr_uint16_t value;
443
444    if ((msg->pos + 1) > msg->len) {
445        return ajp_log_overflow(msg, "ajp_msg_peek_uint16");
446    }
447
448    value = ((msg->buf[(msg->pos)] & 0xFF) << 8);
449    value += ((msg->buf[(msg->pos + 1)] & 0xFF));
450
451    *rvalue = value;
452    return APR_SUCCESS;
453}
454
455/**
456 * Peek a 8bits unsigned value from AJP Message, position in message
457 * is not updated
458 *
459 * @param msg       AJP Message to get value from
460 * @param rvalue    Pointer where value will be returned
461 * @return          APR_SUCCESS or error
462 */
463apr_status_t ajp_msg_peek_uint8(ajp_msg_t *msg, apr_byte_t *rvalue)
464{
465    if (msg->pos > msg->len) {
466        return ajp_log_overflow(msg, "ajp_msg_peek_uint8");
467    }
468
469    *rvalue = msg->buf[msg->pos];
470    return APR_SUCCESS;
471}
472
473/**
474 * Get a 8bits unsigned value from AJP Message
475 *
476 * @param msg       AJP Message to get value from
477 * @param rvalue    Pointer where value will be returned
478 * @return          APR_SUCCESS or error
479 */
480apr_status_t ajp_msg_get_uint8(ajp_msg_t *msg, apr_byte_t *rvalue)
481{
482
483    if (msg->pos > msg->len) {
484        return ajp_log_overflow(msg, "ajp_msg_get_uint8");
485    }
486
487    *rvalue = msg->buf[msg->pos++];
488    return APR_SUCCESS;
489}
490
491
492/**
493 * Get a String value from AJP Message
494 *
495 * @param msg       AJP Message to get value from
496 * @param rvalue    Pointer where value will be returned
497 * @return          APR_SUCCESS or error
498 */
499apr_status_t ajp_msg_get_string(ajp_msg_t *msg, const char **rvalue)
500{
501    apr_uint16_t size;
502    apr_size_t   start;
503    apr_status_t status;
504
505    status = ajp_msg_get_uint16(msg, &size);
506    start = msg->pos;
507
508    if ((status != APR_SUCCESS) || (size + start > msg->max_size)) {
509        return ajp_log_overflow(msg, "ajp_msg_get_string");
510    }
511
512    msg->pos += (apr_size_t)size;
513    msg->pos++;                   /* a String in AJP is NULL terminated */
514
515    *rvalue = (const char *)(msg->buf + start);
516    return APR_SUCCESS;
517}
518
519
520/**
521 * Get a Byte array from AJP Message
522 *
523 * @param msg       AJP Message to get value from
524 * @param rvalue    Pointer where value will be returned
525 * @param rvalueLen Pointer where Byte array len will be returned
526 * @return          APR_SUCCESS or error
527 */
528apr_status_t ajp_msg_get_bytes(ajp_msg_t *msg, apr_byte_t **rvalue,
529                               apr_size_t *rvalue_len)
530{
531    apr_uint16_t size;
532    apr_size_t   start;
533    apr_status_t status;
534
535    status = ajp_msg_get_uint16(msg, &size);
536    /* save the current position */
537    start = msg->pos;
538
539    if ((status != APR_SUCCESS) || (size + start > msg->max_size)) {
540        return ajp_log_overflow(msg, "ajp_msg_get_bytes");
541    }
542    msg->pos += (apr_size_t)size;   /* only bytes, no trailer */
543
544    *rvalue     = msg->buf + start;
545    *rvalue_len = size;
546
547    return APR_SUCCESS;
548}
549
550
551/**
552 * Create an AJP Message from pool
553 *
554 * @param pool      memory pool to allocate AJP message from
555 * @param size      size of the buffer to create
556 * @param rmsg      Pointer to newly created AJP message
557 * @return          APR_SUCCESS or error
558 */
559apr_status_t ajp_msg_create(apr_pool_t *pool, apr_size_t size, ajp_msg_t **rmsg)
560{
561    ajp_msg_t *msg = (ajp_msg_t *)apr_pcalloc(pool, sizeof(ajp_msg_t));
562
563    msg->server_side = 0;
564
565    msg->buf = (apr_byte_t *)apr_palloc(pool, size);
566    msg->len = 0;
567    msg->header_len = AJP_HEADER_LEN;
568    msg->max_size = size;
569    *rmsg = msg;
570
571    return APR_SUCCESS;
572}
573
574/**
575 * Recopy an AJP Message to another
576 *
577 * @param smsg      source AJP message
578 * @param dmsg      destination AJP message
579 * @return          APR_SUCCESS or error
580 */
581apr_status_t ajp_msg_copy(ajp_msg_t *smsg, ajp_msg_t *dmsg)
582{
583    if (smsg->len > smsg->max_size) {
584        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(01082)
585                     "ajp_msg_copy(): destination buffer too "
586                     "small %" APR_SIZE_T_FMT ", max size is %" APR_SIZE_T_FMT,
587                     smsg->len, smsg->max_size);
588        return  AJP_ETOSMALL;
589    }
590
591    memcpy(dmsg->buf, smsg->buf, smsg->len);
592    dmsg->len = smsg->len;
593    dmsg->pos = smsg->pos;
594
595    return APR_SUCCESS;
596}
597
598
599/**
600 * Serialize in an AJP Message a PING command
601 *
602 * +-----------------------+
603 * | PING CMD (1 byte)     |
604 * +-----------------------+
605 *
606 * @param smsg      AJP message to put serialized message
607 * @return          APR_SUCCESS or error
608 */
609apr_status_t ajp_msg_serialize_ping(ajp_msg_t *msg)
610{
611    apr_status_t rc;
612    ajp_msg_reset(msg);
613
614    if ((rc = ajp_msg_append_uint8(msg, CMD_AJP13_PING)) != APR_SUCCESS)
615        return rc;
616
617    return APR_SUCCESS;
618}
619
620/**
621 * Serialize in an AJP Message a CPING command
622 *
623 * +-----------------------+
624 * | CPING CMD (1 byte)    |
625 * +-----------------------+
626 *
627 * @param smsg      AJP message to put serialized message
628 * @return          APR_SUCCESS or error
629 */
630apr_status_t ajp_msg_serialize_cping(ajp_msg_t *msg)
631{
632    apr_status_t rc;
633    ajp_msg_reset(msg);
634
635    if ((rc = ajp_msg_append_uint8(msg, CMD_AJP13_CPING)) != APR_SUCCESS)
636        return rc;
637
638    return APR_SUCCESS;
639}
640