blob: 12c1bcb3f321ab513e238d95e8dea678b8883051 [file] [log] [blame]
Brian Waters13d96012017-12-08 16:53:31 -06001/*********************************************************************************************************
2* Software License Agreement (BSD License) *
3* Author: Alexandre Westfahl <awestfahl@freediameter.net> *
4* *
5* Copyright (c) 2010, Alexandre Westfahl, Teraoka Laboratory (Keio University), and the WIDE Project. *
6* *
7* All rights reserved. *
8* *
9* Redistribution and use of this software in source and binary forms, with or without modification, are *
10* permitted provided that the following conditions are met: *
11* *
12* * Redistributions of source code must retain the above *
13* copyright notice, this list of conditions and the *
14* following disclaimer. *
15* *
16* * Redistributions in binary form must reproduce the above *
17* copyright notice, this list of conditions and the *
18* following disclaimer in the documentation and/or other *
19* materials provided with the distribution. *
20* *
21* * Neither the name of the Teraoka Laboratory nor the *
22* names of its contributors may be used to endorse or *
23* promote products derived from this software without *
24* specific prior written permission of Teraoka Laboratory *
25* *
26* *
27* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
28* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
29* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
30* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
31* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
32* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
33* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
34* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
35*********************************************************************************************************/
36#include "app_sip.h"
37
38struct sess_state
39{
40 char *nonce;
41};
42
43
44int app_sip_MAR_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, void * opaque, enum disp_action * act)
45{
46 struct msg *ans, *qry;
47 struct avp *avp, *a2, *authdataitem;
48 //struct msg_hdr * header = NULL;
49 struct avp_hdr * avphdr=NULL, *avpheader=NULL, *avpheader_auth=NULL,*digestheader=NULL;
50 union avp_value val;
51 int found_cnonce=0;
52 struct avp * tempavp=NULL,*sipAuthentication=NULL,*sipAuthenticate=NULL;
53 char * result;
54 char password[51];
55 int idx=0, number_of_auth_items=0,i=0, ret=0;
56 //Flags and variables for Database
57 int sipurinotstored=0, authenticationpending=0;
58 size_t querylen=0, usernamelen=0;
59 char *query=NULL;
60 unsigned char *username=NULL;
61
62 //The nonce we will store and retrieve in session
63 struct sess_state *storednonce=NULL;
64
65
66 TRACE_ENTRY("%p %p %p %p", msg, paramavp, sess, act);
67
68 if (msg == NULL)
69 return EINVAL;
70
71
72 /* Create answer header */
73 qry = *msg;
74 CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, msg, 0 ) );
75 ans = *msg;
76
77
78
79 /* Add the appropriate command code & Auth-Application-Id
80 {
81
82 CHECK_FCT( fd_msg_hdr ( *msg, &header ) );
83 header->msg_flags = CMD_FLAG_PROXIABLE;
84 header->msg_code = 286;
85 header->msg_appl = 6;
86
87
88 // Add the Auth-Application-Id
89 {
90 CHECK_FCT( fd_msg_avp_new ( sip_dict.Auth_Application_Id, 0, &avp ) );
91 ASSERT(avp);
92 val.i32 = header->msg_appl;
93 CHECK_FCT( fd_msg_avp_setvalue ( avp, &val ) );
94 CHECK_FCT( fd_msg_avp_add ( ans, MSG_BRW_LAST_CHILD, avp) );
95 }
96 }*/
97
98
99 /* Add the Auth-Session-State AVP */
100 {
101
102 CHECK_FCT( fd_msg_search_avp ( qry, sip_dict.Auth_Session_State, &avp) );
103 CHECK_FCT( fd_msg_avp_hdr( avp, &avphdr ) );
104
105 CHECK_FCT( fd_msg_avp_new ( sip_dict.Auth_Session_State, 0, &avp ) );
106 CHECK_FCT( fd_msg_avp_setvalue( avp, avphdr->avp_value ) );
107 CHECK_FCT( fd_msg_avp_add( ans, MSG_BRW_LAST_CHILD, avp ) );
108 }
109
110
111
112 /* Check if method is REGISTER then User-Name must be present */
113 {
114
115 CHECK_FCT( fd_msg_search_avp ( qry, sip_dict.SIP_Method, &avp) );
116 CHECK_FCT( fd_msg_avp_hdr( avp, &avpheader ));
117
118
119 char *method=NULL;
120
121 CHECK_FCT( fd_msg_search_avp ( qry, sip_dict.User_Name, &avp) );
122 if(avp!=NULL)
123 {
124
125 int not_found=1;
126 MYSQL_RES *res=NULL;
127 MYSQL_ROW row;
128
129 CHECK_FCT( fd_msg_avp_hdr( avp, &avphdr ) );
130
131
132
133
134 if((strncmp((const char *)avpheader->avp_value->os.data,"REGISTER",avpheader->avp_value->os.len)==0))
135 {
136 not_found=1;
137
138 //TODO TODO TODO TODO TODO TODO TODO: maybe doesn't work!!'
139 ret=get_password(avphdr->avp_value->os.data, avphdr->avp_value->os.len, (char *)&password);
140
141 if(ret>1)
142 {
143 //We couldn't make the request
144 result="DIAMETER_UNABLE_TO_COMPLY";
145 goto out;
146 }
147 not_found=ret;
148
149 if(not_found)
150 {
151 TRACE_DEBUG(FULL,"The user %s doesn't exist!",username);
152 result="DIAMETER_ERROR_USER_UNKNOWN";
153 free(username);
154 goto out;
155 }
156
157
158 //We allocate the double size of username because at worst it can be all quotes
159 username=malloc(avphdr->avp_value->os.len*2+1);
160 //We purify username not to have forbidden characters
161 usernamelen=mysql_real_escape_string(conn, (char *)username, (const char *)avphdr->avp_value->os.data, avphdr->avp_value->os.len);
162
163 //Now that we know the user exist, we get the list of AOR owned by this user
164 querylen=SQL_GETSIPAOR_LEN + usernamelen;
165 query = malloc(querylen+2);
166 snprintf(query, querylen+1, SQL_GETSIPAOR, username);
167
168 //We make the query
169 request_mysql(query);
170 res=mysql_use_result(conn);
171 if(res==NULL)
172 {
173 //We couldn't make the request
174 result="DIAMETER_UNABLE_TO_COMPLY";
175 goto out;
176 }
177
178 //We retrieve the SIP-AOR from AVP to check if the user can us it
179 CHECK_FCT( fd_msg_search_avp ( qry, sip_dict.SIP_AOR, &avp) );
180 CHECK_FCT( fd_msg_avp_hdr( avp, &avphdr ) );
181
182 not_found=1;
183 while ((row = mysql_fetch_row(res)) != NULL)
184 {
185 if(strncmp((const char *)avphdr->avp_value->os.data,row[0],avphdr->avp_value->os.len)==0)
186 {
187 not_found=0;
188 break;
189 }
190 }
191 mysql_free_result(res);
192 free(query);
193
194 if(not_found)
195 {
196 TRACE_DEBUG(FULL,"The user %s can't use this SIP-AOR!",username);
197 result="DIAMETER_ERROR_IDENTITIES_DONT_MATCH";
198 free(username);
199 goto out;
200 }
201
202 }
203
204 CHECK_FCT( fd_msg_search_avp ( qry, sip_dict.SIP_Server_URI, &avp) );
205 CHECK_FCT( fd_msg_avp_hdr( avp, &avphdr ));
206
207 if(avphdr!=NULL)
208 {
209 unsigned char *sipuri=NULL;
210 int sipurilen=0;
211
212 //We allocate the double size of SIP-URI because at worst it can be all quotes
213 CHECK_MALLOC(sipuri=malloc(avphdr->avp_value->os.len*2+1));
214 //We purify SIP-URI not to have forbidden characters
215 sipurilen=mysql_real_escape_string(conn, (char *)sipuri, (const char *)avphdr->avp_value->os.data, avphdr->avp_value->os.len);
216
217
218 //We get the SIP-URI assignated to the user
219 querylen=SQL_GETSIPURI_LEN + usernamelen;
220 CHECK_MALLOC(query = malloc(querylen+2));
221 snprintf(query, querylen+1, SQL_GETSIPURI, username);
222
223 //We make the query
224 request_mysql(query);
225 res=mysql_use_result(conn);
226 if(res==NULL)
227 {
228 //We couldn't make the request
229 result="DIAMETER_UNABLE_TO_COMPLY";
230 goto out;
231 }
232 not_found=1;
233 while ((row = mysql_fetch_row(res)) != NULL)
234 {
235 if(strncmp((const char *)avphdr->avp_value->os.data,row[0],avphdr->avp_value->os.len)==0)
236 {
237 not_found=0;
238 break;
239 }
240 }
241 mysql_free_result(res);
242 free(query);
243
244 if(not_found)
245 {
246 //Temporary
247 set_sipserver_uri(username, usernamelen, sipuri,sipurilen);
248
249
250 set_pending_flag(username, usernamelen);
251
252
253 authenticationpending=1;
254 }
255 free(sipuri);
256
257 }
258 else
259 sipurinotstored=1;
260
261 }
262 else
263 {
264 result="DIAMETER_USER_NAME_REQUIRED";
265 goto out;
266 }
267
268
269 free(method);
270
271 }
272
273
274 //TODO: remove loop for authdataitem because RFC say only one (wait for answer from Garcia)
275 // How many Auth Data Items?
276 CHECK_FCT( fd_msg_search_avp ( qry, sip_dict.SIP_Number_Auth_Items, &avp) );
277 CHECK_FCT( fd_msg_avp_hdr( avp, &avpheader ) );
278
279
280 if(avp!=NULL)
281 {
282 CHECK_FCT(fd_msg_search_avp ( qry, sip_dict.SIP_Auth_Data_Item, &avp));
283 CHECK_FCT( fd_msg_avp_hdr( avp, &avphdr ) );
284
285 if(avp!=NULL)
286 {
287 //First is Authentication Scheme
288 CHECK_FCT(fd_msg_browse ( avp, MSG_BRW_FIRST_CHILD, &avp, NULL) );
289 CHECK_FCT( fd_msg_avp_hdr( avp, &avphdr ) );
290
291 //Digest-Authentication?
292 if(avphdr->avp_value->i32==0)
293 {
294
295 for(idx=0;idx<avpheader->avp_value->i32;idx++)
296 {
297 //We look for SIP Auth items
298 CHECK_FCT(fd_msg_browse ( avp, MSG_BRW_WALK, &avp, NULL) );
299
300 if(avp!=NULL)
301 {
302
303 CHECK_FCT( fd_msg_avp_hdr( avp,&avphdr ));
304
305 if(avphdr->avp_code==380) //We only create Auth-Data-Item to answer Auth-Data-Item
306 {
307 /* Add the Auth-Data-Item AVP */
308 CHECK_FCT( fd_msg_avp_new ( sip_dict.SIP_Auth_Data_Item, 0, &authdataitem ) );
309
310 /* Add the Authentication Scheme AVP */
311 {
312 CHECK_FCT( fd_msg_avp_new ( sip_dict.SIP_Authentication_Scheme, 0, &a2 ) );
313 val.i32=0; //We only know Digest Authentication
314 CHECK_FCT( fd_msg_avp_setvalue( a2, &val ) );
315 CHECK_FCT( fd_msg_avp_add( authdataitem, MSG_BRW_LAST_CHILD, a2 ) );
316 }
317
318 //We need to know if there is a Cnonce attribute (only in the second MAR request)
319
320 //CHECK_FCT(fd_msg_browse ( avp, MSG_BRW_WALK, &avp, NULL) );
321
322
323 CHECK_FCT(fd_avp_search_avp (avp, sip_dict.Digest_CNonce, &a2 ));
324
325 if(a2!=NULL)
326 found_cnonce=1;
327 else
328 found_cnonce=0;
329
330 if(!found_cnonce)
331 {
332 /*
333 We are in the case of first access request so we need to challenge the user.
334 */
335 TRACE_DEBUG(FULL,"First Authorization in progress...");
336
337 /* Create a new session */ //this create a new session Id !!!
338 //CHECK_FCT_DO( fd_sess_new( &sess, fd_g_config->cnf_diamid, "diamsip", 7), goto out );
339
340
341 /* Create the SIP-Authenticate AVP */
342 {
343 CHECK_FCT( fd_msg_avp_new ( sip_dict.SIP_Authenticate, 0, &sipAuthenticate ) );
344 }
345
346 /* Add the Digest QOP AVP */
347 {
348 CHECK_FCT( fd_msg_avp_new ( sip_dict.Digest_QOP, 0, &a2 ) );
349 val.os.data=(unsigned char *)"auth";
350 val.os.len=strlen((const char *)val.os.data);
351 CHECK_FCT( fd_msg_avp_setvalue( a2, &val ) );
352 CHECK_FCT( fd_msg_avp_add( sipAuthenticate, MSG_BRW_LAST_CHILD, a2 ) );
353 }
354 /* Add the Digest Nonce AVP */
355 {
356 uint8_t buffer[NONCE_SIZE];
357 char nonce[NONCE_SIZE * 2 + 1];
358
359
360 gcry_create_nonce ((uint8_t *)buffer, sizeof(buffer));
361
362 for(i=0;i<NONCE_SIZE;i++)
363 sprintf(&nonce[2 * i], "%2.2hhx", buffer[i]);
364
365 CHECK_FCT( fd_msg_avp_new ( sip_dict.Digest_Nonce, 0, &a2 ) );
366
367
368 //We store the nonce (storednonce structure) inside the session
369 storednonce=malloc(sizeof(struct sess_state));
370 memset(storednonce,0,sizeof(struct sess_state));
371 CHECK_MALLOC(storednonce->nonce=malloc(NONCE_SIZE*2+1));
372 memcpy(storednonce->nonce,(char *)nonce,NONCE_SIZE*2+1);
373 CHECK_FCT( fd_sess_state_store ( ds_sess_hdl, sess, &storednonce ));
374
375 val.os.data=(unsigned char *)nonce;
376 val.os.len=NONCE_SIZE * 2;
377
378 CHECK_FCT( fd_msg_avp_setvalue( a2, &val ) );
379 CHECK_FCT( fd_msg_avp_add( sipAuthenticate, MSG_BRW_LAST_CHILD, a2 ) );
380 }
381 /* Add the Digest Algorithm AVP */
382 {
383 CHECK_FCT( fd_msg_avp_new ( sip_dict.Digest_Algorithm, 0, &a2 ) );
384 val.os.data=(unsigned char *)"MD5";
385 val.os.len=strlen((const char *)val.os.data);
386 CHECK_FCT( fd_msg_avp_setvalue( a2, &val ) );
387 CHECK_FCT( fd_msg_avp_add( sipAuthenticate, MSG_BRW_LAST_CHILD, a2 ) );
388
389 }
390 /* Add the Digest Realm AVP */
391 {
392 tempavp=avp;
393
394 avpheader_auth=walk_digest(tempavp, 104);
395 if(avpheader_auth!=NULL)
396 {
397 CHECK_FCT( fd_msg_avp_new ( sip_dict.Digest_Realm, 0, &a2 ) );
398 CHECK_FCT( fd_msg_avp_setvalue( a2, avpheader_auth->avp_value ) );
399 CHECK_FCT( fd_msg_avp_add( sipAuthenticate, MSG_BRW_LAST_CHILD, a2 ) );
400
401 }
402 }
403
404
405 //We add SIP Authenticate to Auth Data Item
406 CHECK_FCT( fd_msg_avp_add( authdataitem, MSG_BRW_LAST_CHILD, sipAuthenticate ) );
407 //We add Auth Data Item to Answer
408 CHECK_FCT( fd_msg_avp_add( ans, MSG_BRW_LAST_CHILD, authdataitem ) );
409
410 number_of_auth_items++;
411 if(sipurinotstored)
412 result="DIAMETER_SUCCESS_AUTH_SENT_SERVER_NOT_STORED";
413 else
414 result="DIAMETER_MULTI_ROUND_AUTH";
415 found_cnonce=0;
416 }
417 else
418 {
419 /*
420 We are in the case of access request after challenge so we need to check credentials.
421 */
422 TRACE_DEBUG(FULL,"Authentication after challenge");
423
424 /* Search the session, retrieve its data */
425 {
426 //int new=0;
427
428 //TRACE_DEBUG(FULL,"new: *%d*",new);
429 //ASSERT( new == 0 );
430 CHECK_FCT( fd_sess_state_retrieve( ds_sess_hdl, sess, &storednonce ));
431 if(storednonce ==NULL)
432 {
433 result="DIAMETER_UNABLE_TO_COMPLY";
434
435 if(username!=NULL)
436 free(username);
437 goto out;
438 }
439 }
440
441 /* Create the SIP-Authentication-Info AVP */
442 {
443 CHECK_FCT( fd_msg_avp_new ( sip_dict.SIP_Authentication_Info, 0, &sipAuthentication ) );
444 }
445
446
447
448 /* Add the Digest response Auth AVP */
449 {
450 //uint8_t bufferresp[DIGEST_LEN];
451 //char response[DIGEST_LEN*2+1];
452
453
454 //We extract all the data we need
455 tempavp=avp;
456
457 char * digest_username=NULL, *digest_uri=NULL, *digest_response=NULL, *digest_realm=NULL, *digest_nonce=NULL, *digest_method=NULL, *digest_qop=NULL, *digest_algorithm=NULL, *digest_cnonce=NULL, *digest_noncecount=NULL;
458
459
460 CHECK_FCT(fd_avp_search_avp (avp, sip_dict.Digest_Nonce, &a2 ));
461 if(a2!=NULL)
462 {
463 CHECK_FCT( fd_msg_avp_hdr( a2, &digestheader ) );
464 if(digestheader!=NULL)
465 {
466
467 digest_nonce = malloc(digestheader->avp_value->os.len + 1);
468 memcpy(digest_nonce, digestheader->avp_value->os.data,
469 digestheader->avp_value->os.len);
470 digest_nonce[digestheader->avp_value->os.len]='\0';
471 TRACE_DEBUG(FULL,"Element:*%s*",digest_nonce);
472 TRACE_DEBUG(FULL,"Stored Nonce:*%s*",storednonce->nonce);
473
474 if(strcmp(digest_nonce,storednonce->nonce)!=0)
475 {
476 free(digest_nonce);
477 free(storednonce->nonce);
478 free(storednonce);
479 result="DIAMETER_UNABLE_TO_COMPLY";
480
481 if(username!=NULL)
482 free(username);
483 goto out;
484 }
485
486 }
487
488 }
489 CHECK_FCT(fd_avp_search_avp (avp, sip_dict.Digest_Response, &a2 ));
490 if(a2!=NULL)
491 {
492 CHECK_FCT( fd_msg_avp_hdr( a2, &digestheader ) );
493 if(digestheader!=NULL)
494 {
495 digest_response = malloc(digestheader->avp_value->os.len + 1);
496 memcpy(digest_response, digestheader->avp_value->os.data,
497 digestheader->avp_value->os.len);
498 digest_response[digestheader->avp_value->os.len]='\0';
499 TRACE_DEBUG(FULL,"Element:*%s*",digest_response);
500 }
501
502 }
503 CHECK_FCT(fd_avp_search_avp (avp, sip_dict.Digest_Realm, &a2 ));
504 if(a2!=NULL)
505 {
506 CHECK_FCT( fd_msg_avp_hdr( a2, &digestheader ) );
507 if(digestheader!=NULL)
508 {
509 digest_realm = malloc(digestheader->avp_value->os.len + 1);
510 memcpy(digest_realm, digestheader->avp_value->os.data,
511 digestheader->avp_value->os.len);
512 digest_realm[digestheader->avp_value->os.len]='\0';
513 TRACE_DEBUG(FULL,"Element:*%s*",digest_realm);
514 }
515 }
516
517 CHECK_FCT(fd_avp_search_avp (avp, sip_dict.Digest_Method, &a2 ));
518 if(a2!=NULL)
519 {
520 CHECK_FCT( fd_msg_avp_hdr( a2, &digestheader ) );
521 if(digestheader!=NULL)
522 {
523 digest_method = malloc(digestheader->avp_value->os.len + 1);
524 memcpy(digest_method, digestheader->avp_value->os.data,
525 digestheader->avp_value->os.len);
526 digest_method[digestheader->avp_value->os.len]='\0';
527 TRACE_DEBUG(FULL,"Element:*%s*",digest_method);
528 }
529 }
530 else
531 digest_method="";
532
533 CHECK_FCT(fd_avp_search_avp (avp, sip_dict.Digest_URI, &a2 ));
534 if(a2!=NULL)
535 {
536 CHECK_FCT( fd_msg_avp_hdr( a2, &digestheader ) );
537 if(digestheader!=NULL)
538 {
539 digest_uri = malloc(digestheader->avp_value->os.len + 1);
540 memcpy(digest_uri, digestheader->avp_value->os.data,
541 digestheader->avp_value->os.len);
542 digest_uri[digestheader->avp_value->os.len]='\0';
543 TRACE_DEBUG(FULL,"Element:*%s*",digest_uri);
544 }
545 }
546
547 CHECK_FCT(fd_avp_search_avp (avp, sip_dict.Digest_QOP, &a2 ));
548 if(a2!=NULL)
549 {
550 CHECK_FCT( fd_msg_avp_hdr( a2, &digestheader ) );
551 if(digestheader!=NULL)
552 {
553 digest_qop = malloc(digestheader->avp_value->os.len + 1);
554 memcpy(digest_qop, digestheader->avp_value->os.data,
555 digestheader->avp_value->os.len);
556 digest_qop[digestheader->avp_value->os.len]='\0';
557 TRACE_DEBUG(FULL,"Element:*%s*",digest_qop);
558 }
559 }
560 else
561 digest_qop=NULL;
562 CHECK_FCT(fd_avp_search_avp (avp, sip_dict.Digest_Algorithm, &a2 ));
563 if(a2!=NULL)
564 {
565 CHECK_FCT( fd_msg_avp_hdr( a2, &digestheader ) );
566 if(digestheader!=NULL)
567 {
568 digest_algorithm = malloc(digestheader->avp_value->os.len + 1);
569 memcpy(digest_algorithm, digestheader->avp_value->os.data,
570 digestheader->avp_value->os.len);
571 digest_algorithm[digestheader->avp_value->os.len]='\0';
572 TRACE_DEBUG(FULL,"Element:*%s*",digest_algorithm);
573 }
574 }
575 else
576 digest_algorithm=NULL;
577 CHECK_FCT(fd_avp_search_avp (avp, sip_dict.Digest_CNonce, &a2 ));
578 if(a2!=NULL)
579 {
580 CHECK_FCT( fd_msg_avp_hdr( a2, &digestheader ) );
581 if(digestheader!=NULL)
582 {
583 digest_cnonce = malloc(digestheader->avp_value->os.len + 1);
584 memcpy(digest_cnonce, digestheader->avp_value->os.data,
585 digestheader->avp_value->os.len);
586 digest_cnonce[digestheader->avp_value->os.len]='\0';
587 TRACE_DEBUG(FULL,"Element:*%s*",digest_cnonce);
588 }
589 }
590 else
591 digest_cnonce="";
592 CHECK_FCT(fd_avp_search_avp (avp, sip_dict.Digest_Nonce_Count, &a2 ));
593 if(a2!=NULL)
594 {
595 CHECK_FCT( fd_msg_avp_hdr( a2, &digestheader ) );
596 if(digestheader!=NULL)
597 {
598 digest_noncecount = malloc(digestheader->avp_value->os.len + 1);
599 memcpy(digest_noncecount, digestheader->avp_value->os.data,
600 digestheader->avp_value->os.len);
601 digest_noncecount[digestheader->avp_value->os.len]='\0';
602 TRACE_DEBUG(FULL,"Element:*%s*",digest_noncecount);
603 }
604 }
605 else
606 digest_noncecount="";
607 CHECK_FCT(fd_avp_search_avp (avp, sip_dict.Digest_Username, &a2 ));
608 if(a2!=NULL)
609 {
610 CHECK_FCT( fd_msg_avp_hdr( a2, &digestheader ) );
611 if(digestheader!=NULL)
612 {
613 digest_username = malloc(digestheader->avp_value->os.len + 1);
614 memcpy(digest_username, digestheader->avp_value->os.data,
615 digestheader->avp_value->os.len);
616 digest_username[digestheader->avp_value->os.len]='\0';
617 TRACE_DEBUG(FULL,"Element:*%s*",digest_username);
618 }
619 }
620 //TODO: replace by authentication function
621
622 HASHHEX HA1;
623 HASHHEX HA2 = "";
624 HASHHEX response, responseauth;
625
626
627 DigestCalcHA1(digest_algorithm, digest_username, digest_realm, password, digest_nonce,digest_cnonce, HA1);
628 DigestCalcResponse(HA1, digest_nonce, digest_noncecount, digest_cnonce, digest_qop,digest_method, digest_uri, HA2, response);
629
630
631 // We check that the Digest-Response is the same (UA, Diameter)
632 if(strcmp(response,digest_response)!=0)
633 {
634 TRACE_DEBUG(FULL,"Response calculated by Diameter server:%s",response);
635 TRACE_DEBUG(FULL,"Response calculated by UA:%s",digest_response);
636 TRACE_DEBUG(INFO,"Digest-Response does not match!");
637 result="DIAMETER_UNABLE_TO_COMPLY";
638 free(digest_algorithm);
639 free(digest_cnonce);
640 free(digest_nonce);
641 free(digest_noncecount);
642 free(digest_method);
643 free(digest_username);
644 free(digest_uri);
645 free(digest_qop);
646 free(digest_response);
647 free(digest_realm);
648 free(storednonce->nonce);
649 free(storednonce);
650 if(username!=NULL)
651 free(username);
652 goto out;
653
654 }
655 //We calculate Digest_Response_Auth
656 DigestCalcResponseAuth(HA1, digest_nonce, digest_noncecount, digest_cnonce, digest_qop,digest_method, digest_uri, HA2, responseauth);
657
658 TRACE_DEBUG(FULL,"Response calculated by Diameter server:%s",response);
659 TRACE_DEBUG(FULL,"Response calculated by UA:%s",digest_response);
660 if(strcmp(digest_qop,"auth-int")==0)
661 {
662 //Digest-HA1 MUST be used instead of Digest-Response-Auth if Digest-Qop is 'auth-int'.
663 CHECK_FCT( fd_msg_avp_new ( sip_dict.Digest_HA1, 0, &a2 ) );
664 val.os.data=(unsigned char *)HA1;
665 val.os.len=HASHHEXLEN+1;
666 CHECK_FCT( fd_msg_avp_setvalue( a2, &val ) );
667 CHECK_FCT( fd_msg_avp_add( sipAuthentication, MSG_BRW_LAST_CHILD, a2 ) );
668 }
669 else
670 {
671 //Digest-Response-Auth MUST be used instead of Digest-HA1 if Digest-Qop is 'auth'.
672 CHECK_FCT( fd_msg_avp_new ( sip_dict.Digest_Response_Auth, 0, &a2 ) );
673 val.os.data=(unsigned char *)responseauth;
674 val.os.len=DIGEST_LEN*2;
675 CHECK_FCT( fd_msg_avp_setvalue( a2, &val ) );
676 CHECK_FCT( fd_msg_avp_add( sipAuthentication, MSG_BRW_LAST_CHILD, a2 ) );
677 }
678 free(digest_algorithm);
679 free(digest_cnonce);
680 free(digest_nonce);
681 free(digest_noncecount);
682 free(digest_method);
683 free(digest_username);
684 free(digest_uri);
685 free(digest_qop);
686 free(digest_response);
687 free(digest_realm);
688 free(storednonce->nonce);
689 free(storednonce);
690
691 number_of_auth_items++;
692 }
693
694
695 //We add SIP Authentication-Info to Auth Data Item
696 CHECK_FCT( fd_msg_avp_add( authdataitem, MSG_BRW_LAST_CHILD, sipAuthentication ) );
697 //We add Auth Data Item to Answer
698 CHECK_FCT( fd_msg_avp_add( ans, MSG_BRW_LAST_CHILD, authdataitem ) );
699
700
701 if(username!=NULL && authenticationpending)
702 {
703 //We clear the pending flag
704 clear_pending_flag(username, usernamelen);
705 }
706
707 if(sipurinotstored)
708 result="DIAMETER_SUCCESS_SERVER_NAME_NOT_STORED";
709 else
710 result="DIAMETER_SUCCESS";
711 found_cnonce=0;
712 }
713 }
714 }
715 else
716 TRACE_DEBUG(INFO,"No auth data items!");
717 }
718 /*Add SIP_Number_Auth_Items AVP */
719 {
720 CHECK_FCT( fd_msg_avp_new ( sip_dict.SIP_Number_Auth_Items, 0, &avp ) );
721 val.i32 = number_of_auth_items;
722 CHECK_FCT( fd_msg_avp_setvalue ( avp, &val ) );
723 CHECK_FCT( fd_msg_avp_add ( ans, MSG_BRW_LAST_CHILD, avp) );
724 }
725
726
727 }
728 else
729 {
730 TRACE_DEBUG(INFO,"We only support DIGEST for now, unable to comply");
731 result="DIAMETER_ERROR_AUTH_SCHEME_NOT_SUPPORTED";
732 if(username!=NULL)
733 free(username);
734 goto out;
735 }
736 }
737 }
738 else
739 {
740 //TODO: remove this because Number_Auth_Items is not compulsory
741 TRACE_DEBUG(FULL,"Number-Auth-Items is not included.");
742 result="DIAMETER_UNABLE_TO_COMPLY";
743 if(username!=NULL)
744 free(username);
745 goto out;
746 }
747
748 if(username!=NULL)
749 free(username);
750
751
752out:
753 /* Set the Origin-Host, Origin-Realm, Result-Code AVPs */
754 CHECK_FCT( fd_msg_rescode_set( ans, result, NULL, NULL, 1 ) );
755
756
757 /* Send the answer */
758 CHECK_FCT( fd_msg_send( msg, NULL, NULL ) );
759
760
761 return 0;
762}