/* * Function to decompress a compressed message */ static int mc_decompress(struct sip_msg* msg) { #define HDRS_TO_SKIP 4 int i; int j; int rc; int algo=-1; int hdrs_algo=-1; int b64_required=-1; str msg_body; str msg_final; str b64_decode={NULL, 0}; str hdr_b64_decode={NULL,0}; str uncomp_body={NULL,0}; str uncomp_hdrs={NULL,0}; char *new_buf; unsigned long temp; /* hdr_vec allows to sort the headers. This will help skipping these headers when building the new message */ struct hdr_field *hf; struct hdr_field *hdr_vec[HDRS_TO_SKIP]; /*hdr_vec : 0 Content-Length 1 Comp-Hdrs 2 Headers-Algo 3 Content-Encoding*/ memset(hdr_vec, 0, HDRS_TO_SKIP * sizeof(struct hdr_field*)); if (parse_headers(msg, HDR_EOH_F, 0) != 0) { LM_ERR("failed to parse SIP message\n"); return -1; } /*If compressed with this module there are great chances that Content-Encoding is last*/ hdr_vec[3] = msg->last_header; if (!is_content_encoding(hdr_vec[3])) { hdr_vec[3] = NULL; for (hf = msg->headers; hf; hf = hf->next) { if (is_content_encoding(hf)) { hdr_vec[3] = hf; continue; } if (hf->type == HDR_OTHER_T && !strncasecmp(hf->name.s, COMP_HDRS,COMP_HDRS_LEN)) { hdr_vec[1] = hf; continue; } if (hf->type == HDR_OTHER_T && !strncasecmp(hf->name.s, HDRS_ENCODING, sizeof(HDRS_ENCODING)-1)) { hdr_vec[2] = hf; } if (hdr_vec[1] && hdr_vec[2] && hdr_vec[3]) break; } } else { for (hf = msg->headers; hf; hf = hf->next) { if (!hdr_vec[1] && hf->type == HDR_OTHER_T && !strncasecmp(hf->name.s, COMP_HDRS,COMP_HDRS_LEN)) { hdr_vec[1] = hf; continue; } if (!hdr_vec[2] && hf->type == HDR_OTHER_T && !strncasecmp(hf->name.s, HDRS_ENCODING, sizeof(HDRS_ENCODING)-1)) hdr_vec[2] = hf; if (hdr_vec[2] && hdr_vec[3] && hdr_vec[1]) break; } } /* Only if content-encoding present, Content-Length will be replaced with the one in the compressed body or in compressed headers*/ if (hdr_vec[3]) { hdr_vec[0] = msg->content_length; parse_algo_hdr(hdr_vec[3], &algo, &b64_required); } if (b64_required > 0 && hdr_vec[3]) { msg_body.s = msg->last_header->name.s + msg->last_header->len + CRLF_LEN; msg_body.len = strlen(msg_body.s); /* Cutting CRLF'S at the end of the message */ while (WORD(msg_body.s + msg_body.len-CRLF_LEN) == PARSE_CRLF) { msg_body.len -= CRLF_LEN; } if (wrap_realloc(&body_in, calc_max_base64_decode_len(msg_body.len))) return -1; b64_decode.s = body_in.s; b64_decode.len = base64decode((unsigned char*)b64_decode.s, (unsigned char*)msg_body.s, msg_body.len); } else if (hdr_vec[3]) { if (get_body(msg, &msg_body) < 0) { LM_ERR("failed to get body\n"); return -1; } b64_decode.s = msg_body.s; b64_decode.len = msg_body.len; } b64_required=0; if (hdr_vec[2]) { parse_algo_hdr(hdr_vec[3], &algo, &b64_required); } if (b64_required > 0 && hdr_vec[1]) { if (wrap_realloc(&hdr_in, calc_max_base64_decode_len(hdr_vec[1]->body.len))) return -1; hdr_b64_decode.s = hdr_in.s; hdr_b64_decode.len = base64decode( (unsigned char*)hdr_b64_decode.s, (unsigned char*)hdr_vec[1]->body.s, hdr_vec[1]->body.len ); } else if (hdr_vec[1]) { hdr_b64_decode.s = hdr_vec[1]->body.s; hdr_b64_decode.len = hdr_vec[1]->body.len; } switch (hdrs_algo) { case 0: /* deflate */ temp = (unsigned long)BUFLEN; rc = uncompress((unsigned char*)hdr_buf, &temp, (unsigned char*)hdr_b64_decode.s, (unsigned long)hdr_b64_decode.len); uncomp_hdrs.s = hdr_buf; uncomp_hdrs.len = temp; if (check_zlib_rc(rc)) { LM_ERR("header decompression failed\n"); return -1; } break; case 1: /* gzip */ rc = gzip_uncompress( (unsigned char*)hdr_b64_decode.s, (unsigned long)hdr_b64_decode.len, &hdr_out, &temp); if (check_zlib_rc(rc)) { LM_ERR("header decompression failed\n"); return -1; } uncomp_hdrs.s = hdr_out.s; uncomp_hdrs.len = temp; break; case -1: break; default: return -1; } switch (algo) { case 0: /* deflate */ temp = (unsigned long)BUFLEN; rc = uncompress((unsigned char*)body_buf, &temp, (unsigned char*)b64_decode.s, (unsigned long)b64_decode.len); if (check_zlib_rc(rc)) { LM_ERR("body decompression failed\n"); return -1; } uncomp_body.s = body_buf; uncomp_body.len = temp; break; case 1: /* gzip */ rc = gzip_uncompress( (unsigned char*)b64_decode.s, (unsigned long)b64_decode.len, &body_out, &temp); if (check_zlib_rc(rc)) { LM_ERR("body decompression failed\n"); return -1; } uncomp_body.s = body_out.s; uncomp_body.len = temp; break; case -1: LM_DBG("no body\n"); break; default: LM_ERR("invalid algo\n"); return -1; } /* Sort to have the headers in order */ for (i = 0; i < HDRS_TO_SKIP - 1; i++) { for (j = i + 1; j < HDRS_TO_SKIP; j++) { if (!hdr_vec[j]) continue; if (!hdr_vec[i] && hdr_vec[j]) { hdr_vec[i] = hdr_vec[j]; hdr_vec[j] = NULL; } if ((hdr_vec[i] && hdr_vec[j]) && (hdr_vec[i]->name.s > hdr_vec[j]->name.s)) { hf = hdr_vec[i]; hdr_vec[i] = hdr_vec[j]; hdr_vec[j] = hf; } } } int msg_final_len = 0; int msg_ptr=0; for ( i = 0; i < HDRS_TO_SKIP; i++) { if (hdr_vec[i]) { msg_final_len += hdr_vec[i]->name.s - (msg->buf+msg_ptr); msg_ptr += hdr_vec[i]->name.s+hdr_vec[i]->len - (msg->buf+msg_ptr); } } msg_final_len += msg->last_header->name.s + msg->last_header->len - (msg->buf + msg_ptr); if (hdrs_algo >= 0) msg_final_len += uncomp_hdrs.len; if (algo >= 0) msg_final_len += uncomp_body.len; else msg_final_len += strlen(msg->eoh); if (wrap_realloc(&buf_out, msg_final_len)) return -1; msg_ptr = 0; msg_final.len = 0; msg_final.s = buf_out.s; for ( i = 0; i < HDRS_TO_SKIP; i++) { if (hdr_vec[i]) { wrap_copy_and_update(&msg_final.s, msg->buf+msg_ptr, hdr_vec[i]->name.s-(msg->buf+msg_ptr), &msg_final.len); msg_ptr += (hdr_vec[i]->name.s+hdr_vec[i]->len) - (msg->buf+msg_ptr); } } wrap_copy_and_update( &msg_final.s, msg->buf+msg_ptr, (msg->last_header->name.s+msg->last_header->len)- (msg->buf+msg_ptr), &msg_final.len ); if (hdrs_algo >= 0) { wrap_copy_and_update(&msg_final.s, uncomp_hdrs.s, uncomp_hdrs.len,&msg_final.len); } if (algo >= 0) { wrap_copy_and_update(&msg_final.s, uncomp_body.s, uncomp_body.len, &msg_final.len); } else { wrap_copy_and_update(&msg_final.s, msg->eoh, strlen(msg->eoh), &msg_final.len); } /* new buffer because msg_final(out_buf) will * be overwritten at next iteration */ #ifdef DYN_BUF new_buf = pkg_malloc(msg_final.len+1); if (new_buf == NULL) { LM_ERR("no more pkg mem\n"); return -1; } #else new_buf = msg->buf; #endif memcpy(new_buf, msg_final.s, msg_final.len); new_buf[msg_final.len] = '\0'; struct sip_msg tmp; memcpy(&tmp, msg, sizeof(struct sip_msg)); /*reset dst_uri and path_vec to avoid free*/ if (msg->dst_uri.s != NULL) { msg->dst_uri.s = NULL; msg->dst_uri.len = 0; } if (msg->path_vec.s != NULL) { msg->path_vec.s = NULL; msg->path_vec.len = 0; } free_sip_msg(msg); memset(msg, 0, sizeof(struct sip_msg)); /* restore msg fields */ msg->id = tmp.id; msg->rcv = tmp.rcv; msg->set_global_address = tmp.set_global_address; msg->set_global_port = tmp.set_global_port; msg->flags = tmp.flags; msg->msg_flags = tmp.msg_flags; msg->hash_index = tmp.hash_index; msg->force_send_socket = tmp.force_send_socket; msg->dst_uri = tmp.dst_uri; msg->path_vec = tmp.path_vec; /* set the new ones */ msg->buf = new_buf; msg->len = msg_final.len; /* reparse the message */ if (parse_msg(msg->buf, msg->len, msg) != 0) LM_ERR("parse_msg failed\n"); return 1; }
int init_load_irx(char *gz, int gz_size, module_t *modules, int num) { int i; int ret; char *tar; int tar_size; char *module; int module_size; smod_mod_info_t mod_t; tar_size = gzip_get_size(gz,gz_size); tar = malloc(tar_size); if ((ret = gzip_uncompress(gz,tar)) != Z_OK) { free(tar); return ret; } if (tar == NULL) { return -1; } for(i = 0; i < num; i++) { if(!smod_get_mod_by_name(modules[i].name, &mod_t)) { if (get_file_from_tar(tar,tar_size,modules[i].module, &module, &module_size) < 0) { #ifdef DEBUG printf("Failed to find module: %s\n", modules[i].module); #endif modules[i].result = -1; free(tar); return -1; } if (SifExecModuleBuffer(module, module_size,modules[i].arglen, modules[i].args, &modules[i].result) < 0) { #ifdef DEBUG printf("Failed to load module: %s\n", modules[i].module); #endif modules[i].result = -2; free(tar); return -2; } if (modules[i].result) { #ifdef DEBUG printf("Failed to start module: %s\n", modules[i].module); #endif free(tar); return -3; } } else { #ifdef DEBUG printf("Possible module conflict\n"); #endif free(tar); return -4; } } free(tar); return 0; }