/* * Copyright (C) 2001-2003 FhG Fokus * * This file is part of Kamailio, a free SIP server. * * Kamailio is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * Kamailio is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ /*! * \file * \brief Exec module:: Module interface * \ingroup exec * Module: \ref exec * * functions for creating environment variables out of a request's * header; known compact header field names are translated to * canonical form; multiple header field occurrences are merged * into a single variable * * known limitations: * - compact header field names unknown to parser will not be translated to * canonical form. Thus, environment variables may have either name and * users have to check for both of them. * - symbols in header field names will be translated to underscore * */ #include #include "../../parser/msg_parser.h" #include "../../parser/parse_to.h" #include "../../parser/parse_via.h" #include "../../parser/parse_uri.h" #include "../../mem/mem.h" #include "../../dprint.h" #include "../../md5utils.h" #include "../../char_msg_val.h" #include "exec_hf.h" extern int exec_bash_safety; /* should be environment variables set by header fields ? */ unsigned int setvars=1; /* insert a new header field into the structure; */ static int insert_hf( struct hf_wrapper **list, struct hdr_field *hf ) { struct hf_wrapper *w; /* new wrapper */ struct hf_wrapper *i; w=(struct hf_wrapper *)pkg_malloc(sizeof(struct hf_wrapper)); if (!w) { LM_ERR("ran out of pkg mem\n"); return 0; } memset(w, 0, sizeof(struct hf_wrapper)); w->var_type=W_HF;w->u.hf=hf; w->prefix=HF_PREFIX; w->prefix_len=HF_PREFIX_LEN; /* is there another hf of the same type?... */ for(i=*list; i; i=i->next_other) { if (i->var_type==W_HF && i->u.hf->type==hf->type) { /* if it is OTHER, check name too */ if (hf->type==HDR_OTHER_T && (hf->name.len!=i->u.hf->name.len || strncasecmp(i->u.hf->name.s, hf->name.s, hf->name.len)!=0)) continue; /* yes, we found a hf of same type */ w->next_same=i->next_same; w->next_other=i->next_other; i->next_same=w; break; } } /* ... no previous HF of the same type found */ if (i==0) { w->next_other=*list; *list=w; } return 1; } static void release_hf_struct( struct hf_wrapper *list ) { struct hf_wrapper *i, *j, *nexts, *nexto; i=list; while(i) { nexto=i->next_other; j=i->next_same; pkg_free(i); /* release list of same type hf */ while(j) { nexts=j->next_same; pkg_free(j); j=nexts; } i=nexto; } } /* if that is some of well-known header fields which have compact * form, return canonical form ... returns 1 and sets params; * 0 is returned otherwise */ static int compacthdr_type2str(hdr_types_t type, char **hname, int *hlen ) { switch(type) { /* HDR_CONTENT_ENCODING: 'e' -- unsupported by parser */ /* HDR_SUBJECT: 's' -- unsupported by parser */ case HDR_VIA_T /* v */ : *hname=VAR_VIA; *hlen=VAR_VIA_LEN; break; case HDR_CONTENTTYPE_T /* c */ : *hname=VAR_CTYPE; *hlen=VAR_CTYPE_LEN; break; case HDR_FROM_T /* f */: *hname=VAR_FROM; *hlen=VAR_FROM_LEN; break; case HDR_CALLID_T /* i */: *hname=VAR_CALLID; *hlen=VAR_CALLID_LEN; break; case HDR_SUPPORTED_T /* k */: *hname=VAR_SUPPORTED; *hlen=VAR_SUPPORTED_LEN; break; case HDR_CONTENTLENGTH_T /* l */: *hname=VAR_CLEN; *hlen=VAR_CLEN_LEN; break; case HDR_CONTACT_T /* m */: *hname=VAR_CONTACT; *hlen=VAR_CONTACT_LEN; break; case HDR_TO_T /* t */: *hname=VAR_TO; *hlen=VAR_TO_LEN; break; case HDR_EVENT_T /* o */: *hname=VAR_EVENT; *hlen=VAR_EVENT_LEN; break; default: return 0; } return 1; } static int canonize_headername(str *orig, char **hname, int *hlen ) { char *c; int i; *hlen=orig->len; *hname=pkg_malloc(*hlen); if (!*hname) { LM_ERR("no pkg mem for hname\n"); return 0; } for (c=orig->s, i=0; i<*hlen; i++, c++) { /* lowercase to uppercase */ if (*c>='a' && *c<='z') *((*hname)+i)=*c-('a'-'A'); /* uppercase and numbers stay "as is" */ else if ((*c>='A' && *c<='Z')||(*c>='0' && *c<='9')) *((*hname)+i)=*c; /* legal symbols will be translated to underscore */ else if (strchr(UNRESERVED_MARK HNV_UNRESERVED, *c) || (*c==ESCAPE)) *((*hname)+i)=HFN_SYMBOL; else { LM_ERR("print_var unexpected char '%c' in hfname %.*s\n", *c, *hlen, orig->s ); *((*hname)+i)=HFN_SYMBOL; } } return 1; } static int print_av_var(struct hf_wrapper *w) { int env_len; char *env; char *c; env_len=w->u.av.attr.len+1/*assignment*/+w->u.av.val.len+1/*ZT*/; env=pkg_malloc(env_len); if (!env) { LM_ERR("no pkg mem\n"); return 0; } c=env; memcpy(c, w->u.av.attr.s, w->u.av.attr.len); c+=w->u.av.attr.len; *c=EV_ASSIGN;c++; memcpy(c, w->u.av.val.s, w->u.av.val.len);c+=w->u.av.val.len; *c=0; /* zero termination */ w->envvar=env; return 1; } /* creates a malloc-ed string with environment variable; returns 1 on success, * 0 on failure */ static int print_hf_var(struct hf_wrapper *w, int offset) { char *hname; int hlen; short canonical; char *envvar; int envvar_len; struct hf_wrapper *wi; char *c; /* make -Wall happy */ hname=0;hlen=0;envvar=0; /* Make sure header names with possible compact forms * will be printed canonically */ canonical=compacthdr_type2str(w->u.hf->type, &hname, &hlen); /* header field has not been made canonical using a table; * do it now by uppercasing header-field name */ if (!canonical) { if (!canonize_headername(&w->u.hf->name, &hname, &hlen)) { LM_ERR("canonize_hn error\n"); return 0; } } /* now we have a header name, let us generate the var */ envvar_len=w->u.hf->body.len; for(wi=w->next_same; wi; wi=wi->next_same) { /* other values, separated */ envvar_len+=1 /* separator */ + wi->u.hf->body.len; } envvar=pkg_malloc(w->prefix_len+hlen+1/*assignment*/+envvar_len+1/*ZT*/); if (!envvar) { LM_ERR("no pkg mem\n"); goto error00; } memcpy(envvar, w->prefix, w->prefix_len); c=envvar+w->prefix_len; memcpy(c, hname, hlen ); c+=hlen; *c=EV_ASSIGN;c++; if (exec_bash_safety && w->u.hf->body.len>=4 && !strncmp(w->u.hf->body.s, "() {", 4)) { memcpy(c, w->u.hf->body.s+offset+2, w->u.hf->body.len-2 ); c+=(w->u.hf->body.len-2); } else { memcpy(c, w->u.hf->body.s+offset, w->u.hf->body.len ); c+=w->u.hf->body.len; } for(wi=w->next_same; wi; wi=wi->next_same) { *c=HF_SEPARATOR;c++; if (exec_bash_safety && wi->u.hf->body.len>=4 && !strncmp(wi->u.hf->body.s, "() {", 4)) { memcpy(c, wi->u.hf->body.s+offset+2, wi->u.hf->body.len-2 ); c+=(wi->u.hf->body.len-2); } else { memcpy(c, wi->u.hf->body.s+offset, wi->u.hf->body.len ); c+=wi->u.hf->body.len; } } *c=0; /* zero termination */ LM_DBG("%s\n", envvar ); w->envvar=envvar; if (!canonical) pkg_free(hname); return 1; error00: if (!canonical) pkg_free(hname); return 0; } static int print_var(struct hf_wrapper *w, int offset) { switch(w->var_type) { case W_HF: return print_hf_var(w, offset); case W_AV: return print_av_var(w); default: LM_CRIT("unknown type: %d\n", w->var_type ); return 0; } } static void release_vars(struct hf_wrapper *list) { while(list) { if (list->envvar) { pkg_free(list->envvar); list->envvar=0; } list=list->next_other; } } /* create ordered HF structure in pkg memory */ static int build_hf_struct(struct sip_msg *msg, struct hf_wrapper **list) { struct hdr_field *h; *list=0; /* create ordered header-field structure */ for (h=msg->headers; h; h=h->next) { if (!insert_hf(list,h)) { LM_ERR("insert_hf failed\n"); goto error00; } } return 1; error00: release_hf_struct(*list); *list=0; return 0; } /* create env vars in malloc memory */ static int create_vars(struct hf_wrapper *list, int offset) { int var_cnt; struct hf_wrapper *w; /* create variables now */ var_cnt=0; for(w=list;w;w=w->next_other) { if (!print_var(w, offset)) { LM_ERR("create_vars failed\n"); return 0; } var_cnt++; } return var_cnt; } environment_t *replace_env(struct hf_wrapper *list) { int var_cnt; char **cp; struct hf_wrapper *w; char **new_env; int i; environment_t *backup_env; backup_env=(environment_t *)pkg_malloc(sizeof(environment_t)); if (!backup_env) { LM_ERR("no pkg mem for backup env\n"); return 0; } /* count length of current env list */ var_cnt=0; for (cp=environ; *cp; cp++) var_cnt++; backup_env->old_cnt=var_cnt; /* count length of our extensions */ for(w=list;w;w=w->next_other) var_cnt++; new_env=pkg_malloc((var_cnt+1)*sizeof(char *)); if (!new_env) { LM_ERR("no pkg mem\n"); pkg_free(backup_env); return 0; } /* put all var pointers into new environment */ i=0; for (cp=environ; *cp; cp++) { /* replicate old env */ new_env[i]=*cp; i++; } for (w=list;w;w=w->next_other) { /* append new env */ new_env[i]=w->envvar; i++; } new_env[i]=0; /* zero termination */ /* install new environment */ backup_env->env=environ; environ=new_env; /* return previous environment */ return backup_env; } void unset_env(environment_t *backup_env) { char **cur_env, **cur_env0; int i; /* switch-over to backup environment */ cur_env0=cur_env=environ; environ=backup_env->env; i=0; /* release environment */ while(*cur_env) { /* leave previously existing vars alone */ if (i>=backup_env->old_cnt) { pkg_free(*cur_env); } cur_env++; i++; } pkg_free(cur_env0); pkg_free(backup_env); } static int append_var(char *name, char *value, int len, struct hf_wrapper **list) { struct hf_wrapper *w; w=(struct hf_wrapper *)pkg_malloc(sizeof(struct hf_wrapper)); if (!w) { LM_ERR("ran out of pkg mem\n"); return 0; } memset(w, 0, sizeof(struct hf_wrapper)); w->var_type=W_AV; w->u.av.attr.s=name; w->u.av.attr.len=strlen(name); w->u.av.val.s=value; /* NULL strings considered empty, if len unknown, calculate it now */ w->u.av.val.len= value==0?0:(len==0? strlen(value) : len); w->next_other=*list; *list=w; return 1; } static int append_fixed_vars(struct sip_msg *msg, struct hf_wrapper **list) { static char tid[MD5_LEN]; str *uri; struct sip_uri parsed_uri, oparsed_uri; char *val; int val_len; /* source ip */ if (!append_var(EV_SRCIP, ip_addr2a(&msg->rcv.src_ip), 0, list)) { LM_ERR("append_var SRCIP failed \n"); return 0; } /* request URI */ uri=msg->new_uri.s && msg->new_uri.len ? &msg->new_uri : &msg->first_line.u.request.uri; if (!append_var(EV_RURI, uri->s, uri->len, list )) { LM_ERR("append_var URI failed\n"); return 0; } /* userpart of request URI */ if (parse_uri(uri->s, uri->len, &parsed_uri)<0) { LM_WARN("uri not parsed\n"); } else { if (!append_var(EV_USER, parsed_uri.user.s, parsed_uri.user.len, list)) { LM_ERR("append_var USER failed\n"); goto error; } } /* original URI */ if (!append_var(EV_ORURI, msg->first_line.u.request.uri.s, msg->first_line.u.request.uri.len, list)) { LM_ERR("append_var O-URI failed\n"); goto error; } /* userpart of request URI */ if (parse_uri(msg->first_line.u.request.uri.s, msg->first_line.u.request.uri.len, &oparsed_uri)<0) { LM_WARN("orig URI not parsed\n"); } else { if (!append_var(EV_OUSER, oparsed_uri.user.s, oparsed_uri.user.len, list)) { LM_ERR("ppend_var OUSER failed\n"); goto error; } } /* tid, transaction id == via/branch */ if (!char_msg_val(msg, tid)) { LM_WARN("no tid can be determined\n"); val=0; val_len=0; } else { val=tid;val_len=MD5_LEN; } if (!append_var(EV_TID, val,val_len, list)) { LM_ERR("append_var TID failed\n"); goto error; } /* did, dialogue id == To-tag */ if (!(msg->to && get_to(msg) )) { LM_ERR("no to-tag\n"); val=0; val_len=0; } else { val=get_to(msg)->tag_value.s; val_len=get_to(msg)->tag_value.len; } if (!append_var(EV_DID, val, val_len, list)) { LM_ERR("append_var DID failed\n"); goto error; } return 1; error: return 0; } environment_t *set_env(struct sip_msg *msg) { struct hf_wrapper *hf_list; environment_t *backup_env; /* parse all so that we can pass all header fields to script */ if (parse_headers(msg, HDR_EOH_F, 0)==-1) { LM_ERR("parsing failed\n"); return 0; } hf_list=0; /* create a temporary structure with ordered header fields * and create environment variables out of it */ if (!build_hf_struct(msg, &hf_list)) { LM_ERR("build_hf_struct failed\n"); return 0; } if (!append_fixed_vars(msg, &hf_list)) { LM_ERR("append_fixed_vars failed\n"); goto error01; } /* create now the strings for environment variables */ if (!create_vars(hf_list, 0)) { LM_ERR("create_vars failed\n"); goto error00; } /* install the variables in current environment */ backup_env=replace_env(hf_list); if (!backup_env) { LM_ERR("replace_env failed\n"); goto error00; } /* release the ordered HF structure -- we only need the vars now */ release_hf_struct(hf_list); return backup_env; error00: release_vars(hf_list); /* release variables */ error01: release_hf_struct(hf_list); /* release temporary ordered HF struct */ return 0; }