utils/xcap_auth.c

Go to the documentation of this file.
00001 /*
00002  * xcap_auth.c
00003  *
00004  * Copyright (C) 2007 Voice Sistem S.R.L.
00005  *
00006  * Copyright (C) 2009 Juha Heinanen
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  * History:
00025  * --------
00026  *  2007-04-11  initial version (anca)
00027  *  2009-06-03  util version (jh)
00028  */
00029 
00037 #include <stdio.h>
00038 #include <stdlib.h>
00039 #include <string.h>
00040 #include <time.h>
00041 #include <libxml/parser.h>
00042 
00043 #include "../../str.h"
00044 #include "../../dprint.h"
00045 #include "../../pvar.h"
00046 #include "../../parser/parse_uri.h"
00047 #include "../../modules_k/presence/subscribe.h"
00048 #include "../../modules_k/presence/utils_func.h"
00049 #include "../../modules_k/presence/hash.h"
00050 #include "../../modules_k/xcap_client/xcap_callbacks.h"
00051 #include "utils.h"
00052 #include "pidf.h"
00053 
00054 xmlNodePtr get_rule_node(subs_t* subs, xmlDocPtr xcap_tree)
00055 {
00056     str w_uri = {0, 0};
00057     char* id = NULL, *domain = NULL, *time_cont= NULL;
00058     int apply_rule = -1;
00059     xmlNodePtr ruleset_node = NULL, node1= NULL, node2= NULL;
00060     xmlNodePtr cond_node = NULL, except_node = NULL;
00061     xmlNodePtr identity_node = NULL;
00062     xmlNodePtr iden_child;
00063     xmlNodePtr validity_node, time_node;
00064     time_t t_init, t_fin, t;
00065     int valid= 0;
00066 
00067     uandd_to_uri(subs->from_user, subs->from_domain, &w_uri);
00068     if (w_uri.s == NULL) {
00069         LM_ERR("while creating uri\n");
00070         return NULL;
00071     }
00072     ruleset_node = xmlDocGetNodeByName(xcap_tree, "ruleset", NULL);
00073     if (ruleset_node == NULL) {
00074         LM_DBG("ruleset_node NULL\n");
00075         goto error;
00076     }   
00077     for (node1 = ruleset_node->children; node1; node1 = node1->next) {
00078         if (xmlStrcasecmp(node1->name, (unsigned char*)"text") == 0)
00079             continue;
00080 
00081         /* process conditions */
00082         LM_DBG("node1->name= %s\n", node1->name);
00083         
00084         cond_node = xmlNodeGetChildByName(node1, "conditions");
00085         if(cond_node == NULL) {
00086             LM_DBG("cond node NULL\n");
00087             goto error;
00088         }
00089         LM_DBG("cond_node->name= %s\n", cond_node->name);
00090 
00091         validity_node = xmlNodeGetChildByName(cond_node, "validity");
00092         if (validity_node != NULL) {
00093             LM_DBG("found validity tag\n");
00094             
00095             t= time(NULL);
00096                 
00097             /* search all from-until pair */
00098             for (time_node = validity_node->children; time_node;
00099                 time_node = time_node->next) {
00100                 if (xmlStrcasecmp(time_node->name, (unsigned char*)"from")!= 0)
00101                     continue;
00102 
00103                 time_cont= (char*)xmlNodeGetContent(time_node);
00104                 t_init= xml_parse_dateTime(time_cont);
00105                 xmlFree(time_cont);
00106                 if (t_init< 0) {
00107                     LM_ERR("failed to parse xml dateTime\n");
00108                     goto error;
00109                 }
00110 
00111                 if (t< t_init) {
00112                     LM_DBG("the lower time limit is not respected\n");
00113                     continue;
00114                 }
00115                                 
00116                 time_node= time_node->next;
00117                 while (1) {
00118                     if (time_node == NULL) {
00119                         LM_ERR("bad formatted xml doc:until child not found in"
00120                                " validity pair\n");
00121                         goto error;
00122                     }
00123                     if( xmlStrcasecmp(time_node->name, 
00124                                       (unsigned char*)"until")== 0)
00125                         break;
00126                     time_node= time_node->next;
00127                 }
00128                                 
00129                 time_cont = (char*)xmlNodeGetContent(time_node);
00130                 t_fin= xml_parse_dateTime(time_cont);
00131                 xmlFree(time_cont);
00132                 
00133                 if (t_fin< 0) {
00134                     LM_ERR("failed to parse xml dateTime\n");
00135                     goto error;
00136                 }
00137                         
00138                 if (t <= t_fin) {
00139                     LM_DBG("the rule is active at this time\n");
00140                     valid= 1;
00141                 }
00142                         
00143             }
00144                 
00145             if (!valid) {
00146                 LM_DBG("the rule is not active at this time\n");
00147                 continue;
00148             }
00149             
00150         }       
00151 
00152         identity_node = xmlNodeGetChildByName(cond_node, "identity");
00153         if (identity_node == NULL) {
00154             LM_ERR("didn't find identity tag\n");
00155             goto error;
00156         }       
00157                 
00158         iden_child = xmlNodeGetChildByName(identity_node, "one");
00159         if(iden_child) {
00160             for (node2 = identity_node->children; node2; node2 = node2->next) {
00161                 if(xmlStrcasecmp(node2->name, (unsigned char*)"one")!= 0)
00162                     continue;
00163                                 
00164                 id = xmlNodeGetAttrContentByName(node2, "id");  
00165                 if(id== NULL) {
00166                     LM_ERR("while extracting attribute\n");
00167                     goto error;
00168                 }
00169                 if ((strlen(id)== w_uri.len && 
00170                      (strncmp(id, w_uri.s, w_uri.len)==0))) {
00171                     apply_rule = 1;
00172                     xmlFree(id);
00173                     break;
00174                 }
00175                 xmlFree(id);
00176             }
00177         }       
00178 
00179         /* search for many node*/
00180         iden_child = xmlNodeGetChildByName(identity_node, "many");
00181         if (iden_child) {
00182             domain = NULL;
00183             for (node2 = identity_node->children; node2; node2 = node2->next) {
00184                 if (xmlStrcasecmp(node2->name, (unsigned char*)"many") != 0)
00185                     continue;
00186         
00187                 domain = xmlNodeGetAttrContentByName(node2, "domain");
00188                 if(domain == NULL) {
00189                     LM_DBG("No domain attribute to many\n");
00190                 } else  {
00191                     LM_DBG("<many domain= %s>\n", domain);
00192                     if((strlen(domain)!= subs->from_domain.len && 
00193                         strncmp(domain, subs->from_domain.s,
00194                                 subs->from_domain.len) )) {
00195                         xmlFree(domain);
00196                         continue;
00197                     }   
00198                 }
00199                 xmlFree(domain);
00200                 apply_rule = 1;
00201                 if (node2->children == NULL)       /* there is no exception */
00202                     break;
00203 
00204                 for (except_node = node2->children; except_node;
00205                      except_node= except_node->next) {
00206                     if(xmlStrcasecmp(except_node->name,
00207                                      (unsigned char*)"except"))
00208                         continue;
00209 
00210                     id = xmlNodeGetAttrContentByName(except_node, "id");        
00211                     if (id != NULL) {
00212                         if((strlen(id)- 1== w_uri.len && 
00213                             (strncmp(id, w_uri.s, w_uri.len)==0))) {
00214                             xmlFree(id);
00215                             apply_rule = 0;
00216                             break;
00217                         }
00218                         xmlFree(id);
00219                     } else {
00220                         domain = NULL;
00221                         domain = xmlNodeGetAttrContentByName(except_node,
00222                                                              "domain");
00223                         if(domain!=NULL) {
00224                             LM_DBG("Found except domain= %s\n- strlen(domain)= %d\n",
00225                                    domain, (int)strlen(domain));
00226                             if (strlen(domain)==subs->from_domain.len &&
00227                                 (strncmp(domain,subs->from_domain.s ,
00228                                          subs->from_domain.len)==0)) {
00229                                 LM_DBG("except domain match\n");
00230                                 xmlFree(domain);
00231                                 apply_rule = 0;
00232                                 break;
00233                             }
00234                             xmlFree(domain);
00235                         }       
00236                     }   
00237                 }
00238                 if (apply_rule == 1)  /* if a match was found no need to keep searching*/
00239                     break;
00240             }
00241         }
00242         if (apply_rule ==1)
00243             break;
00244     }
00245 
00246     LM_DBG("apply_rule= %d\n", apply_rule);
00247     if(w_uri.s!=NULL)
00248         pkg_free(w_uri.s);
00249 
00250     if( !apply_rule || !node1)
00251         return NULL;
00252     
00253     return node1;
00254 
00255  error:
00256     if(w_uri.s)
00257         pkg_free(w_uri.s);
00258     return NULL;
00259 }
00260 
00261 int pres_watcher_allowed(subs_t* subs)
00262 {
00263     xmlDocPtr xcap_tree= NULL;
00264     xmlNodePtr node= NULL,  actions_node = NULL;
00265     xmlNodePtr sub_handling_node = NULL;
00266     char* sub_handling = NULL;
00267         
00268     subs->status= PENDING_STATUS;
00269     subs->reason.s= NULL;
00270     subs->reason.len= 0;
00271 
00272     if (subs->auth_rules_doc== NULL)
00273         return 0;
00274 
00275     xcap_tree= xmlParseMemory(subs->auth_rules_doc->s,
00276                               subs->auth_rules_doc->len);
00277     if (xcap_tree== NULL) {
00278         LM_ERR("parsing xml memory\n");
00279         return -1;
00280     }
00281 
00282     node= get_rule_node(subs, xcap_tree);
00283     if (node== NULL) {
00284         xmlFreeDoc(xcap_tree);
00285         return 0;
00286         }
00287 
00288     /* process actions */       
00289     actions_node = xmlNodeGetChildByName(node, "actions");
00290     if (actions_node == NULL) {
00291         LM_DBG("actions_node NULL\n");
00292         xmlFreeDoc(xcap_tree);
00293         return 0;
00294     }
00295     LM_DBG("actions_node->name= %s\n", actions_node->name);
00296                         
00297     sub_handling_node = xmlNodeGetChildByName(actions_node, "sub-handling");
00298     if (sub_handling_node== NULL) {
00299         LM_DBG("sub_handling_node NULL\n");
00300         xmlFreeDoc(xcap_tree);
00301         return 0;
00302     }
00303     sub_handling = (char*)xmlNodeGetContent(sub_handling_node);
00304     LM_DBG("sub_handling_node->name= %s\n", sub_handling_node->name);
00305     LM_DBG("sub_handling_node->content= %s\n", sub_handling);
00306         
00307     if (sub_handling == NULL) {
00308         LM_ERR("Couldn't get sub-handling content\n");
00309         xmlFreeDoc(xcap_tree);
00310         return -1;
00311     }
00312     if (strncmp((char*)sub_handling, "block", 5) == 0) {
00313         subs->status = TERMINATED_STATUS;;
00314         subs->reason.s= "rejected";
00315         subs->reason.len = 8;
00316     } else      
00317         if (strncmp((char*)sub_handling, "confirm", 7) == 0) {
00318             subs->status = PENDING_STATUS;
00319         } else
00320             if (strncmp((char*)sub_handling , "polite-block", 12) == 0) {
00321                 subs->status = ACTIVE_STATUS;
00322                 subs->reason.s= "polite-block";
00323                 subs->reason.len = 12;
00324             }
00325         else
00326             if (strncmp((char*)sub_handling, "allow", 5) == 0) {
00327                 subs->status = ACTIVE_STATUS;
00328                 subs->reason.s = NULL;
00329             }
00330             else {
00331                 LM_ERR("unknown subscription handling action\n");
00332                 xmlFreeDoc(xcap_tree);
00333                 xmlFree(sub_handling);
00334                 return -1;
00335             }
00336 
00337         xmlFreeDoc(xcap_tree);
00338     xmlFree(sub_handling);
00339 
00340     return 0;
00341 
00342 }
00343 
00344 int get_rules_doc(str* user, str* domain, int type, str** rules_doc)
00345 {
00346     db_key_t query_cols[5];
00347     db_val_t query_vals[5];
00348     db_key_t result_cols[3];
00349     int n_query_cols = 0;
00350     db1_res_t *result = 0;
00351     db_row_t *row;
00352     db_val_t *row_vals;
00353     str body;
00354     str* doc= NULL;
00355     int n_result_cols= 0, xcap_doc_col;
00356     static str tmp1 = str_init("username");
00357     static str tmp2 = str_init("domain");
00358     static str tmp3 = str_init("doc_type");
00359     static str tmp4 = str_init("doc");
00360 
00361     LM_DBG("[user]= %.*s\t[domain]= %.*s", 
00362            user->len, user->s, domain->len, domain->s);
00363 
00364     query_cols[n_query_cols] = &tmp1;
00365     query_vals[n_query_cols].type = DB1_STR;
00366     query_vals[n_query_cols].nul = 0;
00367     query_vals[n_query_cols].val.str_val = *user;
00368     n_query_cols++;
00369     
00370     query_cols[n_query_cols] = &tmp2;
00371     query_vals[n_query_cols].type = DB1_STR;
00372     query_vals[n_query_cols].nul = 0;
00373     query_vals[n_query_cols].val.str_val = *domain;
00374     n_query_cols++;
00375     
00376     query_cols[n_query_cols] = &tmp3;
00377     query_vals[n_query_cols].type = DB1_INT;
00378     query_vals[n_query_cols].nul = 0;
00379     query_vals[n_query_cols].val.int_val= type;
00380     n_query_cols++;
00381 
00382     result_cols[xcap_doc_col= n_result_cols++] = &tmp4;
00383 
00384     if (pres_dbf.query(pres_dbh, query_cols, 0 , query_vals, result_cols, 
00385                        n_query_cols, 1, 0, &result) < 0) {
00386         LM_ERR("while querying table xcap for [user]=%.*s\t[domain]= %.*s\n",
00387                user->len, user->s, domain->len, domain->s);
00388         if (result)
00389             pres_dbf.free_result(pres_dbh, result);
00390         return -1;
00391     }
00392 
00393     if(result == NULL)
00394         return -1;
00395 
00396     if (result->n <= 0) {
00397         LM_DBG("No document found in db table for [user]=%.*s"
00398                "\t[domain]= %.*s\t[doc_type]= %d\n",user->len, user->s,
00399                domain->len, domain->s, type);
00400         pres_dbf.free_result(pres_dbh, result);
00401         return 0;
00402     }   
00403         
00404     row = &result->rows[xcap_doc_col];
00405     row_vals = ROW_VALUES(row);
00406 
00407     body.s = (char*)row_vals[0].val.string_val;
00408     if (body.s== NULL) {
00409         LM_ERR("Xcap doc NULL\n");
00410         goto error;
00411     }   
00412     body.len = strlen(body.s);
00413     if (body.len== 0) {
00414         LM_ERR("Xcap doc empty\n");
00415         goto error;
00416     }                   
00417     LM_DBG("xcap document:\n%.*s", body.len,body.s);
00418     
00419     doc= (str*)pkg_malloc(sizeof(str));
00420     if (doc== NULL) {
00421         ERR_MEM(PKG_MEM_STR);
00422     }
00423     doc->s= (char*)pkg_malloc(body.len* sizeof(char));
00424     if (doc->s== NULL) {
00425         pkg_free(doc);
00426         ERR_MEM(PKG_MEM_STR);
00427     }
00428     memcpy(doc->s, body.s, body.len);
00429     doc->len= body.len;
00430 
00431     *rules_doc= doc;
00432 
00433     if (result)
00434         pres_dbf.free_result(pres_dbh, result);
00435 
00436     return 0;
00437 
00438 error:
00439     if (result)
00440         pres_dbf.free_result(pres_dbh, result);
00441 
00442     return -1;
00443 
00444 }
00445 
00446 
00447 /* 
00448  * Checks from presence server xcap table if watcher is authorized
00449  * to subscribe event 'presence' of presentity.
00450  */
00451 int xcap_auth_status(struct sip_msg* _msg, char* _sp1, char* _sp2)
00452 {
00453     pv_spec_t *sp;
00454     pv_value_t pv_val;
00455     str watcher_uri, presentity_uri;
00456     struct sip_uri uri;
00457     str* rules_doc = NULL;
00458     subs_t subs;
00459     int res;
00460 
00461     if (pres_dbh == 0) {
00462         LM_ERR("function is disabled, to enable define pres_db_url\n");
00463         return -1;
00464     }
00465 
00466     sp = (pv_spec_t *)_sp1;
00467 
00468     if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) {
00469         if (pv_val.flags & PV_VAL_STR) {
00470             watcher_uri = pv_val.rs;
00471             if (watcher_uri.len == 0 || watcher_uri.s == NULL) {
00472                 LM_ERR("missing watcher uri\n");
00473                 return -1;
00474             }
00475         } else {
00476             LM_ERR("watcher pseudo variable value is not string\n");
00477             return -1;
00478         }
00479     } else {
00480         LM_ERR("cannot get watcher pseudo variable value\n");
00481         return -1;
00482     }
00483 
00484     sp = (pv_spec_t *)_sp2;
00485 
00486     if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) {
00487         if (pv_val.flags & PV_VAL_STR) {
00488             presentity_uri = pv_val.rs;
00489             if (presentity_uri.len == 0 || presentity_uri.s == NULL) {
00490                 LM_DBG("missing presentity uri\n");
00491                 return -1;
00492             }
00493         } else {
00494             LM_ERR("presentity pseudo variable value is not string\n");
00495             return -1;
00496         }
00497     } else {
00498         LM_ERR("cannot get presentity pseudo variable value\n");
00499         return -1;
00500     }
00501 
00502     if (parse_uri(presentity_uri.s, presentity_uri.len, &uri) < 0) {
00503         LM_ERR("failed to parse presentity uri\n");
00504         return -1;
00505     }
00506     res = get_rules_doc(&uri.user, &uri.host, PRES_RULES, &rules_doc);
00507     if ((res < 0) || (rules_doc == NULL) || (rules_doc->s == NULL)) {
00508         LM_DBG("no xcap rules doc found for presentity uri\n");
00509         return PENDING_STATUS;
00510     }
00511 
00512     if (parse_uri(watcher_uri.s, watcher_uri.len, &uri) < 0) {
00513         LM_ERR("failed to parse watcher uri\n");
00514         goto err;
00515     }
00516 
00517     subs.from_user = uri.user;
00518     subs.from_domain = uri.host;
00519     subs.pres_uri = presentity_uri;
00520     subs.auth_rules_doc = rules_doc;
00521     if (pres_watcher_allowed(&subs) < 0) {
00522         LM_ERR("getting status from rules document\n");
00523         goto err;
00524     }
00525     LM_DBG("auth status of watcher <%.*s> on presentity <%.*s> is %d\n",
00526            watcher_uri.len, watcher_uri.s, presentity_uri.len, presentity_uri.s,
00527            subs.status);
00528     pkg_free(rules_doc->s);
00529     pkg_free(rules_doc);
00530     return subs.status;
00531 
00532  err:
00533     pkg_free(rules_doc->s);
00534     pkg_free(rules_doc);
00535     return -1;
00536 }