Merge remote branch 'origin/andrei/pointer_alias_warnings'
[sip-router] / modules_s / rr / avp_cookie.c
1 /*
2  * Route & Record-Route module, avp cookie support
3  *
4  * $Id$
5  *
6  * Copyright (C) 2001-2003 FhG Fokus
7  *
8  * This file is part of ser, a free SIP server.
9  *
10  * ser is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version
14  *
15  * For a license to use the ser software under conditions
16  * other than those described here, or to purchase support for this
17  * software, please contact iptel.org by e-mail at the following addresses:
18  *    info@iptel.org
19  *
20  * ser is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28  */
29
30 #include <stdio.h>
31 #include "avp_cookie.h"
32 #include "../../lib/cds/base64.h"
33 #include "../../crc.h"
34 #include "../../usr_avp.h"
35 #include "../../mem/mem.h"
36
37 #define AVP_COOKIE_NAME "avp="
38 #define AVP_COOKIE_BUFFER 1024
39 #define CRC_LEN 4
40
41 unsigned short crc_secret = 0;
42 regex_t* cookie_filter_re = 0;
43 avp_flags_t avp_flag_dialog = 0;
44
45 #define MAX_AVP_DIALOG_LISTS 4
46 static unsigned short avp_dialog_lists[MAX_AVP_DIALOG_LISTS] = {AVP_CLASS_URI|AVP_TRACK_FROM, AVP_CLASS_URI|AVP_TRACK_TO,
47                                                                 AVP_CLASS_USER|AVP_TRACK_FROM, AVP_CLASS_USER|AVP_TRACK_TO};
48 typedef char rr_avp_flags_t;
49
50 str *rr_get_avp_cookies(void) {
51         unsigned short crc, ll;
52         static char buf[AVP_COOKIE_BUFFER];
53         int len, l, avp_list_no;
54         struct usr_avp *avp;
55         int_str avp_val;
56         str *avp_name;
57         str *result = 0;
58         rr_avp_flags_t avp_flags;
59         struct str_int_data *sid;
60         struct str_str_data *ssd;
61
62
63         len = sizeof(crc);
64         for (avp_list_no=0; avp_list_no<MAX_AVP_DIALOG_LISTS; avp_list_no++) {
65                 for ( avp=get_avp_list(avp_dialog_lists[avp_list_no]); avp; avp = avp->next ) {
66
67                         if ( (avp->flags & avp_flag_dialog) == 0)
68                                 continue;
69
70                         if ((avp->flags&(AVP_NAME_STR|AVP_VAL_STR)) == AVP_NAME_STR) {
71                                 /* avp type str, int value */
72                                 sid = (struct str_int_data*)&avp->d.data[0];
73                                 avp_name = &sid->name;
74                         }
75                         else if ((avp->flags&(AVP_NAME_STR|AVP_VAL_STR)) == (AVP_NAME_STR|AVP_VAL_STR)) {
76                                 /* avp type str, str value */
77                                 ssd = (struct str_str_data*)&avp->d.data[0];
78                                 avp_name = &ssd->name;
79                         }
80                         else
81                                 avp_name = 0;  /* dummy */
82
83                         get_avp_val(avp, &avp_val);
84
85                         l = sizeof(rr_avp_flags_t);
86                         if (avp->flags & AVP_NAME_STR )
87                                 l += avp_name->len+sizeof(unsigned short);
88                         else
89                                 l += sizeof(avp->id);
90                         if (avp->flags & AVP_VAL_STR )
91                                 l += avp_val.s.len+sizeof(unsigned short);
92                         else
93                                 l += sizeof(avp_val.n);
94                         if (len+l > AVP_COOKIE_BUFFER) {
95                                 LOG(L_ERR, "rr:get_avp_cookies: not enough memory to prepare all cookies\n");
96                                 goto brk;
97                         }
98                         avp_flags = (avp->flags & 0x0F)|(avp_list_no << 4);
99                         memcpy(buf+len, &avp_flags, sizeof(rr_avp_flags_t));
100                         len += sizeof(rr_avp_flags_t);
101                         if (avp->flags & AVP_NAME_STR) {
102                                 if (avp_name->len > 0xFFFF)
103                                         ll = 0xFFFF;
104                                 else
105                                         ll = avp_name->len;
106                                 memcpy(buf+len, &ll, sizeof(ll));
107                                 len+= sizeof(ll);
108                                 memcpy(buf+len, avp_name->s, ll);
109                                 len+= ll;
110                         }
111                         else {
112                                 memcpy(buf+len, &avp->id, sizeof(avp->id));
113                                 len+= sizeof(avp->id);
114                         }
115                         if (avp->flags & AVP_VAL_STR) {
116                                 if (avp_val.s.len > 0xFFFF)
117                                         ll = 0xFFFF;
118                                 else
119                                         ll = avp_val.s.len;
120                                 memcpy(buf+len, &ll, sizeof(ll));
121                                 len+= sizeof(ll);
122                                 memcpy(buf+len, avp_val.s.s, ll);
123                                 len+= ll;
124                         }
125                         else {
126                                 memcpy(buf+len, &avp_val.n, sizeof(avp_val.n));
127                                 len+= sizeof(avp_val.n);
128                         }
129                 }
130         }
131 brk:
132         if (len > sizeof(crc)) {
133                 result = (str*) pkg_malloc(sizeof(*result) + sizeof(crc) + (len*4)/3 + 3);
134                 if (!result) {
135                         LOG(L_ERR, "rr:get_avp_cookies: not enough memory\n");
136                         return 0;
137                 }
138                 result->s = (char*)result + sizeof(*result);
139                 crc = crcitt_string_ex(buf+sizeof(crc), len-sizeof(crc), crc_secret);
140                 memcpy(&buf, &crc, sizeof(crc));
141
142                 base64encode(buf, len, result->s, &result->len, 0);
143                 DBG("avp_cookies: len=%d, crc=0x%x, base64(%u)='%.*s'\n", len, crc, result->len, result->len, result->s);
144         }
145         return result;
146 }
147
148 void rr_set_avp_cookies(str *enc_cookies, int reverse_direction) {
149         char *buf;
150         int len, pos;
151         unsigned short crc;
152         struct usr_avp avp;
153         int_str avp_name, avp_val;
154         regmatch_t pmatch;
155         rr_avp_flags_t avp_flags;
156
157         DBG("rr_set_avp_cookies: enc_cookie(%d)='%.*s'\n", enc_cookies->len, enc_cookies->len, enc_cookies->s);
158         buf = (char*) pkg_malloc((enc_cookies->len*3)/4 + 3);
159         if (!buf) {
160                 LOG(L_ERR, "rr:set_avp_cookies: not enough memory\n");
161                 return;
162         }
163         base64decode(enc_cookies->s, enc_cookies->len, buf, &len);
164
165         if (len <= sizeof(crc))
166                 return;
167         crc = crcitt_string_ex(buf+sizeof(crc), len-sizeof(crc), crc_secret);
168         if (crc != *(unsigned short*) buf) {
169                 LOG(L_ERR, "rr:set_avp_cookies: bad CRC when decoding AVP cookie\n");
170                 return;
171         }
172         pos = sizeof(crc);
173         while (pos < len) {
174                 memcpy(&avp_flags, buf+pos, sizeof(avp_flags));
175                 if ((avp_flags >> 4) >= MAX_AVP_DIALOG_LISTS) {
176                         LOG(L_ERR, "rr:set_avp_cookies: AVP cookies corrupted\n");
177                         break;
178                 }
179
180                 avp.flags = (avp_flags & 0x0F) | avp_dialog_lists[avp_flags >> 4];
181                 if (reverse_direction && (avp.flags & (AVP_CLASS_DOMAIN|AVP_CLASS_USER|AVP_CLASS_URI)) ) {
182                         avp.flags ^= AVP_TRACK_ALL;  /* flip from/to flags */
183                 }
184                 pos+= sizeof(rr_avp_flags_t);
185                 if (avp.flags & AVP_NAME_STR) {
186                         avp_name.s.len = 0;
187                         memcpy(&avp_name.s.len, buf+pos, sizeof(unsigned short));
188                         avp_name.s.s = buf+pos+sizeof(unsigned short);
189                         pos+= sizeof(unsigned short)+avp_name.s.len;
190                         DBG("rr:set_avp_cookies: found cookie '%.*s'\n", avp_name.s.len, avp_name.s.s);
191                 }
192                 else {
193                         memcpy(&avp.id, buf+pos, sizeof(avp.id));
194                         pos+= sizeof(avp.id);
195                         avp_name.n = avp.id;
196                         DBG("rr:set_avp_cookies: found cookie #%d\n", avp_name.n);
197                 }
198                 if (pos >= len) {
199                         LOG(L_ERR, "rr:set_avp_cookies: AVP cookies corrupted\n");
200                         break;
201                 }
202                 if (avp.flags & AVP_VAL_STR) {
203                         avp_val.s.len = 0;
204                         memcpy(&avp_val.s.len, buf+pos, sizeof(unsigned short));
205                         avp_val.s.s = buf+pos+sizeof(unsigned short);
206                         pos+= sizeof(unsigned short)+avp_val.s.len;
207                 }
208                 else {
209                         memcpy(&avp_val.n, buf+pos, sizeof(avp_val.n));
210                         pos+= sizeof(avp_val.n);
211                 }
212                 if (pos > len) {
213                         LOG(L_ERR, "rr:set_avp_cookies: AVP cookies corrupted\n");
214                         break;
215                 }
216                 /* filter cookie */
217                 if (cookie_filter_re) {
218                         if (avp.flags & AVP_NAME_STR) {
219                                 char savec;
220                                 savec = avp_name.s.s[avp_name.s.len];
221                                 avp_name.s.s[avp_name.s.len] = 0;
222                                 if (regexec(cookie_filter_re, avp_name.s.s, 1, &pmatch, 0) != 0) {
223                                         DBG("rr:set_avp_cookies: regex doesn't match (str)\n");
224                                         avp_name.s.s[avp_name.s.len] = savec;
225                                         continue;
226                                 }
227                                 avp_name.s.s[avp_name.s.len] = savec;
228                         }
229                         else {
230                                 char buf[25];
231                                 snprintf(buf, sizeof(buf)-1, "i:%d", avp_name.n);
232                                 buf[sizeof(buf)-1]=0;
233                                 if (regexec(cookie_filter_re, buf, 1, &pmatch, 0) != 0) {
234                                         DBG("rr:set_avp_cookies: regex doesn't match (int)\n");
235                                         continue;
236                                 }
237                         }
238                 }
239                 /* set avp from cookie */
240                 DBG("rr:set_avp_cookies: adding AVP\n");
241
242                 if ( add_avp(avp.flags|avp_flag_dialog, avp_name, avp_val)!=0 ) {
243                         LOG(L_ERR, "ERROR: rr:set_avp_cookies: add_avp failed\n");
244                 }
245         }
246         pkg_free(buf);
247 }