all: updated FSF address in GPL text
[sip-router] / modules / ims_icscf / registration.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2012 Smile Communications, jason.penton@smilecoms.com
5  * Copyright (C) 2012 Smile Communications, richard.good@smilecoms.com
6  * 
7  * The initial version of this code was written by Dragos Vingarzan
8  * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
9  * Fruanhofer Institute. It was and still is maintained in a separate
10  * branch of the original SER. We are therefore migrating it to
11  * Kamailio/SR and look forward to maintaining it from here on out.
12  * 2011/2012 Smile Communications, Pty. Ltd.
13  * ported/maintained/improved by 
14  * Jason Penton (jason(dot)penton(at)smilecoms.com and
15  * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
16  * effort to add full IMS support to Kamailio/SR using a new and
17  * improved architecture
18  * 
19  * NB: Alot of this code was originally part of OpenIMSCore,
20  * FhG Fokus. 
21  * Copyright (C) 2004-2006 FhG Fokus
22  * Thanks for great work! This is an effort to 
23  * break apart the various CSCF functions into logically separate
24  * components. We hope this will drive wider use. We also feel
25  * that in this way the architecture is more complete and thereby easier
26  * to manage in the Kamailio/SR environment
27  *
28  * This file is part of Kamailio, a free SIP server.
29  *
30  * Kamailio is free software; you can redistribute it and/or modify
31  * it under the terms of the GNU General Public License as published by
32  * the Free Software Foundation; either version 2 of the License, or
33  * (at your option) any later version
34  *
35  * Kamailio is distributed in the hope that it will be useful,
36  * but WITHOUT ANY WARRANTY; without even the implied warranty of
37  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38  * GNU General Public License for more details.
39  *
40  * You should have received a copy of the GNU General Public License 
41  * along with this program; if not, write to the Free Software 
42  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
43  * 
44  */
45
46
47 #include "registration.h"
48 #include "../../action.h" /* run_actions */
49 #include "../../mod_fix.h"
50 #include "cxdx_uar.h"
51
52 extern int route_uar_user_unknown_no;
53
54 /**
55  * Perform User Authorization Request.
56  * creates and send the user authorization query
57  * @param msg - the SIP message
58  * @returns true if OK, false if not
59  */
60 int I_perform_user_authorization_request(struct sip_msg* msg, char* route, char* str1, char* str2) {
61     str private_identity, public_identity, visited_network_id;
62     int authorization_type = AVP_IMS_UAR_REGISTRATION;
63     int expires = 3600;
64     struct hdr_field *hdr;
65     str realm;
66     contact_t *c;
67     int sos_reg = 0;
68     contact_body_t *b = 0;
69     str call_id;
70     saved_uar_transaction_t* saved_t;
71     tm_cell_t *t = 0;
72     int intvalue_param;
73     cfg_action_t* cfg_action;
74     
75     str route_name;
76
77     if (fixup_get_ivalue(msg, (gparam_t*) str1, &intvalue_param) != 0) {
78         LM_ERR("no int value param passed\n");
79         return CSCF_RETURN_ERROR;
80     }
81     if (fixup_get_svalue(msg, (gparam_t*) route, &route_name) != 0) {
82         LM_ERR("no async route block for assign_server_unreg\n");
83         return -1;
84     }
85     
86     LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s);
87     int ri = route_get(&main_rt, route_name.s);
88     if (ri < 0) {
89         LM_ERR("unable to find route block [%.*s]\n", route_name.len, route_name.s);
90         return -1;
91     }
92     cfg_action = main_rt.rlist[ri];
93     if (cfg_action == NULL) {
94         LM_ERR("empty action lists in route block [%.*s]\n", route_name.len, route_name.s);
95         return -1;
96     }
97
98
99     realm = cscf_get_realm_from_ruri(msg);
100
101     //check if we received what we should, we do this even though it should be done in cfg file - double checking!
102     if (msg->first_line.type != SIP_REQUEST) {
103         LM_ERR("ERR:I_UAR: The message is not a request\n");
104         return CSCF_RETURN_ERROR;
105     }
106     if (msg->first_line.u.request.method.len != 8 ||
107             memcmp(msg->first_line.u.request.method.s, "REGISTER", 8) != 0) {
108         LM_ERR("ERR:I_UAR: The method is not a REGISTER\n");
109         return CSCF_RETURN_ERROR;
110     }
111
112     private_identity = cscf_get_private_identity(msg, realm);
113     if (!private_identity.len) {
114         LM_ERR("ERR:I_UAR: Private Identity not found, responding with 400\n");
115         cscf_reply_transactional(msg, 400, MSG_400_NO_PRIVATE);
116         return CSCF_RETURN_BREAK;
117     }
118
119     public_identity = cscf_get_public_identity(msg);
120     if (!public_identity.len) {
121         LM_ERR("ERR:I_UAR: Public Identity not found, responding with 400\n");
122         cscf_reply_transactional(msg, 400, MSG_400_NO_PUBLIC);
123         return CSCF_RETURN_BREAK;
124
125     }
126
127     b = cscf_parse_contacts(msg);
128
129     if (!b || (!b->contacts && !b->star)) {
130         LM_DBG("DBG:I_UAR: No contacts found\n");
131         return CSCF_RETURN_ERROR;
132     }
133
134     for (c = b->contacts; c; c = c->next) {
135
136         sos_reg = cscf_get_sos_uri_param(c->uri);
137         if (sos_reg == -1) {
138             //error case
139             LM_ERR("ERR:I_UAR: MSG_400_MALFORMED_CONTACT, responding with 400\n");
140             cscf_reply_transactional(msg, 400, MSG_400_MALFORMED_CONTACT);
141             return CSCF_RETURN_BREAK;
142         } else if (sos_reg == -2) {
143             LM_ERR("ERR:I_UAR: MSG_500_SERVER_ERROR_OUT_OF_MEMORY, responding with 500\n");
144             cscf_reply_transactional(msg, 500, MSG_500_SERVER_ERROR_OUT_OF_MEMORY);
145             return CSCF_RETURN_BREAK;
146         }
147     }
148
149     visited_network_id = cscf_get_visited_network_id(msg, &hdr);
150     if (!visited_network_id.len) {
151         LM_ERR("ERR:I_UAR: Visited Network Identity not found, responding with 400\n");
152         cscf_reply_transactional(msg, 400, MSG_400_NO_VISITED);
153         return CSCF_RETURN_BREAK;
154     }
155
156     if (atoi(str1)) authorization_type = AVP_IMS_UAR_REGISTRATION_AND_CAPABILITIES;
157     else {
158         expires = cscf_get_max_expires(msg, 0);
159         if (expires == 0) authorization_type = AVP_IMS_UAR_DE_REGISTRATION;
160     }
161
162     LM_DBG("SENDING UAR: PI: [%.*s], PU: [%.*s], VNID: [%.*s]\n", private_identity.len, private_identity.s,
163             public_identity.len, public_identity.s,
164             visited_network_id.len, visited_network_id.s);
165
166     //before we send lets suspend the transaction
167     t = tmb.t_gett();
168     if (t == NULL || t == T_UNDEFINED) {
169         if (tmb.t_newtran(msg) < 0) {
170             LM_ERR("cannot create the transaction for UAR async\n");
171             cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR);
172             return CSCF_RETURN_BREAK;
173         }
174         t = tmb.t_gett();
175         if (t == NULL || t == T_UNDEFINED) {
176             LM_ERR("cannot lookup the transaction\n");
177             cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR);
178             return CSCF_RETURN_BREAK;
179         }
180     }
181
182     saved_t = shm_malloc(sizeof (saved_uar_transaction_t));
183     if (!saved_t) {
184         LM_ERR("no more memory trying to save transaction state\n");
185         return CSCF_RETURN_ERROR;
186
187     }
188     memset(saved_t, 0, sizeof (saved_uar_transaction_t));
189     saved_t->act = cfg_action;
190
191     call_id = cscf_get_call_id(msg, 0);
192     saved_t->callid.s = (char*) shm_malloc(call_id.len + 1);
193     if (!saved_t->callid.s) {
194         LM_ERR("no more memory trying to save transaction state : callid\n");
195         shm_free(saved_t);
196         return CSCF_RETURN_ERROR;
197     }
198     memset(saved_t->callid.s, 0, call_id.len + 1);
199     memcpy(saved_t->callid.s, call_id.s, call_id.len);
200     saved_t->callid.len = call_id.len;
201
202     LM_DBG("Setting default AVP return code used for async callbacks to default as ERROR \n");
203     create_uaa_return_code(CSCF_RETURN_ERROR);
204     
205     LM_DBG("Suspending SIP TM transaction\n");
206     if (tmb.t_suspend(msg, &saved_t->tindex, &saved_t->tlabel) < 0) {
207         LM_ERR("failed to suspend the TM processing\n");
208         free_saved_uar_transaction_data(saved_t);
209
210         cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR);
211         return CSCF_RETURN_BREAK;
212     }
213
214     if (cxdx_send_uar(msg, private_identity, public_identity, visited_network_id, authorization_type, sos_reg, saved_t) != 0) {
215         LM_ERR("ERR:I_UAR: Error sending UAR or UAR time-out\n");
216         tmb.t_cancel_suspend(saved_t->tindex, saved_t->tlabel);
217         free_saved_uar_transaction_data(saved_t);
218         cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR);
219         return CSCF_RETURN_BREAK;
220
221     }
222     //we use async replies therefore we send break and not true when successful
223     return CSCF_RETURN_BREAK;
224 }
225
226
227