4 * Copyright (C) 2007 Voice Sistem S.R.L.
6 * This file is part of Kamailio, a free SIP server.
8 * Kamailio is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version
13 * Kamailio is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 * \brief Kamailio Presence_XML :: XCAP authentication
26 * \ingroup presence_xml
34 #include <libxml/parser.h>
36 #include "../../core/str.h"
37 #include "../../core/dprint.h"
38 #include "../../core/parser/parse_uri.h"
39 #include "../presence/utils_func.h"
40 #include "../presence/hash.h"
41 #include "presence_xml.h"
42 #include "xcap_auth.h"
45 extern str xcapauth_userdel_reason;
47 int http_get_rules_doc(str user, str domain, str *rules_doc);
49 int pres_watcher_allowed(subs_t *subs)
51 xmlDocPtr xcap_tree = NULL;
52 xmlNodePtr node = NULL, actions_node = NULL;
53 xmlNodePtr sub_handling_node = NULL;
54 char *sub_handling = NULL;
57 /* if force_active set status to active*/
59 subs->status = ACTIVE_STATUS;
60 subs->reason.s = NULL;
65 if(subs->auth_rules_doc == NULL) {
66 subs->status = PENDING_STATUS;
67 subs->reason.s = NULL;
73 xmlParseMemory(subs->auth_rules_doc->s, subs->auth_rules_doc->len);
74 if(xcap_tree == NULL) {
75 LM_ERR("parsing xml memory\n");
79 node = get_rule_node(subs, xcap_tree);
81 /* if no rule node was found and the previous state was active -> set the
82 * state to terminated with reason xcapauth_userdel_reason (default "probation") */
83 if(subs->status != PENDING_STATUS) {
84 subs->status = TERMINATED_STATUS;
85 subs->reason = xcapauth_userdel_reason;
90 subs->status = PENDING_STATUS;
91 subs->reason.s = NULL;
95 actions_node = xmlNodeGetChildByName(node, "actions");
96 if(actions_node == NULL) {
97 LM_DBG("actions_node NULL\n");
100 LM_DBG("actions_node->name= %s\n", actions_node->name);
102 sub_handling_node = xmlNodeGetChildByName(actions_node, "sub-handling");
103 if(sub_handling_node == NULL) {
104 LM_DBG("sub_handling_node NULL\n");
107 sub_handling = (char *)xmlNodeGetContent(sub_handling_node);
108 LM_DBG("sub_handling_node->name= %s\n", sub_handling_node->name);
109 LM_DBG("sub_handling_node->content= %s\n", sub_handling);
111 if(sub_handling == NULL) {
112 LM_ERR("Couldn't get sub-handling content\n");
116 if(strncmp((char *)sub_handling, "block", 5) == 0) {
117 subs->status = TERMINATED_STATUS;
118 subs->reason.s = "rejected";
119 subs->reason.len = 8;
120 } else if(strncmp((char *)sub_handling, "confirm", 7) == 0) {
121 subs->status = PENDING_STATUS;
122 } else if(strncmp((char *)sub_handling, "polite-block", 12) == 0) {
123 subs->status = ACTIVE_STATUS;
124 subs->reason.s = "polite-block";
125 subs->reason.len = 12;
126 } else if(strncmp((char *)sub_handling, "allow", 5) == 0) {
127 subs->status = ACTIVE_STATUS;
129 LM_ERR("unknown subscription handling action\n");
135 xmlFree(sub_handling);
136 xmlFreeDoc(xcap_tree);
140 xmlNodePtr get_rule_node(subs_t *subs, xmlDocPtr xcap_tree)
143 char *id = NULL, *domain = NULL, *time_cont = NULL;
145 xmlNodePtr ruleset_node = NULL, node1 = NULL, node2 = NULL;
146 xmlNodePtr cond_node = NULL, except_node = NULL;
147 xmlNodePtr identity_node = NULL, sphere_node = NULL;
148 xmlNodePtr iden_child;
149 xmlNodePtr validity_node, time_node;
150 time_t t_init, t_fin, t;
154 uandd_to_uri(subs->watcher_user, subs->watcher_domain, &w_uri);
155 if(w_uri.s == NULL) {
156 LM_ERR("while creating uri\n");
159 ruleset_node = xmlDocGetNodeByName(xcap_tree, "ruleset", NULL);
160 if(ruleset_node == NULL) {
161 LM_DBG("ruleset_node NULL\n");
164 for(node1 = ruleset_node->children; node1; node1 = node1->next) {
165 if(xmlStrcasecmp(node1->name, (unsigned char *)"text") == 0)
168 /* process conditions */
169 LM_DBG("node1->name= %s\n", node1->name);
171 cond_node = xmlNodeGetChildByName(node1, "conditions");
172 if(cond_node == NULL) {
173 LM_DBG("cond node NULL\n");
176 LM_DBG("cond_node->name= %s\n", cond_node->name);
178 validity_node = xmlNodeGetChildByName(cond_node, "validity");
179 if(validity_node != NULL) {
180 LM_DBG("found validity tag\n");
184 /* search all from-until pair */
185 for(time_node = validity_node->children; time_node;
186 time_node = time_node->next) {
187 if(xmlStrcasecmp(time_node->name, (unsigned char *)"from")
191 time_cont = (char *)xmlNodeGetContent(time_node);
192 t_init = xml_parse_dateTime(time_cont);
195 LM_ERR("failed to parse xml dateTime\n");
200 LM_DBG("the lower time limit is not respected\n");
204 time_node = time_node->next;
206 if(time_node == NULL) {
207 LM_ERR("bad formatted xml doc:until child not found in"
211 if(xmlStrcasecmp(time_node->name, (unsigned char *)"until")
214 time_node = time_node->next;
217 time_cont = (char *)xmlNodeGetContent(time_node);
218 t_fin = xml_parse_dateTime(time_cont);
222 LM_ERR("failed to parse xml dateTime\n");
227 LM_DBG("the rule is active at this time\n");
233 LM_DBG("the rule is not active at this time\n");
238 sphere_node = xmlNodeGetChildByName(cond_node, "sphere");
239 if(sphere_node != NULL) {
240 /* check to see if matches presentity current sphere */
241 /* ask presence for sphere information */
243 char *sphere = psapi.get_sphere(&subs->pres_uri);
245 char *attr = (char *)xmlNodeGetContent(sphere_node);
246 if(xmlStrcasecmp((unsigned char *)attr, (unsigned char *)sphere)
248 LM_DBG("sphere condition not respected\n");
257 /* if the user has not define a sphere ->
258 * consider the condition true*/
261 identity_node = xmlNodeGetChildByName(cond_node, "identity");
262 if(identity_node == NULL) {
263 LM_WARN("didn't find identity tag\n");
267 iden_child = xmlNodeGetChildByName(identity_node, "one");
269 for(node2 = identity_node->children; node2; node2 = node2->next) {
270 if(xmlStrcasecmp(node2->name, (unsigned char *)"one") != 0)
273 id = xmlNodeGetAttrContentByName(node2, "id");
275 LM_ERR("while extracting attribute\n");
278 if((strlen(id) == w_uri.len
279 && (strncmp(id, w_uri.s, w_uri.len) == 0))) {
288 /* search for many node*/
289 iden_child = xmlNodeGetChildByName(identity_node, "many");
292 for(node2 = identity_node->children; node2; node2 = node2->next) {
293 if(xmlStrcasecmp(node2->name, (unsigned char *)"many") != 0)
296 domain = xmlNodeGetAttrContentByName(node2, "domain");
298 LM_DBG("No domain attribute to many\n");
300 LM_DBG("<many domain= %s>\n", domain);
301 if((strlen(domain) != subs->from_domain.len
302 && strncmp(domain, subs->from_domain.s,
303 subs->from_domain.len))) {
310 if(node2->children == NULL) /* there is no exception */
313 for(except_node = node2->children; except_node;
314 except_node = except_node->next) {
316 except_node->name, (unsigned char *)"except"))
319 id = xmlNodeGetAttrContentByName(except_node, "id");
321 if((strlen(id) - 1 == w_uri.len
322 && (strncmp(id, w_uri.s, w_uri.len) == 0))) {
330 domain = xmlNodeGetAttrContentByName(
331 except_node, "domain");
333 LM_DBG("Found except domain= %s\n- strlen(domain)= "
335 domain, (int)strlen(domain));
336 if(strlen(domain) == subs->from_domain.len
337 && (strncmp(domain, subs->from_domain.s,
338 subs->from_domain.len)
340 LM_DBG("except domain match\n");
350 == 1) /* if a match was found no need to keep searching*/
358 LM_DBG("apply_rule= %d\n", apply_rule);
362 if(!apply_rule || !node1)
373 int pres_get_rules_doc(str *user, str *domain, str **rules_doc)
376 return get_rules_doc(user, domain, NULL, PRES_RULES, rules_doc);
379 int pres_get_pidf_doc(str *user, str *domain, str *file_uri, str **rules_doc)
381 return get_rules_doc(user, domain, file_uri, PIDF_MANIPULATION, rules_doc);
385 str *user, str *domain, str *file_uri, int type, str **rules_doc)
387 db_key_t query_cols[3];
388 db_val_t query_vals[3];
389 db_key_t result_cols[1];
390 int n_query_cols = 0;
391 db1_res_t *result = 0;
396 int n_result_cols = 0, xcap_doc_col;
397 static str tmp1 = str_init("doc_type");
398 static str tmp2 = str_init("doc_uri");
399 static str tmp3 = str_init("username");
400 static str tmp4 = str_init("domain");
401 static str tmp5 = str_init("doc");
407 LM_DBG("[user]= %.*s\t[domain]= %.*s", user->len, user->s, domain->len,
410 /* first search in database */
411 query_cols[n_query_cols] = &tmp1;
412 query_vals[n_query_cols].type = DB1_INT;
413 query_vals[n_query_cols].nul = 0;
414 query_vals[n_query_cols].val.int_val = type;
417 if(file_uri != NULL) {
418 query_cols[n_query_cols] = &tmp2;
419 query_vals[n_query_cols].type = DB1_STR;
420 query_vals[n_query_cols].nul = 0;
421 query_vals[n_query_cols].val.str_val = *file_uri;
423 } else if(user != NULL && domain != NULL) {
424 query_cols[n_query_cols] = &tmp3;
425 query_vals[n_query_cols].type = DB1_STR;
426 query_vals[n_query_cols].nul = 0;
427 query_vals[n_query_cols].val.str_val = *user;
430 query_cols[n_query_cols] = &tmp4;
431 query_vals[n_query_cols].type = DB1_STR;
432 query_vals[n_query_cols].nul = 0;
433 query_vals[n_query_cols].val.str_val = *domain;
436 LM_ERR("Need to specify file uri _OR_ username and domain\n");
440 result_cols[xcap_doc_col = n_result_cols++] = &tmp5;
442 if(pxml_dbf.use_table(pxml_db, &xcap_table) < 0) {
443 LM_ERR("in use_table-[table]= %.*s\n", xcap_table.len, xcap_table.s);
447 if(pxml_dbf.query(pxml_db, query_cols, 0, query_vals, result_cols,
448 n_query_cols, 1, 0, &result)
450 LM_ERR("while querying table xcap for [user]=%.*s\t[domain]= %.*s\n",
451 user->len, user->s, domain->len, domain->s);
453 pxml_dbf.free_result(pxml_db, result);
460 LM_DBG("No document found in db table for [user]=%.*s"
461 "\t[domain]= %.*s\t[doc_type]= %d\n",
462 user->len, user->s, domain->len, domain->s, type);
464 if(!integrated_xcap_server && type != PRES_RULES) {
465 LM_WARN("Cannot retrieve non pres-rules documents from"
466 "external XCAP server\n");
467 } else if(!integrated_xcap_server) {
468 if(http_get_rules_doc(*user, *domain, &body) < 0) {
469 LM_ERR("sending http GET request to xcap server\n");
472 if(body.s && body.len)
475 pxml_dbf.free_result(pxml_db, result);
479 row = &result->rows[xcap_doc_col];
480 row_vals = ROW_VALUES(row);
482 body.s = (char *)row_vals[0].val.string_val;
484 LM_ERR("Xcap doc NULL\n");
487 body.len = strlen(body.s);
489 LM_ERR("Xcap doc empty\n");
492 LM_DBG("xcap document:\n%.*s", body.len, body.s);
495 doc = (str *)pkg_malloc(sizeof(str));
497 ERR_MEM(PKG_MEM_STR);
499 doc->s = (char *)pkg_malloc(body.len * sizeof(char));
502 ERR_MEM(PKG_MEM_STR);
504 memcpy(doc->s, body.s, body.len);
510 pxml_dbf.free_result(pxml_db, result);
516 pxml_dbf.free_result(pxml_db, result);
521 int http_get_rules_doc(str user, str domain, str *rules_doc)
524 xcap_doc_sel_t doc_sel;
529 memset(&req, 0, sizeof(xcap_get_req_t));
530 if(uandd_to_uri(user, domain, &uri) < 0) {
531 LM_ERR("constructing uri\n");
535 doc_sel.auid.s = "pres-rules";
536 doc_sel.auid.len = strlen("pres-rules");
537 doc_sel.doc_type = PRES_RULES;
538 doc_sel.type = USERS_TYPE;
540 doc_sel.filename.s = "index";
541 doc_sel.filename.len = 5;
543 /* need the whole document so the node selector is NULL */
544 /* don't know which is the authoritative server for the user
545 * so send request to all in the list */
546 req.doc_sel = doc_sel;
550 req.xcap_root = xs->addr;
552 doc = xcap_GetNewDoc(req, user, domain);
559 rules_doc->len = doc ? strlen(doc) : 0;