everything: shotgun attempt to put PROTO_WS and PROTO_WSS across core and in modules...
[sip-router] / modules_k / permissions / trusted.c
1 /*
2  * $Id$
3  *
4  * allow_trusted related functions
5  *
6  * Copyright (C) 2003-2012 Juha Heinanen
7  *
8  * This file is part of Kamailio, a free SIP server.
9  *
10  * Kamailio 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  * Kamailio is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License 
21  * along with this program; if not, write to the Free Software 
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  *
24  * History:
25  * --------
26  *  2004-06-07  updated to the new DB api, moved reload_trusted_table (andrei)
27  */
28
29 #include <sys/types.h>
30 #include <regex.h>
31 #include <string.h>
32
33 #include "permissions.h"
34 #include "hash.h"
35 #include "../../config.h"
36 #include "../../lib/srdb1/db.h"
37 #include "../../ip_addr.h"
38 #include "../../mod_fix.h"
39 #include "../../mem/shm_mem.h"
40 #include "../../parser/msg_parser.h"
41 #include "../../parser/parse_from.h"
42 #include "../../usr_avp.h"
43
44 #define TABLE_VERSION 5
45
46 struct trusted_list ***hash_table;     /* Pointer to current hash table pointer */
47 struct trusted_list **hash_table_1;   /* Pointer to hash table 1 */
48 struct trusted_list **hash_table_2;   /* Pointer to hash table 2 */
49
50
51 static db1_con_t* db_handle = 0;
52 static db_func_t perm_dbf;
53
54
55 /*
56  * Reload trusted table to new hash table and when done, make new hash table
57  * current one.
58  */
59 int reload_trusted_table(void)
60 {
61         db_key_t cols[4];
62         db1_res_t* res = NULL;
63         db_row_t* row;
64         db_val_t* val;
65
66         struct trusted_list **new_hash_table;
67         int i;
68
69         char *pattern, *tag;
70
71         cols[0] = &source_col;
72         cols[1] = &proto_col;
73         cols[2] = &from_col;
74         cols[3] = &tag_col;
75
76         if (db_handle == 0) {
77             LM_ERR("no connection to database\n");
78             return -1;
79         }
80
81         if (perm_dbf.use_table(db_handle, &trusted_table) < 0) {
82                 LM_ERR("failed to use trusted table\n");
83                 return -1;
84         }
85
86         if (perm_dbf.query(db_handle, NULL, 0, NULL, cols, 0, 4, 0, &res) < 0) {
87                 LM_ERR("failed to query database\n");
88                 return -1;
89         }
90
91         /* Choose new hash table and free its old contents */
92         if (*hash_table == hash_table_1) {
93                 empty_hash_table(hash_table_2);
94                 new_hash_table = hash_table_2;
95         } else {
96                 empty_hash_table(hash_table_1);
97                 new_hash_table = hash_table_1;
98         }
99
100         row = RES_ROWS(res);
101
102         LM_DBG("number of rows in trusted table: %d\n", RES_ROW_N(res));
103                 
104         for (i = 0; i < RES_ROW_N(res); i++) {
105             val = ROW_VALUES(row + i);
106             if ((ROW_N(row + i) == 4) &&
107                 (VAL_TYPE(val) == DB1_STRING) && !VAL_NULL(val) &&
108                 (VAL_TYPE(val + 1) == DB1_STRING) && !VAL_NULL(val + 1) &&
109                 (VAL_NULL(val + 2) ||
110                  ((VAL_TYPE(val + 2) == DB1_STRING) && !VAL_NULL(val + 2))) &&
111                 (VAL_NULL(val + 3) ||
112                  ((VAL_TYPE(val + 3) == DB1_STRING) && !VAL_NULL(val + 3)))) {
113                 if (VAL_NULL(val + 2)) {
114                     pattern = 0;
115                 } else {
116                     pattern = (char *)VAL_STRING(val + 2);
117                 }
118                 if (VAL_NULL(val + 3)) {
119                     tag = 0;
120                 } else {
121                     tag = (char *)VAL_STRING(val + 3);
122                 }
123                 if (hash_table_insert(new_hash_table,
124                                       (char *)VAL_STRING(val),
125                                       (char *)VAL_STRING(val + 1),
126                                       pattern, tag) == -1) {
127                     LM_ERR("hash table problem\n");
128                     perm_dbf.free_result(db_handle, res);
129                     return -1;
130                 }
131                 LM_DBG("tuple <%s, %s, %s, %s> inserted into trusted hash "
132                     "table\n", VAL_STRING(val), VAL_STRING(val + 1),
133                     pattern, tag);
134             } else {
135                 LM_ERR("database problem\n");
136                 perm_dbf.free_result(db_handle, res);
137                 return -1;
138             }
139         }
140
141         perm_dbf.free_result(db_handle, res);
142
143         *hash_table = new_hash_table;
144
145         LM_DBG("trusted table reloaded successfully.\n");
146         
147         return 1;
148 }
149
150
151 /*
152  * Initialize data structures
153  */
154 int init_trusted(void)
155 {
156         /* Check if hash table needs to be loaded from trusted table */
157         if (!db_url.s) {
158                 LM_INFO("db_url parameter of permissions module not set, "
159                         "disabling allow_trusted\n");
160                 return 0;
161         } else {
162                 if (db_bind_mod(&db_url, &perm_dbf) < 0) {
163                         LM_ERR("load a database support module\n");
164                         return -1;
165                 }
166
167                 if (!DB_CAPABILITY(perm_dbf, DB_CAP_QUERY)) {
168                         LM_ERR("database module does not implement 'query' function\n");
169                         return -1;
170                 }
171         }
172
173         hash_table_1 = hash_table_2 = 0;
174         hash_table = 0;
175
176         if (db_mode == ENABLE_CACHE) {
177                 db_handle = perm_dbf.init(&db_url);
178                 if (!db_handle) {
179                         LM_ERR("unable to connect database\n");
180                         return -1;
181                 }
182
183                 if(db_check_table_version(&perm_dbf, db_handle, &trusted_table, TABLE_VERSION) < 0) {
184                         LM_ERR("error during table version check.\n");
185                         perm_dbf.close(db_handle);
186                         return -1;
187                 }
188
189                 hash_table_1 = new_hash_table();
190                 if (!hash_table_1) return -1;
191                 
192                 hash_table_2  = new_hash_table();
193                 if (!hash_table_2) goto error;
194                 
195                 hash_table = (struct trusted_list ***)shm_malloc
196                         (sizeof(struct trusted_list **));
197                 if (!hash_table) goto error;
198
199                 *hash_table = hash_table_1;
200
201                 if (reload_trusted_table() == -1) {
202                         LM_CRIT("reload of trusted table failed\n");
203                         goto error;
204                 }
205
206                 perm_dbf.close(db_handle);
207                 db_handle = 0;
208         }
209         return 0;
210
211 error:
212         if (hash_table_1) {
213                 free_hash_table(hash_table_1);
214                 hash_table_1 = 0;
215         }
216         if (hash_table_2) {
217                 free_hash_table(hash_table_2);
218                 hash_table_2 = 0;
219         }
220         if (hash_table) {
221                 shm_free(hash_table);
222                 hash_table = 0;
223         }
224         perm_dbf.close(db_handle);
225         db_handle = 0;
226         return -1;
227 }
228
229
230 /*
231  * Open database connections if necessary
232  */
233 int init_child_trusted(int rank)
234 {
235     if ((rank <= 0) && (rank != PROC_RPC) && (rank != PROC_UNIXSOCK))
236                 return 0;
237
238         if (!db_url.s) {
239                 return 0;
240         }
241         
242         db_handle = perm_dbf.init(&db_url);
243         if (!db_handle) {
244             LM_ERR("unable to connect database\n");
245             return -1;
246         }
247
248         if (db_check_table_version(&perm_dbf, db_handle, &trusted_table,
249                                    TABLE_VERSION) < 0) {
250             LM_ERR("error during table version check.\n");
251             perm_dbf.close(db_handle);
252             return -1;
253         }
254
255         return 0;
256 }
257
258
259 /*
260  * Open database connection if necessary
261  */
262 int mi_init_trusted(void)
263 {
264     if (!db_url.s) return 0;
265     db_handle = perm_dbf.init(&db_url);
266     if (!db_handle) {
267         LM_ERR("unable to connect database\n");
268         return -1;
269     }
270     return 0;
271 }
272
273
274 /*
275  * Close connections and release memory
276  */
277 void clean_trusted(void)
278 {
279         if (hash_table_1) free_hash_table(hash_table_1);
280         if (hash_table_2) free_hash_table(hash_table_2);
281         if (hash_table) shm_free(hash_table);
282 }
283
284
285 /*
286  * Matches protocol string against the protocol of the request.  Returns 1 on
287  * success and 0 on failure.
288  */
289 static inline int match_proto(const char *proto_string, int proto_int)
290 {
291         if ((proto_int == PROTO_NONE) ||
292                         (strcasecmp(proto_string, "any") == 0))
293                 return 1;
294         
295         if (proto_int == PROTO_UDP) {
296                 if (strcasecmp(proto_string, "udp") == 0) {
297                         return 1;
298                 } else {
299                         return 0;
300                 }
301         }
302         
303         if (proto_int == PROTO_TCP) {
304                 if (strcasecmp(proto_string, "tcp") == 0) {
305                         return 1;
306                 } else {
307                         return 0;
308                 }
309         }
310         
311         if (proto_int == PROTO_TLS) {
312                 if (strcasecmp(proto_string, "tls") == 0) {
313                         return 1;
314                 } else {
315                         return 0;
316                 }
317         }
318         
319         if (proto_int == PROTO_SCTP) {
320                 if (strcasecmp(proto_string, "sctp") == 0) {
321                         return 1;
322                 } else {
323                         return 0;
324                 }
325         }
326
327         if (proto_int == PROTO_WS) {
328                 if (strcasecmp(proto_string, "ws") == 0) {
329                         return 1;
330                 } else {
331                         return 0;
332                 }
333         }
334         
335         if (proto_int == PROTO_WSS) {
336                 if (strcasecmp(proto_string, "wss") == 0) {
337                         return 1;
338                 } else {
339                         return 0;
340                 }
341         }
342
343         LM_ERR("unknown request protocol\n");
344
345         return 0;
346 }
347
348 /*
349  * Matches from uri against patterns returned from database.  Returns number
350  * of matches or -1 if none of the patterns match.
351  */
352 static int match_res(struct sip_msg* msg, int proto, db1_res_t* _r)
353 {
354         int i, tag_avp_type;
355         str uri;
356         char uri_string[MAX_URI_SIZE+1];
357         db_row_t* row;
358         db_val_t* val;
359         regex_t preg;
360         int_str tag_avp, avp_val;
361         int count = 0;
362
363         if (IS_SIP(msg)) {
364                 if (parse_from_header(msg) < 0) return -1;
365                 uri = get_from(msg)->uri;
366                 if (uri.len > MAX_URI_SIZE) {
367                         LM_ERR("message has From URI too large\n");
368                         return -1;
369                 }
370                 memcpy(uri_string, uri.s, uri.len);
371                 uri_string[uri.len] = (char)0;
372         }
373         get_tag_avp(&tag_avp, &tag_avp_type);
374
375         row = RES_ROWS(_r);
376
377         for(i = 0; i < RES_ROW_N(_r); i++) {
378                 val = ROW_VALUES(row + i);
379                 if ((ROW_N(row + i) == 3) &&
380                     (VAL_TYPE(val) == DB1_STRING) && !VAL_NULL(val) &&
381                     match_proto(VAL_STRING(val), proto) &&
382                     (VAL_NULL(val + 1) ||
383                       ((VAL_TYPE(val + 1) == DB1_STRING) && !VAL_NULL(val + 1))) &&
384                     (VAL_NULL(val + 2) ||
385                       ((VAL_TYPE(val + 2) == DB1_STRING) && !VAL_NULL(val + 2))))
386                 {
387                         if (!VAL_NULL(val + 1) && IS_SIP(msg)) {
388                                 if (regcomp(&preg, (char *)VAL_STRING(val + 1), REG_NOSUB)) {
389                                         LM_ERR("invalid regular expression\n");
390                                         continue;
391                                 }
392                                 if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
393                                         regfree(&preg);
394                                         continue;
395                                 }
396                             regfree(&preg);
397                         }
398                         /* Found a match */
399                         if (tag_avp.n && !VAL_NULL(val + 2)) {
400                                 avp_val.s.s = (char *)VAL_STRING(val + 2);
401                                 avp_val.s.len = strlen(avp_val.s.s);
402                                 if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, avp_val) != 0) {
403                                         LM_ERR("failed to set of tag_avp failed\n");
404                                         return -1;
405                                 }
406                         }
407                         if (!peer_tag_mode) 
408                                 return 1;
409                         count++;
410                 }
411         }
412         if (!count)
413                 return -1;
414         else 
415                 return count;
416 }
417
418
419 /*
420  * Checks based on given source IP address and protocol, and From URI
421  * of request if request can be trusted without authentication.
422  */
423 int allow_trusted(struct sip_msg* msg, char *src_ip, int proto) 
424 {
425         int result;
426         db1_res_t* res = NULL;
427         
428         db_key_t keys[1];
429         db_val_t vals[1];
430         db_key_t cols[3];
431
432         if (db_mode == DISABLE_CACHE) {
433         
434                 if (db_handle == 0) {
435                     LM_ERR("no connection to database\n");
436                     return -1;
437                 }
438
439                 keys[0] = &source_col;
440                 cols[0] = &proto_col;
441                 cols[1] = &from_col;
442                 cols[2] = &tag_col;
443
444                 if (perm_dbf.use_table(db_handle, &trusted_table) < 0) {
445                         LM_ERR("failed to use trusted table\n");
446                         return -1;
447                 }
448                 
449                 VAL_TYPE(vals) = DB1_STRING;
450                 VAL_NULL(vals) = 0;
451                 VAL_STRING(vals) = src_ip;
452
453                 if (perm_dbf.query(db_handle, keys, 0, vals, cols, 1, 3, 0,
454                                    &res) < 0){
455                         LM_ERR("failed to query database\n");
456                         return -1;
457                 }
458
459                 if (RES_ROW_N(res) == 0) {
460                         perm_dbf.free_result(db_handle, res);
461                         return -1;
462                 }
463                 
464                 result = match_res(msg, proto, res);
465                 perm_dbf.free_result(db_handle, res);
466                 return result;
467         } else {
468                 return match_hash_table(*hash_table, msg, src_ip, proto);
469         }
470 }
471
472
473 /*
474  * Checks based on request's source address, protocol, and From URI
475  * if request can be trusted without authentication.
476  */
477 int allow_trusted_0(struct sip_msg* _msg, char* str1, char* str2) 
478 {
479     return allow_trusted(_msg, ip_addr2a(&(_msg->rcv.src_ip)),
480                          _msg->rcv.proto);
481 }
482
483
484 /*
485  * Checks based on source address and protocol given in pvar arguments and
486  * and requests's From URI, if request can be trusted without authentication.
487  */
488 int allow_trusted_2(struct sip_msg* _msg, char* _src_ip_sp, char* _proto_sp) 
489 {
490     str src_ip, proto;
491     int proto_int;
492
493     if (_src_ip_sp==NULL
494         || (fixup_get_svalue(_msg, (gparam_p)_src_ip_sp, &src_ip) != 0)) {
495         LM_ERR("src_ip param does not exist or has no value\n");
496         return -1;
497     }
498     
499     if (_proto_sp==NULL
500         || (fixup_get_svalue(_msg, (gparam_p)_proto_sp, &proto) != 0)) {
501         LM_ERR("proto param does not exist or has no value\n");
502         return -1;
503     }
504
505     if(proto.len!=3 && proto.len!=4)
506         goto error;
507
508     switch(proto.s[0]) {
509     case 'a': case 'A':
510         if (proto.len==3 && strncasecmp(proto.s, "any", 3) == 0) {
511             proto_int = PROTO_NONE;
512         } else goto error;
513         break;
514     case 'u': case 'U':
515         if (proto.len==3 && strncasecmp(proto.s, "udp", 3) == 0) {
516             proto_int = PROTO_UDP;
517         } else goto error;
518         break;
519     case 't': case 'T':
520         if (proto.len==3 && strncasecmp(proto.s, "tcp", 3) == 0) {
521             proto_int = PROTO_TCP;
522         } else if (proto.len==3 && strncasecmp(proto.s, "tls", 3) == 0) {
523             proto_int = PROTO_TLS;
524         } else goto error;
525         break;
526     case 's': case 'S':
527         if (proto.len==4 && strncasecmp(proto.s, "sctp", 4) == 0) {
528             proto_int = PROTO_SCTP;
529         } else goto error;
530         break;
531     case 'w': case 'W':
532         if (proto.len==2 && strncasecmp(proto.s, "ws", 2) == 0) {
533             proto_int = PROTO_WS;
534         } else if (proto.len==3 && strncasecmp(proto.s, "wss", 3) == 0) {
535             proto_int = PROTO_WSS;
536         } else goto error;
537         break;
538     default:
539         goto error;
540     }
541
542     return allow_trusted(_msg, src_ip.s, proto_int);
543 error:
544     LM_ERR("unknown protocol %.*s\n", proto.len, proto.s);
545     return -1;
546 }
547