uac: use auth_ha1 field if set for remote registrations
[sip-router] / src / modules / uac / uac_reg.c
1 /**
2  * Copyright (C) 2010 Daniel-Constantin Mierla (asipto.com)
3  *
4  * This file is part of kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 /*!
22  * \file
23  * \brief Kamailio uac :: The SIP UA registration client module
24  * \ingroup uac
25  * Module: \ref uac
26  */
27
28 #include <time.h>
29
30 #include "../../core/dprint.h"
31 #include "../../core/timer.h"
32
33 #include "../../core/mem/shm_mem.h"
34 #include "../../lib/srdb1/db.h"
35 #include "../../core/ut.h"
36 #include "../../core/trim.h"
37 #include "../../core/hashes.h"
38 #include "../../core/locking.h"
39 #include "../../core/parser/parse_uri.h"
40 #include "../../core/parser/parse_from.h"
41 #include "../../core/parser/parse_to.h"
42 #include "../../core/parser/parse_expires.h"
43 #include "../../core/parser/contact/parse_contact.h"
44 #include "../../core/rpc.h"
45 #include "../../core/rpc_lookup.h"
46 #include "../../core/rand/kam_rand.h"
47
48 #include "../../modules/tm/tm_load.h"
49
50 #include "auth.h"
51 #include "auth_hdr.h"
52 #include "uac_reg.h"
53
54 #define UAC_REG_DISABLED        (1<<0) /* registration disabled */
55 #define UAC_REG_ONGOING         (1<<1) /* registration on progress */
56 #define UAC_REG_ONLINE          (1<<2) /* registered */
57 #define UAC_REG_AUTHSENT        (1<<3) /* registration with auth in progress */
58 #define UAC_REG_INIT            (1<<4) /* registration initialized */
59
60 #define MAX_UACH_SIZE 2048
61 #define UAC_REG_TM_CALLID_SIZE 90
62
63 int _uac_reg_gc_interval = 150;
64
65 typedef struct _reg_uac
66 {
67         unsigned int h_uuid;
68         unsigned int h_user;
69         str   l_uuid;
70         str   l_username;
71         str   l_domain;
72         str   r_username;
73         str   r_domain;
74         str   realm;
75         str   auth_proxy;
76         str   auth_username;
77         str   auth_password;
78         str   auth_ha1;
79         str   callid;
80         str   socket;
81         unsigned int cseq;
82         unsigned int flags;
83         unsigned int expires;
84         time_t timer_expires;
85         unsigned int reg_delay;
86         time_t reg_init;
87         gen_lock_t *lock;
88 } reg_uac_t;
89
90 typedef struct _reg_item
91 {
92         reg_uac_t *r;
93         struct _reg_item *next;
94 } reg_item_t;
95
96
97 typedef struct _reg_entry
98 {
99         unsigned int isize;
100         unsigned int usize;
101         reg_item_t *byuser;
102         reg_item_t *byuuid;
103         gen_lock_t lock;
104 } reg_entry_t;
105
106 typedef struct _reg_ht
107 {
108         unsigned int htsize;
109         time_t stime;
110         reg_entry_t *entries;
111 } reg_ht_t;
112
113 static reg_ht_t *_reg_htable = NULL;
114 static reg_ht_t *_reg_htable_gc = NULL;
115 static gen_lock_t *_reg_htable_gc_lock = NULL;
116
117 int reg_use_domain = 0;
118 int reg_timer_interval = 90;
119 int reg_retry_interval = 0;
120 int reg_htable_size = 4;
121 int reg_fetch_rows = 1000;
122 int reg_keep_callid = 0;
123 int reg_random_delay = 0;
124 int *reg_active = NULL;
125 str reg_contact_addr = STR_NULL;
126 str reg_db_url = STR_NULL;
127 str reg_db_table = str_init("uacreg");
128
129 str l_uuid_column = str_init("l_uuid");
130 str l_username_column = str_init("l_username");
131 str l_domain_column = str_init("l_domain");
132 str r_username_column = str_init("r_username");
133 str r_domain_column = str_init("r_domain");
134 str realm_column = str_init("realm");
135 str auth_username_column = str_init("auth_username");
136 str auth_password_column = str_init("auth_password");
137 str auth_ha1_column = str_init("auth_ha1");
138 str auth_proxy_column = str_init("auth_proxy");
139 str expires_column = str_init("expires");
140 str flags_column = str_init("flags");
141 str reg_delay_column = str_init("reg_delay");
142 str socket_column = str_init("socket");
143
144 str str_empty = str_init("");
145
146
147 extern struct tm_binds uac_tmb;
148 extern pv_spec_t auth_username_spec;
149 extern pv_spec_t auth_realm_spec;
150 extern pv_spec_t auth_password_spec;
151
152 counter_handle_t regtotal;         /* Total number of registrations in memory */
153 counter_handle_t regactive;        /* Active registrations - 200 OK */
154 counter_handle_t regdisabled;      /* Disabled registrations */
155
156 /* Init reg active mode */
157 int reg_active_init(int mode)
158 {
159         if(reg_active!=NULL) {
160                 /* already allocated */
161                 *reg_active = mode;
162                 return 0;
163         }
164         reg_active = (int*)shm_malloc(sizeof(int));
165         if(reg_active==NULL) {
166                 LM_ERR("not enough shared memory\n");
167                 return -1;
168         }
169         *reg_active = mode;
170         return 0;
171 }
172
173 /* Init counters */
174 static void uac_reg_counter_init()
175 {
176         LM_DBG("*** Initializing UAC reg counters\n");
177         counter_register(&regtotal, "uac", "regtotal", 0, 0, 0, "Total number of registration accounts in memory", 0);
178         counter_register(&regactive, "uac", "regactive", 0, 0, 0, "Number of successfully registered accounts (200 OK)", 0);
179         counter_register(&regdisabled, "uac", "regdisabled", 0, 0, 0, "Counter of failed registrations (not 200 OK)", 0);
180 }
181
182
183 /**
184  * Init the in-memory registration database in hash table
185  */
186 int uac_reg_init_ht(unsigned int sz)
187 {
188         int i;
189
190         _reg_htable_gc_lock = (gen_lock_t*)shm_malloc(sizeof(gen_lock_t));
191         if(_reg_htable_gc_lock == NULL)
192         {
193                 LM_ERR("no more shm for lock\n");
194                 return -1;
195         }
196         if(lock_init(_reg_htable_gc_lock)==0)
197         {
198                 LM_ERR("cannot init global lock\n");
199                 shm_free((void*)_reg_htable_gc_lock);
200                 return -1;
201         }
202         _reg_htable_gc = (reg_ht_t*)shm_malloc(sizeof(reg_ht_t));
203         if(_reg_htable_gc==NULL)
204         {
205                 LM_ERR("no more shm\n");
206                 lock_destroy(_reg_htable_gc_lock);
207                 shm_free((void*)_reg_htable_gc_lock);
208                 return -1;
209         }
210         memset(_reg_htable_gc, 0, sizeof(reg_ht_t));
211         _reg_htable_gc->htsize = sz;
212
213         _reg_htable_gc->entries =
214                 (reg_entry_t*)shm_malloc(_reg_htable_gc->htsize*sizeof(reg_entry_t));
215         if(_reg_htable_gc->entries==NULL)
216         {
217                 LM_ERR("no more shm.\n");
218                 shm_free(_reg_htable_gc);
219                 lock_destroy(_reg_htable_gc_lock);
220                 shm_free((void*)_reg_htable_gc_lock);
221                 return -1;
222         }
223         memset(_reg_htable_gc->entries, 0, _reg_htable_gc->htsize*sizeof(reg_entry_t));
224
225
226         _reg_htable = (reg_ht_t*)shm_malloc(sizeof(reg_ht_t));
227         if(_reg_htable==NULL)
228         {
229                 LM_ERR("no more shm\n");
230                 shm_free(_reg_htable_gc->entries);
231                 shm_free(_reg_htable_gc);
232                 lock_destroy(_reg_htable_gc_lock);
233                 shm_free((void*)_reg_htable_gc_lock);
234                 return -1;
235         }
236         memset(_reg_htable, 0, sizeof(reg_ht_t));
237         _reg_htable->htsize = sz;
238
239         _reg_htable->entries =
240                 (reg_entry_t*)shm_malloc(_reg_htable->htsize*sizeof(reg_entry_t));
241         if(_reg_htable->entries==NULL)
242         {
243                 LM_ERR("no more shm.\n");
244                 shm_free(_reg_htable_gc->entries);
245                 shm_free(_reg_htable_gc);
246                 shm_free(_reg_htable);
247                 lock_destroy(_reg_htable_gc_lock);
248                 shm_free((void*)_reg_htable_gc_lock);
249                 return -1;
250         }
251         memset(_reg_htable->entries, 0, _reg_htable->htsize*sizeof(reg_entry_t));
252         for(i=0; i<_reg_htable->htsize; i++)
253         {
254                 if(lock_init(&_reg_htable->entries[i].lock)==0)
255                 {
256                         LM_ERR("cannot initialize lock[%d] n", i);
257                         i--;
258                         while(i>=0)
259                         {
260                                 lock_destroy(&_reg_htable->entries[i].lock);
261                                 i--;
262                         }
263                         shm_free(_reg_htable->entries);
264                         shm_free(_reg_htable);
265                         shm_free(_reg_htable_gc->entries);
266                         shm_free(_reg_htable_gc);
267                         lock_destroy(_reg_htable_gc_lock);
268                         shm_free((void*)_reg_htable_gc_lock);
269                         return -1;
270                 }
271         }
272
273         /* Initialize uac reg counters */
274         uac_reg_counter_init();
275
276         return 0;
277 }
278
279 /**
280  *
281  */
282 int uac_reg_free_ht(void)
283 {
284         int i;
285         reg_item_t *it = NULL;
286         reg_item_t *it0 = NULL;
287
288         if(_reg_htable_gc_lock != NULL)
289         {
290                 lock_destroy(_reg_htable_gc_lock);
291                 shm_free((void*)_reg_htable_gc_lock);
292                 _reg_htable_gc_lock = NULL;
293         }
294         if(_reg_htable_gc!=NULL)
295         {
296                 for(i=0; i<_reg_htable_gc->htsize; i++)
297                 {
298                         it = _reg_htable_gc->entries[i].byuuid;
299                         while(it)
300                         {
301                                 it0 = it;
302                                 it = it->next;
303                                 shm_free(it0);
304                         }
305                         it = _reg_htable_gc->entries[i].byuser;
306                         while(it)
307                         {
308                                 it0 = it;
309                                 it = it->next;
310                                 shm_free(it0->r);
311                                 shm_free(it0);
312                         }
313                 }
314                 shm_free(_reg_htable_gc->entries);
315                 shm_free(_reg_htable_gc);
316                 _reg_htable_gc = NULL;
317         }
318
319         if(_reg_htable==NULL)
320         {
321                 LM_DBG("no hash table\n");
322                 return -1;
323         }
324         for(i=0; i<_reg_htable->htsize; i++)
325         {
326                 lock_get(&_reg_htable->entries[i].lock);
327                 /* free entries */
328                 it = _reg_htable->entries[i].byuuid;
329                 while(it)
330                 {
331                         it0 = it;
332                         it = it->next;
333                         shm_free(it0);
334                 }
335                 it = _reg_htable->entries[i].byuser;
336                 while(it)
337                 {
338                         it0 = it;
339                         it = it->next;
340                         shm_free(it0->r);
341                         shm_free(it0);
342                 }
343                 lock_destroy(&_reg_htable->entries[i].lock);
344         }
345         shm_free(_reg_htable->entries);
346         shm_free(_reg_htable);
347         _reg_htable = NULL;
348         return 0;
349 }
350
351 /**
352  *
353  */
354 int uac_reg_reset_ht_gc(void)
355 {
356         int i;
357         reg_item_t *it = NULL;
358         reg_item_t *it0 = NULL;
359
360         if(_reg_htable_gc==NULL)
361         {
362                 LM_DBG("no hash table\n");
363                 return -1;
364         }
365         for(i=0; i<_reg_htable_gc->htsize; i++)
366         {
367                 /* free entries */
368                 it = _reg_htable_gc->entries[i].byuuid;
369                 while(it)
370                 {
371                         it0 = it;
372                         it = it->next;
373                         shm_free(it0);
374                 }
375                 _reg_htable_gc->entries[i].byuuid = NULL;
376                 _reg_htable_gc->entries[i].isize=0;
377                 it = _reg_htable_gc->entries[i].byuser;
378                 while(it)
379                 {
380                         it0 = it;
381                         it = it->next;
382                         shm_free(it0->r);
383                         shm_free(it0);
384                 }
385                 _reg_htable_gc->entries[i].byuser = NULL;
386                 _reg_htable_gc->entries[i].usize = 0;
387         }
388         /* Reset all counters */
389         counter_reset(regtotal);
390         counter_reset(regactive);
391         counter_reset(regdisabled);
392         return 0;
393 }
394
395 /**
396  *
397  */
398 int uac_reg_ht_shift(void)
399 {
400         time_t tn;
401         int i;
402
403         if(_reg_htable==NULL || _reg_htable_gc==NULL)
404         {
405                 LM_ERR("data struct invalid\n");
406                 return -1;
407         }
408         tn = time(NULL);
409
410         lock_get(_reg_htable_gc_lock);
411         if(_reg_htable_gc->stime > tn - _uac_reg_gc_interval) {
412                 lock_release(_reg_htable_gc_lock);
413                 LM_ERR("shifting in-memory table is not possible in less than %d secs\n",
414                                 _uac_reg_gc_interval);
415                 return -1;
416         }
417         uac_reg_reset_ht_gc();
418         for(i=0; i<_reg_htable->htsize; i++)
419         {
420                 /* shift entries */
421                 _reg_htable_gc->entries[i].byuuid = _reg_htable->entries[i].byuuid;
422                 _reg_htable_gc->entries[i].byuser = _reg_htable->entries[i].byuser;
423                 _reg_htable_gc->stime = time(NULL);
424
425                 /* reset active table entries */
426                 _reg_htable->entries[i].byuuid = NULL;
427                 _reg_htable->entries[i].isize=0;
428                 _reg_htable->entries[i].byuser = NULL;
429                 _reg_htable->entries[i].usize = 0;
430         }
431         lock_release(_reg_htable_gc_lock);
432         return 0;
433 }
434
435 #define reg_compute_hash(_s)            get_hash1_raw((_s)->s,(_s)->len)
436 #define reg_get_entry(_h,_size)         ((_h)&((_size)-1))
437
438 /**
439  *
440  */
441 int reg_ht_add_byuuid(reg_uac_t *reg)
442 {
443         unsigned int slot;
444         reg_item_t *ri = NULL;
445
446         if(_reg_htable==NULL)
447         {
448                 LM_ERR("reg hash table not initialized\n");
449                 return -1;
450         }
451
452         ri = (reg_item_t*)shm_malloc(sizeof(reg_item_t));
453         if(ri==NULL)
454         {
455                 LM_ERR("no more shm\n");
456                 return -1;
457         }
458         memset(ri, 0, sizeof(reg_item_t));
459         slot = reg_get_entry(reg->h_uuid, _reg_htable->htsize);
460         ri->r = reg;
461         lock_get(&_reg_htable->entries[slot].lock);
462         ri->next = _reg_htable->entries[slot].byuuid;
463         _reg_htable->entries[slot].byuuid = ri;
464         _reg_htable->entries[slot].isize++;
465         lock_release(&_reg_htable->entries[slot].lock);
466         return 0;
467 }
468
469 /**
470  *
471  */
472 int reg_ht_add_byuser(reg_uac_t *reg)
473 {
474         unsigned int slot;
475         reg_item_t *ri = NULL;
476
477         if(_reg_htable==NULL)
478         {
479                 LM_ERR("reg hash table not initialized\n");
480                 return -1;
481         }
482
483         ri = (reg_item_t*)shm_malloc(sizeof(reg_item_t));
484         if(ri==NULL)
485         {
486                 LM_ERR("no more shm\n");
487                 return -1;
488         }
489         memset(ri, 0, sizeof(reg_item_t));
490         slot = reg_get_entry(reg->h_user, _reg_htable->htsize);
491         ri->r = reg;
492         lock_get(&_reg_htable->entries[slot].lock);
493         ri->next = _reg_htable->entries[slot].byuser;
494         _reg_htable->entries[slot].byuser = ri;
495         _reg_htable->entries[slot].usize++;
496         lock_release(&_reg_htable->entries[slot].lock);
497         return 0;
498 }
499
500 #define reg_copy_shm(dst, src, bsize) do { \
501                 if((src)->s!=NULL) { \
502                         (dst)->s = p; \
503                         strncpy((dst)->s, (src)->s, (src)->len); \
504                         (dst)->len = (src)->len; \
505                         (dst)->s[(dst)->len] = '\0'; \
506                         p = p + ((bsize)!=0?(bsize):(dst)->len) + 1; \
507                 } \
508         } while(0);
509
510 /**
511  *
512  */
513 int reg_ht_add(reg_uac_t *reg)
514 {
515         int len;
516         reg_uac_t *nr = NULL;
517         char *p;
518         int i;
519
520         if(reg==NULL || _reg_htable==NULL)
521         {
522                 LM_ERR("bad parameters: %p/%p\n", reg, _reg_htable);
523                 return -1;
524         }
525         len = reg->l_uuid.len + 1
526                 + reg->l_username.len + 1
527                 + reg->l_domain.len + 1
528                 + reg->r_username.len + 1
529                 + reg->r_domain.len + 1
530                 + reg->realm.len + 1
531                 + reg->auth_proxy.len + 1
532                 + reg->auth_username.len + 1
533                 + reg->auth_password.len + 1
534                 + reg->auth_ha1.len + 1
535                 + reg->socket.len + 1
536                 + (reg_keep_callid ? UAC_REG_TM_CALLID_SIZE : 0) + 1;
537         nr = (reg_uac_t*)shm_malloc(sizeof(reg_uac_t) + len);
538         if(nr==NULL)
539         {
540                 LM_ERR("no more shm\n");
541                 return -1;
542         }
543         memset(nr, 0, sizeof(reg_uac_t) + len);
544         nr->expires = reg->expires;
545         nr->flags   = reg->flags;
546         if (reg->reg_delay)
547                 nr->reg_delay = reg->reg_delay;
548         else if (reg_random_delay>0)
549                 nr->reg_delay = kam_rand() % reg_random_delay;
550         nr->reg_init  = time(NULL);
551         nr->h_uuid = reg_compute_hash(&reg->l_uuid);
552         nr->h_user = reg_compute_hash(&reg->l_username);
553
554         p = (char*)nr + sizeof(reg_uac_t);
555
556         reg_copy_shm(&nr->l_uuid, &reg->l_uuid, 0);
557         reg_copy_shm(&nr->l_username, &reg->l_username, 0);
558         reg_copy_shm(&nr->l_domain, &reg->l_domain, 0);
559         reg_copy_shm(&nr->r_username, &reg->r_username, 0);
560         reg_copy_shm(&nr->r_domain, &reg->r_domain, 0);
561         reg_copy_shm(&nr->realm, &reg->realm, 0);
562         reg_copy_shm(&nr->auth_proxy, &reg->auth_proxy, 0);
563         reg_copy_shm(&nr->auth_username, &reg->auth_username, 0);
564         reg_copy_shm(&nr->auth_password, &reg->auth_password, 0);
565         reg_copy_shm(&nr->auth_ha1, &reg->auth_ha1, 0);
566         reg_copy_shm(&nr->socket, &reg->socket, 0);
567         reg_copy_shm(&nr->callid, &str_empty, reg_keep_callid ? UAC_REG_TM_CALLID_SIZE : 0);
568
569         for(i=0; i<nr->auth_ha1.len; i++) {
570                 /* ha1 to lowercase */
571                 if(nr->auth_ha1.s[i] >= 'A' && nr->auth_ha1.s[i] <= 'F') {
572                         nr->auth_ha1.s[i] += 32;
573                 }
574         }
575
576         reg_ht_add_byuser(nr);
577         reg_ht_add_byuuid(nr);
578         counter_inc(regtotal);
579
580         LM_DBG("added uuid: %.*s - l_user: %.*s\n", nr->l_uuid.len, nr->l_uuid.s,
581                         nr->l_username.len, nr->l_username.s);
582         return 0;
583 }
584
585
586  /**
587   *
588   */
589 int reg_ht_rm(reg_uac_t *reg)
590 {
591         unsigned int slot1, slot2;
592         reg_item_t *it = NULL;
593         reg_item_t *prev = NULL;
594         int found = 0;
595
596         if (reg == NULL)
597         {
598                 LM_ERR("bad parameter\n");
599                 return -1;
600         }
601
602         /* by uuid */
603         slot1 = reg_get_entry(reg->h_uuid, _reg_htable->htsize);
604         it = _reg_htable->entries[slot1].byuuid;
605         while (it)
606         {
607                 if (it->r == reg)
608                 {
609                         if (prev)
610                                 prev->next=it->next;
611                         else
612                                 _reg_htable->entries[slot1].byuuid = it->next;
613                         _reg_htable->entries[slot1].isize--;
614                         shm_free(it);
615                         found = 1;
616                         break;
617                 }
618                 prev = it;
619                 it = it->next;
620         }
621
622         /* by user */
623         prev = NULL;
624         slot2 = reg_get_entry(reg->h_user, _reg_htable->htsize);
625         if (slot2 != slot1) {
626                 lock_get(&_reg_htable->entries[slot2].lock);
627         }
628         it = _reg_htable->entries[slot2].byuser;
629         while (it)
630         {
631                 if (it->r == reg)
632                 {
633                         if (prev)
634                                 prev->next=it->next;
635                         else
636                                 _reg_htable->entries[slot2].byuser = it->next;
637                         _reg_htable->entries[slot2].usize--;
638                         shm_free(it);
639                         break;
640                 }
641                 prev = it;
642                 it = it->next;
643         }
644
645         shm_free(reg);
646         if (slot2 != slot1) {
647                 lock_release(&_reg_htable->entries[slot2].lock);
648         }
649         lock_release(&_reg_htable->entries[slot1].lock);
650
651         if (found) {
652                 counter_add(regtotal, -1);
653                 if(reg->flags & UAC_REG_ONLINE)
654                         counter_add(regactive, -1);
655                 if(reg->flags & UAC_REG_DISABLED)
656                         counter_add(regdisabled, -1);
657         }
658         return 0;
659 }
660
661
662 reg_uac_t *reg_ht_get_byuuid(str *uuid)
663 {
664         unsigned int hash;
665         unsigned int slot;
666         reg_item_t *it = NULL;
667
668         if(_reg_htable==NULL)
669         {
670                 LM_ERR("reg hash table not initialized\n");
671                 return NULL;
672         }
673
674         hash = reg_compute_hash(uuid);
675         slot = reg_get_entry(hash, _reg_htable->htsize);
676         lock_get(&_reg_htable->entries[slot].lock);
677         it = _reg_htable->entries[slot].byuuid;
678         while(it)
679         {
680                 if((it->r->h_uuid==hash) && (it->r->l_uuid.len==uuid->len)
681                                 && (strncmp(it->r->l_uuid.s, uuid->s, uuid->len)==0))
682                 {
683                         it->r->lock = &_reg_htable->entries[slot].lock;
684                         return it->r;
685                 }
686                 it = it->next;
687         }
688         lock_release(&_reg_htable->entries[slot].lock);
689         return NULL;
690 }
691
692 /**
693  *
694  */
695 reg_uac_t *reg_ht_get_byuser(str *user, str *domain)
696 {
697         unsigned int hash;
698         unsigned int slot;
699         reg_item_t *it = NULL;
700
701         if(_reg_htable==NULL)
702         {
703                 LM_ERR("reg hash table not initialized\n");
704                 return NULL;
705         }
706
707         hash = reg_compute_hash(user);
708         slot = reg_get_entry(hash, _reg_htable->htsize);
709         lock_get(&_reg_htable->entries[slot].lock);
710         it = _reg_htable->entries[slot].byuser;
711         while(it)
712         {
713                 if((it->r->h_user==hash) && (it->r->l_username.len==user->len)
714                                 && (strncmp(it->r->l_username.s, user->s, user->len)==0))
715                 {
716                         if(domain!=NULL && domain->s!=NULL)
717                         {
718                                 if((it->r->l_domain.len==domain->len)
719                                                 && (strncmp(it->r->l_domain.s, domain->s, domain->len)==0))
720                                 {
721                                         it->r->lock = &_reg_htable->entries[slot].lock;
722                                         return it->r;
723                                 }
724                         } else {
725                                 it->r->lock = &_reg_htable->entries[slot].lock;
726                                 return it->r;
727                         }
728                 }
729                 it = it->next;
730         }
731         lock_release(&_reg_htable->entries[slot].lock);
732         return NULL;
733 }
734
735 int reg_ht_get_byfilter(reg_uac_t **reg, str *attr, str *val)
736 {
737         int i;
738         str *rval;
739         reg_item_t *it;
740
741         /* try to use the hash table indices */
742         if(attr->len==6 && strncmp(attr->s, "l_uuid", 6)==0) {
743                 *reg = reg_ht_get_byuuid(val);
744                 return *reg != NULL;
745         }
746         if(attr->len==10 && strncmp(attr->s, "l_username", 10)==0) {
747                 *reg = reg_ht_get_byuser(val, NULL);
748                 return *reg != NULL;
749         }
750
751         /* check _all_ records */
752         for(i=0; i<_reg_htable->htsize; i++)
753         {
754                 lock_get(&_reg_htable->entries[i].lock);
755                 /* walk through entries */
756                 it = _reg_htable->entries[i].byuuid;
757                 while(it)
758                 {
759                         if(attr->len==10 && strncmp(attr->s, "r_username", 10)==0) {
760                                 rval = &it->r->r_username;
761                         } else if(attr->len==13 && strncmp(attr->s, "auth_username", 13)==0) {
762                                 rval = &it->r->auth_username;
763                         } else {
764                                 lock_release(&_reg_htable->entries[i].lock);
765                                 LM_ERR("unsupported filter attribute %.*s\n", attr->len, attr->s);
766                                 return -1;
767                         }
768
769                         if(rval->len==val->len && strncmp(val->s, rval->s, val->len)==0) {
770                                 /* found */
771                                 *reg = it->r;
772                                 (*reg)->lock = &_reg_htable->entries[i].lock;
773                                 return 1;
774                         }
775                         it = it->next;
776                 }
777                 lock_release(&_reg_htable->entries[i].lock);
778         }
779         *reg = NULL;
780         return 0;
781 }
782
783 int uac_reg_tmdlg(dlg_t *tmdlg, sip_msg_t *rpl)
784 {
785         if(tmdlg==NULL || rpl==NULL)
786                 return -1;
787
788         if (parse_headers(rpl, HDR_EOH_F, 0) < 0) {
789                 LM_ERR("error while parsing all headers in the reply\n");
790                 return -1;
791         }
792         if(parse_to_header(rpl)<0 || parse_from_header(rpl)<0) {
793                 LM_ERR("error while parsing From/To headers in the reply\n");
794                 return -1;
795         }
796         memset(tmdlg, 0, sizeof(dlg_t));
797
798         str2int(&(get_cseq(rpl)->number), &tmdlg->loc_seq.value);
799         tmdlg->loc_seq.is_set = 1;
800
801         tmdlg->id.call_id = rpl->callid->body;
802         trim(&tmdlg->id.call_id);
803
804         if (get_from(rpl)->tag_value.len) {
805                 tmdlg->id.loc_tag = get_from(rpl)->tag_value;
806         }
807         tmdlg->loc_uri = get_from(rpl)->uri;
808         tmdlg->rem_uri = get_to(rpl)->uri;
809         tmdlg->state= DLG_CONFIRMED;
810         return 0;
811 }
812
813 void uac_reg_tm_callback( struct cell *t, int type, struct tmcb_params *ps)
814 {
815         char *uuid;
816         str suuid;
817         reg_uac_t *ri = NULL;
818         contact_t* c;
819         int expires;
820         struct sip_uri puri;
821         struct hdr_field *hdr;
822         HASHHEX response;
823         str *new_auth_hdr = NULL;
824         static struct authenticate_body auth;
825         uac_credential_t cred;
826         char  b_ruri[MAX_URI_SIZE];
827         str   s_ruri;
828         char  b_hdrs[MAX_UACH_SIZE];
829         str   s_hdrs;
830         uac_req_t uac_r;
831         str method = {"REGISTER", 8};
832         int ret;
833         dlg_t tmdlg;
834
835         if(ps->param==NULL || *ps->param==0)
836         {
837                 LM_DBG("uuid not received\n");
838                 return;
839         }
840         uuid = *((char**)ps->param);
841         LM_DBG("completed with status %d [uuid: %s]\n",
842                         ps->code, uuid);
843         suuid.s = uuid;
844         suuid.len = strlen(suuid.s);
845         ri = reg_ht_get_byuuid(&suuid);
846
847         if(ri==NULL)
848         {
849                 LM_DBG("no user with uuid %s\n", uuid);
850                 goto done;
851         }
852
853         if(ps->code == 200)
854         {
855                 if (parse_headers(ps->rpl, HDR_EOH_F, 0) == -1)
856                 {
857                         LM_ERR("failed to parse headers\n");
858                         goto error;
859                 }
860                 if (ps->rpl->contact==NULL)
861                 {
862                         LM_ERR("no Contact found\n");
863                         goto error;
864                 }
865                 if (parse_contact(ps->rpl->contact) < 0)
866                 {
867                         LM_ERR("failed to parse Contact HF\n");
868                         goto error;
869                 }
870                 if (((contact_body_t*)ps->rpl->contact->parsed)->star)
871                 {
872                         LM_DBG("* Contact found\n");
873                         goto done;
874                 }
875
876                 if (contact_iterator(&c, ps->rpl, 0) < 0)
877                         goto done;
878                 while(c)
879                 {
880                         if(parse_uri(c->uri.s, c->uri.len, &puri)!=0)
881                         {
882                                 LM_ERR("failed to parse c-uri\n");
883                                 goto error;
884                         }
885                         if(suuid.len==puri.user.len
886                                         && (strncmp(puri.user.s, suuid.s, suuid.len)==0))
887                         {
888                                 /* calculate expires */
889                                 expires=0;
890                                 if(c->expires==NULL || c->expires->body.len<=0)
891                                 {
892                                         if(ps->rpl->expires!=NULL && parse_expires(ps->rpl->expires)==0)
893                                                 expires = ((exp_body_t *)ps->rpl->expires->parsed)->val;
894                                 } else {
895                                         str2int(&c->expires->body, (unsigned int*)(&expires));
896                                 }
897                                 ri->timer_expires = ri->timer_expires + expires;
898                                 ri->flags |= UAC_REG_ONLINE;
899                                 if (reg_keep_callid && ps->rpl->callid->body.len < UAC_REG_TM_CALLID_SIZE) {
900                                         ri->callid.len = ps->rpl->callid->body.len;
901                                         memcpy(ri->callid.s, ps->rpl->callid->body.s, ri->callid.len);
902                                         str2int(&(get_cseq(ps->rpl)->number), &ri->cseq);
903                                 }
904                                 goto done;
905                         }
906                         if (contact_iterator(&c, ps->rpl, c) < 0)
907                         {
908                                 LM_DBG("local contact not found\n");
909                                 goto done;
910                         }
911                 }
912
913                 LM_DBG("sip response %d while registering [%.*s] with no match\n",
914                                 ps->code, ri->l_uuid.len, ri->l_uuid.s);
915                 goto done;
916         }
917
918         if(ps->code == 401 || ps->code == 407)
919         {
920                 if(ri->flags & UAC_REG_AUTHSENT)
921                 {
922                         LM_ERR("authentication failed for <%.*s>\n",
923                                         ri->l_uuid.len, ri->l_uuid.s);
924                         goto error;
925                 }
926                 hdr = get_autenticate_hdr(ps->rpl, ps->code);
927                 if (hdr==0)
928                 {
929                         LM_ERR("failed to extract authenticate hdr\n");
930                         goto error;
931                 }
932
933                 LM_DBG("auth header body [%.*s]\n",
934                                 hdr->body.len, hdr->body.s);
935
936                 if (parse_authenticate_body(&hdr->body, &auth)<0)
937                 {
938                         LM_ERR("failed to parse auth hdr body\n");
939                         goto error;
940                 }
941                 if (ri->realm.len>0) {
942                         /* only check if realms match if it is non-empty */
943                         if(auth.realm.len!=ri->realm.len
944                                         || strncmp(auth.realm.s, ri->realm.s, ri->realm.len)!=0)
945                         {
946                                 LM_ERR("realms do not match. requested realm: [%.*s]\n",
947                                                 auth.realm.len, auth.realm.s);
948                                 goto error;
949                         }
950                 }
951                 cred.aflags = 0;
952                 cred.realm = auth.realm;
953                 cred.user = ri->auth_username;
954                 if(ri->auth_ha1.len > 0) {
955                         cred.passwd = ri->auth_ha1;
956                         cred.aflags |= UAC_FLCRED_HA1;
957                 } else {
958                         cred.passwd = ri->auth_password;
959                 }
960                 cred.next = NULL;
961
962                 snprintf(b_ruri, MAX_URI_SIZE, "sip:%.*s",
963                                 ri->r_domain.len, ri->r_domain.s);
964                 s_ruri.s = b_ruri; s_ruri.len = strlen(s_ruri.s);
965
966                 do_uac_auth(&method, &s_ruri, &cred, &auth, response);
967                 new_auth_hdr=build_authorization_hdr(ps->code, &s_ruri, &cred,
968                                 &auth, response);
969                 if (new_auth_hdr==0)
970                 {
971                         LM_ERR("failed to build authorization hdr\n");
972                         goto error;
973                 }
974
975                 snprintf(b_hdrs, MAX_UACH_SIZE,
976                                 "Contact: <sip:%.*s@%.*s>\r\n"
977                                 "Expires: %d\r\n"
978                                 "%.*s",
979                                 ri->l_uuid.len, ri->l_uuid.s,
980                                 reg_contact_addr.len, reg_contact_addr.s,
981                                 ri->expires,
982                                 new_auth_hdr->len, new_auth_hdr->s);
983                 s_hdrs.s = b_hdrs; s_hdrs.len = strlen(s_hdrs.s);
984                 pkg_free(new_auth_hdr->s);
985
986                 memset(&uac_r, 0, sizeof(uac_r));
987                 if(uac_reg_tmdlg(&tmdlg, ps->rpl)<0)
988                 {
989                         LM_ERR("failed to build tm dialog\n");
990                         goto error;
991                 }
992                 tmdlg.rem_target = s_ruri;
993                 if(ri->auth_proxy.len)
994                         tmdlg.dst_uri = ri->auth_proxy;
995                 uac_r.method = &method;
996                 uac_r.headers = &s_hdrs;
997                 uac_r.dialog = &tmdlg;
998                 uac_r.cb_flags = TMCB_LOCAL_COMPLETED;
999                 /* Callback function */
1000                 uac_r.cb  = uac_reg_tm_callback;
1001                 /* Callback parameter */
1002                 uac_r.cbp = (void*)uuid;
1003                 ret = uac_tmb.t_request_within(&uac_r);
1004
1005                 if(ret<0) {
1006                         LM_ERR("failed to send request with authentication for [%.*s]",
1007                                         ri->l_uuid.len, ri->l_uuid.s);
1008                         goto error;
1009                 }
1010
1011                 ri->flags |= UAC_REG_AUTHSENT;
1012                 lock_release(ri->lock);
1013                 return;
1014         }
1015
1016         if (ps->code == 423)   /* Interval too brief, retry with longer expiry */
1017         {
1018                 if (parse_headers(ps->rpl, HDR_EOH_F, 0) == -1) {
1019                         LM_ERR("failed to parse headers\n");
1020                         goto error;
1021                 }
1022                 if(ps->rpl->min_expires!=NULL && parse_expires(ps->rpl->min_expires)==0) {
1023                         ri->expires = ((exp_body_t *)ps->rpl->min_expires->parsed)->val;
1024                 } else {
1025                         ri->expires *= 2;
1026                 }
1027                 LM_DBG("got 423 response while registering [%.*s], set new expires to %d\n",
1028                                 ri->l_uuid.len, ri->l_uuid.s, ri->expires);
1029                 /* Retry will be done on next timer interval */
1030                 goto done;
1031         } else
1032         {
1033                 LM_ERR("got sip response %d while registering [%.*s]\n",
1034                                 ps->code, ri->l_uuid.len, ri->l_uuid.s);
1035                 goto error;
1036         }
1037
1038 error:
1039         if(reg_retry_interval) {
1040                 ri->timer_expires = time(NULL) + reg_retry_interval;
1041         } else {
1042                 ri->flags |= UAC_REG_DISABLED;
1043                 counter_inc(regdisabled);
1044         }
1045         ri->cseq = 0;
1046 done:
1047         if(ri) {
1048                 ri->flags &= ~(UAC_REG_ONGOING|UAC_REG_AUTHSENT);
1049                 lock_release(ri->lock);
1050         }
1051         shm_free(uuid);
1052         counter_inc(regactive);
1053 }
1054
1055 int uac_reg_update(reg_uac_t *reg, time_t tn)
1056 {
1057         char *uuid;
1058         uac_req_t uac_r;
1059         str method = {"REGISTER", 8};
1060         int ret;
1061         char  b_ruri[MAX_URI_SIZE];
1062         str   s_ruri;
1063         char  b_turi[MAX_URI_SIZE];
1064         str   s_turi;
1065         char  b_hdrs[MAX_UACH_SIZE];
1066         str   s_hdrs;
1067         dlg_t tmdlg;
1068
1069         if(uac_tmb.t_request==NULL)
1070                 return -1;
1071         if(reg->expires==0)
1072                 return 1;
1073         if(reg->flags&UAC_REG_ONGOING) {
1074                 if (reg->timer_expires > tn - reg_retry_interval)
1075                         return 2;
1076                 LM_DBG("record marked as ongoing registration (%d) - resetting\n",
1077                                 (int)reg->flags);
1078                 reg->flags &= ~(UAC_REG_ONLINE|UAC_REG_AUTHSENT);
1079         }
1080         if(reg_active && *reg_active == 0)
1081                 return 4;
1082         if(reg->flags&UAC_REG_DISABLED)
1083                 return 4;
1084
1085         if(!(reg->flags & UAC_REG_INIT)) {
1086                 if(reg->reg_delay>0) {
1087                         if(tn < reg->reg_init+reg->reg_delay) {
1088                                 return 2;
1089                         }
1090                 }
1091                 reg->flags |= UAC_REG_INIT;
1092         }
1093
1094         if(reg->timer_expires > tn + reg_timer_interval + 3)
1095                 return 3;
1096         uuid = (char*)shm_malloc(reg->l_uuid.len+1);
1097         if(uuid==NULL)
1098         {
1099                 LM_ERR("no more shm\n");
1100                 return -1;
1101         }
1102         reg->timer_expires = tn;
1103         reg->flags |= UAC_REG_ONGOING;
1104         counter_add(regactive, -1);             /* Take it out of the active pool while re-registering */
1105         memcpy(uuid, reg->l_uuid.s, reg->l_uuid.len);
1106         uuid[reg->l_uuid.len] = '\0';
1107
1108         snprintf(b_ruri, MAX_URI_SIZE, "sip:%.*s",
1109                         reg->r_domain.len, reg->r_domain.s);
1110         s_ruri.s = b_ruri; s_ruri.len = strlen(s_ruri.s);
1111
1112         snprintf(b_turi, MAX_URI_SIZE, "sip:%.*s@%.*s",
1113                         reg->r_username.len, reg->r_username.s,
1114                         reg->r_domain.len, reg->r_domain.s);
1115         s_turi.s = b_turi; s_turi.len = strlen(s_turi.s);
1116
1117         snprintf(b_hdrs, MAX_UACH_SIZE,
1118                         "Contact: <sip:%.*s@%.*s>\r\n"
1119                         "Expires: %d\r\n",
1120                         reg->l_uuid.len, reg->l_uuid.s,
1121                         reg_contact_addr.len, reg_contact_addr.s,
1122                         reg->expires);
1123         s_hdrs.s = b_hdrs; s_hdrs.len = strlen(s_hdrs.s);
1124
1125         memset(&uac_r, '\0', sizeof(uac_r));
1126         uac_r.method = &method;
1127         uac_r.headers = &s_hdrs;
1128         uac_r.cb_flags = TMCB_LOCAL_COMPLETED;
1129         /* Callback function */
1130         uac_r.cb  = uac_reg_tm_callback;
1131         /* Callback parameter */
1132         uac_r.cbp = (void*)uuid;
1133
1134         if (reg_keep_callid && reg->flags & UAC_REG_ONLINE
1135                                 && reg->cseq > 0 && reg->cseq < 2147483638
1136                                 && reg->callid.len > 0)
1137         {
1138                 /* reregister, reuse callid and cseq */
1139                 memset(&tmdlg, 0, sizeof(dlg_t));
1140                 tmdlg.id.call_id = reg->callid;
1141                 tmdlg.loc_seq.value = reg->cseq;
1142                 tmdlg.loc_seq.is_set = 1;
1143                 tmdlg.rem_target = s_ruri;
1144                 tmdlg.loc_uri = s_turi;
1145                 tmdlg.rem_uri = s_turi;
1146                 tmdlg.state= DLG_CONFIRMED;
1147                 if(reg->auth_proxy.len)
1148                         tmdlg.dst_uri = reg->auth_proxy;
1149                 uac_r.dialog = &tmdlg;
1150
1151                 ret = uac_tmb.t_request_within(&uac_r);
1152         } else {
1153                 /* custom socket */
1154                 if(reg->socket.s != NULL && reg->socket.len > 0) {
1155                         LM_DBG("using custom socket %.*s to send request\n",
1156                                 reg->socket.len, reg->socket.s);
1157                         uac_r.ssock = &reg->socket;
1158                 }
1159                 /* default socket */
1160                 else {
1161                         if(uac_default_socket.s != NULL && uac_default_socket.len > 0) {
1162                                 LM_DBG("using configured default_socket to send request\n");
1163                                 uac_r.ssock = &uac_default_socket;
1164                         }
1165                 }
1166                 ret = uac_tmb.t_request(&uac_r,  /* UAC Req */
1167                                 &s_ruri, /* Request-URI */
1168                                 &s_turi, /* To */
1169                                 &s_turi, /* From */
1170                                 (reg->auth_proxy.len)?&reg->auth_proxy:NULL /* outbound uri */
1171                                 );
1172         }
1173         reg->flags &= ~UAC_REG_ONLINE;
1174
1175         if(ret<0)
1176         {
1177                 LM_ERR("failed to send request for [%.*s]", reg->l_uuid.len, reg->l_uuid.s);
1178                 shm_free(uuid);
1179                 if (reg_retry_interval)
1180                         reg->timer_expires = (tn ? tn : time(NULL)) + reg_retry_interval;
1181                 else {
1182                         reg->flags |= UAC_REG_DISABLED;
1183                         counter_inc(regdisabled);
1184                 }
1185                 reg->flags &= ~UAC_REG_ONGOING;
1186                 return -1;
1187         }
1188         return 0;
1189 }
1190
1191 /**
1192  *
1193  */
1194 void uac_reg_timer(unsigned int ticks)
1195 {
1196         int i;
1197         reg_item_t *it = NULL;
1198         time_t tn;
1199
1200         if(_reg_htable==NULL)
1201                 return;
1202
1203         tn = time(NULL);
1204         for(i=0; i<_reg_htable->htsize; i++)
1205         {
1206                 /* walk through entries */
1207                 lock_get(&_reg_htable->entries[i].lock);
1208                 it = _reg_htable->entries[i].byuuid;
1209                 while(it)
1210                 {
1211                         uac_reg_update(it->r, tn);
1212                         it = it->next;
1213                 }
1214                 lock_release(&_reg_htable->entries[i].lock);
1215         }
1216
1217         if(_reg_htable_gc!=NULL)
1218         {
1219                 lock_get(_reg_htable_gc_lock);
1220                 if(_reg_htable_gc->stime!=0
1221                                 && _reg_htable_gc->stime < tn - _uac_reg_gc_interval)
1222                         uac_reg_reset_ht_gc();
1223                 lock_release(_reg_htable_gc_lock);
1224         }
1225 }
1226
1227 static int uac_reg_check_password(reg_uac_t *reg)
1228 {
1229         int i;
1230
1231         if(reg->auth_password.len<=0 && reg->auth_ha1.len<=0) {
1232                 LM_ERR("no password value provided - ignoring record\n");
1233                 return -1;
1234         }
1235
1236         if(reg->auth_ha1.len > 0 && reg->auth_ha1.len != HASHHEXLEN) {
1237                 LM_ERR("invalid HA2 length: %d - ignoring record\n", reg->auth_ha1.len);
1238                 return -1;
1239         }
1240         for(i=0; i<reg->auth_ha1.len; i++) {
1241                 if(!((reg->auth_ha1.s[i]>='0' && reg->auth_ha1.s[i]<'9')
1242                                 || (reg->auth_ha1.s[i]>='a' && reg->auth_ha1.s[i]<='f')
1243                                 || (reg->auth_ha1.s[i]>='A' && reg->auth_ha1.s[i]<='F'))) {
1244                         LM_ERR("invalid char %d in HA1 string: %.*s\n", i,
1245                                         reg->auth_ha1.len, reg->auth_ha1.s);
1246                         return -1;
1247                 }
1248         }
1249
1250         return 0;
1251 }
1252
1253 #define reg_db_set_attr(attr, pos, eval) do { \
1254         if(!VAL_NULL(&RES_ROWS(db_res)[i].values[pos])) { \
1255                 reg->attr.s = \
1256                                 (char*)(RES_ROWS(db_res)[i].values[pos].val.string_val); \
1257                 reg->attr.len = strlen(reg->attr.s); \
1258                 if(reg->attr.len == 0) { \
1259                         if(eval == 0) { \
1260                                 LM_ERR("empty value not allowed for column[%d]='%.*s' - ignoring record\n", \
1261                                                 pos, db_cols[pos]->len, db_cols[pos]->s); \
1262                                 return -1; \
1263                         }  else { \
1264                                 reg->attr.s = NULL; \
1265                         } \
1266                 } \
1267         } \
1268 } while(0);
1269
1270
1271 static int uac_reg_db_to_reg(reg_uac_t *reg, db1_res_t* db_res, int i, db_key_t *db_cols)
1272 {
1273         memset(reg, 0, sizeof(reg_uac_t));;
1274         /* check for NULL values ?!?! */
1275         reg_db_set_attr(l_uuid, 0, 0);
1276         reg_db_set_attr(l_username, 1, 0);
1277         reg_db_set_attr(l_domain, 2, 0);
1278         reg_db_set_attr(r_username, 3, 0);
1279         reg_db_set_attr(r_domain, 4, 0);
1280         /* realm may be empty */
1281         reg_db_set_attr(realm, 5, 1);
1282         reg_db_set_attr(auth_username, 6, 0);
1283         reg_db_set_attr(auth_password, 7, 1);
1284         reg_db_set_attr(auth_ha1, 8, 1);
1285         if(uac_reg_check_password(reg) < 0) {
1286                 return -1;
1287         }
1288         reg_db_set_attr(auth_proxy, 9, 0);
1289         reg->expires = (unsigned int)RES_ROWS(db_res)[i].values[10].val.int_val;
1290         reg->flags = (unsigned int)RES_ROWS(db_res)[i].values[11].val.int_val;
1291         reg->reg_delay = (unsigned int)RES_ROWS(db_res)[i].values[12].val.int_val;
1292
1293         /* socket may be empty */
1294         reg_db_set_attr(socket, 13, 1);
1295
1296         return 0;
1297 }
1298
1299
1300 /**
1301  *
1302  */
1303 int uac_reg_load_db(void)
1304 {
1305         db1_con_t *reg_db_con = NULL;
1306         db_func_t reg_dbf;
1307         reg_uac_t reg;
1308         db_key_t db_cols[14] = {
1309                 &l_uuid_column,
1310                 &l_username_column,
1311                 &l_domain_column,
1312                 &r_username_column,
1313                 &r_domain_column,
1314                 &realm_column,
1315                 &auth_username_column,
1316                 &auth_password_column,
1317                 &auth_ha1_column,
1318                 &auth_proxy_column,
1319                 &expires_column,
1320                 &flags_column,
1321                 &reg_delay_column,
1322                 &socket_column
1323         };
1324         db1_res_t* db_res = NULL;
1325         int i, ret;
1326
1327         /* binding to db module */
1328         if(reg_db_url.s==NULL)
1329         {
1330                 LM_ERR("no db url\n");
1331                 return -1;
1332         }
1333
1334         if(db_bind_mod(&reg_db_url, &reg_dbf))
1335         {
1336                 LM_ERR("database module not found\n");
1337                 return -1;
1338         }
1339
1340         if (!DB_CAPABILITY(reg_dbf, DB_CAP_ALL))
1341         {
1342                 LM_ERR("database module does not "
1343                                 "implement all functions needed by the module\n");
1344                 return -1;
1345         }
1346
1347         /* open a connection with the database */
1348         reg_db_con = reg_dbf.init(&reg_db_url);
1349         if(reg_db_con==NULL)
1350         {
1351                 LM_ERR("failed to connect to the database\n");
1352                 return -1;
1353         }
1354
1355         if(db_check_table_version(&reg_dbf, reg_db_con, &reg_db_table, UACREG_TABLE_VERSION) < 0) {
1356                 DB_TABLE_VERSION_ERROR(reg_db_table);
1357                 return -1;
1358         }
1359
1360         if (reg_dbf.use_table(reg_db_con, &reg_db_table) < 0)
1361         {
1362                 LM_ERR("failed to use_table\n");
1363                 return -1;
1364         }
1365
1366         if (DB_CAPABILITY(reg_dbf, DB_CAP_FETCH)) {
1367                 if(reg_dbf.query(reg_db_con, 0, 0, 0, db_cols, 0, 13, 0, 0) < 0)
1368                 {
1369                         LM_ERR("Error while querying db\n");
1370                         return -1;
1371                 }
1372                 if(reg_dbf.fetch_result(reg_db_con, &db_res, reg_fetch_rows)<0)
1373                 {
1374                         LM_ERR("Error while fetching result\n");
1375                         if (db_res)
1376                                 reg_dbf.free_result(reg_db_con, db_res);
1377                         goto error;
1378                 } else {
1379                         if(RES_ROW_N(db_res)==0)
1380                         {
1381                                 goto done;
1382                         }
1383                 }
1384         } else {
1385                 if((ret=reg_dbf.query(reg_db_con, NULL, NULL, NULL, db_cols,
1386                                                 0, 13, 0, &db_res))!=0
1387                                 || RES_ROW_N(db_res)<=0 )
1388                 {
1389                         reg_dbf.free_result(reg_db_con, db_res);
1390                         if( ret==0)
1391                         {
1392                                 return 0;
1393                         } else {
1394                                 goto error;
1395                         }
1396                 }
1397         }
1398
1399         do {
1400                 for(i=0; i<RES_ROW_N(db_res); i++)
1401                 {
1402                         if(uac_reg_db_to_reg(&reg, db_res, i, db_cols) < 0)
1403                                 continue;
1404                         if(reg_ht_add(&reg)<0)
1405                         {
1406                                 LM_ERR("Error adding reg to htable\n");
1407                                 goto error;
1408                         }
1409                 }
1410                 if (DB_CAPABILITY(reg_dbf, DB_CAP_FETCH)) {
1411                         if(reg_dbf.fetch_result(reg_db_con, &db_res, reg_fetch_rows)<0) {
1412                                 LM_ERR("Error while fetching!\n");
1413                                 if (db_res)
1414                                         reg_dbf.free_result(reg_db_con, db_res);
1415                                 goto error;
1416                         }
1417                 } else {
1418                         break;
1419                 }
1420         }  while(RES_ROW_N(db_res)>0);
1421         reg_dbf.free_result(reg_db_con, db_res);
1422         reg_dbf.close(reg_db_con);
1423
1424 done:
1425         return 0;
1426
1427 error:
1428         if (reg_db_con) {
1429                 reg_dbf.free_result(reg_db_con, db_res);
1430                 reg_dbf.close(reg_db_con);
1431         }
1432         return -1;
1433 }
1434
1435 /**
1436  *
1437  */
1438 int uac_reg_db_refresh(str *pl_uuid)
1439 {
1440         db1_con_t *reg_db_con = NULL;
1441         db_func_t reg_dbf;
1442         reg_uac_t reg;
1443         reg_uac_t *cur_reg;
1444         db_key_t db_cols[14] = {
1445                 &l_uuid_column,
1446                 &l_username_column,
1447                 &l_domain_column,
1448                 &r_username_column,
1449                 &r_domain_column,
1450                 &realm_column,
1451                 &auth_username_column,
1452                 &auth_password_column,
1453                 &auth_ha1_column,
1454                 &auth_proxy_column,
1455                 &expires_column,
1456                 &flags_column,
1457                 &reg_delay_column,
1458                 &socket_column
1459         };
1460         db_key_t db_keys[1] = {&l_uuid_column};
1461         db_val_t db_vals[1];
1462
1463         db1_res_t* db_res = NULL;
1464         int ret;
1465
1466         /* binding to db module */
1467         if(reg_db_url.s==NULL)
1468         {
1469                 LM_ERR("no db url\n");
1470                 return -1;
1471         }
1472
1473         if(db_bind_mod(&reg_db_url, &reg_dbf))
1474         {
1475                 LM_ERR("database module not found\n");
1476                 return -1;
1477         }
1478
1479         if (!DB_CAPABILITY(reg_dbf, DB_CAP_ALL))
1480         {
1481                 LM_ERR("database module does not "
1482                                 "implement all functions needed by the module\n");
1483                 return -1;
1484         }
1485
1486         /* open a connection with the database */
1487         reg_db_con = reg_dbf.init(&reg_db_url);
1488         if(reg_db_con==NULL)
1489         {
1490                 LM_ERR("failed to connect to the database\n");
1491                 return -1;
1492         }
1493         if (reg_dbf.use_table(reg_db_con, &reg_db_table) < 0)
1494         {
1495                 LM_ERR("failed to use_table\n");
1496                 return -1;
1497         }
1498
1499         db_vals[0].type = DB1_STR;
1500         db_vals[0].nul = 0;
1501         db_vals[0].val.str_val.s = pl_uuid->s;
1502         db_vals[0].val.str_val.len = pl_uuid->len;
1503
1504         if((ret=reg_dbf.query(reg_db_con, db_keys, NULL, db_vals, db_cols,
1505                                         1 /*nr keys*/, 13 /*nr cols*/, 0, &db_res))!=0
1506                         || RES_ROW_N(db_res)<=0 )
1507         {
1508                 reg_dbf.free_result(reg_db_con, db_res);
1509                 if( ret==0)
1510                 {
1511                         return 0;
1512                 } else {
1513                         goto error;
1514                 }
1515         }
1516
1517         if (uac_reg_db_to_reg(&reg, db_res, 0, db_cols)==0)
1518         {
1519                 lock_get(_reg_htable_gc_lock);
1520                 if((cur_reg=reg_ht_get_byuuid(pl_uuid))!=NULL)
1521                 {
1522                         reg.flags |= (cur_reg->flags & (UAC_REG_ONGOING | UAC_REG_AUTHSENT));
1523                         reg_ht_rm(cur_reg);
1524                 }
1525                 if(reg_ht_add(&reg)<0)
1526                 {
1527                         lock_release(_reg_htable_gc_lock);
1528                         LM_ERR("Error adding reg to htable\n");
1529                         goto error;
1530                 }
1531                 lock_release(_reg_htable_gc_lock);
1532         }
1533
1534         reg_dbf.free_result(reg_db_con, db_res);
1535         reg_dbf.close(reg_db_con);
1536
1537         return 1;
1538
1539 error:
1540         if (reg_db_con) {
1541                 reg_dbf.free_result(reg_db_con, db_res);
1542                 reg_dbf.close(reg_db_con);
1543         }
1544         return -1;
1545 }
1546
1547 /**
1548  *
1549  */
1550 int uac_reg_refresh(sip_msg_t *msg, str *l_uuid)
1551 {
1552         int ret;
1553
1554         if(l_uuid==NULL || l_uuid->s==NULL || l_uuid->len<=0) {
1555                 LM_ERR("invalid parameters\n");
1556                 return -1;
1557         }
1558
1559         ret = uac_reg_db_refresh(l_uuid);
1560         if(ret==0) {
1561                 LM_WARN("record not found: %.*s\n", l_uuid->len, l_uuid->s);
1562                 return -1;
1563         } else if(ret<0) {
1564                 LM_WARN("failed to refresh record: %.*s - check log messages\n",
1565                                 l_uuid->len, l_uuid->s);
1566                 return -1;
1567         }
1568
1569         return 1;
1570 }
1571
1572 /**
1573  *
1574  */
1575 int  uac_reg_lookup(struct sip_msg *msg, str *src, pv_spec_t *dst, int mode)
1576 {
1577         char  b_ruri[MAX_URI_SIZE];
1578         str   s_ruri;
1579         struct sip_uri puri;
1580         reg_uac_t *reg = NULL;
1581         pv_value_t val;
1582
1583         if(!pv_is_w(dst))
1584         {
1585                 LM_ERR("dst is not w/\n");
1586                 return -1;
1587         }
1588         if(mode==0)
1589         {
1590                 reg = reg_ht_get_byuuid(src);
1591                 if(reg==NULL)
1592                 {
1593                         LM_DBG("no uuid: %.*s\n", src->len, src->s);
1594                         return -1;
1595                 }
1596                 snprintf(b_ruri, MAX_URI_SIZE, "sip:%.*s@%.*s",
1597                                 reg->l_username.len, reg->l_username.s,
1598                                 reg->l_domain.len, reg->l_domain.s);
1599                 s_ruri.s = b_ruri; s_ruri.len = strlen(s_ruri.s);
1600         } else {
1601                 if(parse_uri(src->s, src->len, &puri)!=0)
1602                 {
1603                         LM_ERR("failed to parse uri\n");
1604                         return -2;
1605                 }
1606                 reg = reg_ht_get_byuser(&puri.user, (reg_use_domain)?&puri.host:NULL);
1607                 if(reg==NULL)
1608                 {
1609                         LM_DBG("no user: %.*s\n", src->len, src->s);
1610                         return -1;
1611                 }
1612                 snprintf(b_ruri, MAX_URI_SIZE, "%.*s",
1613                                 reg->l_uuid.len, reg->l_uuid.s);
1614                 s_ruri.s = b_ruri; s_ruri.len = strlen(s_ruri.s);
1615         }
1616         lock_release(reg->lock);
1617         memset(&val, 0, sizeof(pv_value_t));
1618         val.flags |= PV_VAL_STR;
1619         val.rs = s_ruri;
1620         if(pv_set_spec_value(msg, dst, 0, &val)!=0)
1621                 return -1;
1622
1623         return 1;
1624 }
1625
1626 /**
1627  *
1628  */
1629 int uac_reg_status(struct sip_msg *msg, str *src, int mode)
1630 {
1631         struct sip_uri puri;
1632         reg_uac_t *reg = NULL;
1633         int ret;
1634
1635         if(mode==0)
1636         {
1637                 reg = reg_ht_get_byuuid(src);
1638                 if(reg==NULL)
1639                 {
1640                         LM_DBG("no uuid: %.*s\n", src->len, src->s);
1641                         return -1;
1642                 }
1643         } else {
1644                 if(parse_uri(src->s, src->len, &puri)!=0)
1645                 {
1646                         LM_ERR("failed to parse uri\n");
1647                         return -1;
1648                 }
1649                 reg = reg_ht_get_byuser(&puri.user, (reg_use_domain)?&puri.host:NULL);
1650                 if(reg==NULL)
1651                 {
1652                         LM_DBG("no user: %.*s\n", src->len, src->s);
1653                         return -1;
1654                 }
1655         }
1656
1657         if ((reg->flags & UAC_REG_ONLINE) && (reg->timer_expires > time(NULL)))
1658                 ret = 1;
1659         else if (reg->flags & UAC_REG_ONGOING)
1660                 ret = -2;
1661         else if (reg->flags & UAC_REG_DISABLED)
1662                 ret = -3;
1663         else
1664                 ret = -99;
1665
1666         lock_release(reg->lock);
1667         return ret;
1668 }
1669
1670 /**
1671  *
1672  */
1673 int uac_reg_request_to(struct sip_msg *msg, str *src, unsigned int mode)
1674 {
1675         char ruri[MAX_URI_SIZE];
1676         struct sip_uri puri;
1677         reg_uac_t *reg = NULL;
1678         pv_value_t val;
1679         struct action act;
1680         struct run_act_ctx ra_ctx;
1681
1682         switch(mode)
1683         {
1684                 case 0:
1685                         reg = reg_ht_get_byuuid(src);
1686                         break;
1687                 case 1:
1688                         if(reg_use_domain)
1689                         {
1690                                 if (parse_uri(src->s, src->len, &puri)!=0)
1691                                 {
1692                                         LM_ERR("failed to parse uri\n");
1693                                         return -2;
1694                                 }
1695                                 reg = reg_ht_get_byuser(&puri.user, &puri.host);
1696                         } else {
1697                                 reg = reg_ht_get_byuser(src, NULL);
1698                         }
1699                         break;
1700                 default:
1701                         LM_ERR("unknown mode: %d\n", mode);
1702                         return -1;
1703         }
1704
1705         if(reg==NULL)
1706         {
1707                 LM_DBG("no user: %.*s\n", src->len, src->s);
1708                 return -1;
1709         }
1710
1711         // Set uri ($ru)
1712         snprintf(ruri, MAX_URI_SIZE, "sip:%.*s@%.*s",
1713                         reg->r_username.len, reg->r_username.s,
1714                         reg->r_domain.len, reg->r_domain.s);
1715         memset(&act, 0, sizeof(act));
1716         act.type = SET_URI_T;
1717         act.val[0].type = STRING_ST;
1718         act.val[0].u.string = ruri;
1719         init_run_actions_ctx(&ra_ctx);
1720         if (do_action(&ra_ctx, &act, msg) < 0) {
1721                 LM_ERR("error while setting request uri\n");
1722                 goto error;
1723         }
1724
1725         // Set auth_proxy ($du)
1726         if (set_dst_uri(msg, &reg->auth_proxy) < 0) {
1727                 LM_ERR("error while setting outbound proxy\n");
1728                 goto error;
1729         }
1730
1731         memset(&val, 0, sizeof(pv_value_t));
1732         val.flags |= PV_VAL_STR;
1733
1734         // Set auth_realm
1735         val.rs = reg->realm;
1736         if(pv_set_spec_value(msg, &auth_realm_spec, 0, &val)!=0) {
1737                 LM_ERR("error while setting auth_realm\n");
1738                 goto error;
1739         }
1740
1741         // Set auth_username
1742         val.rs = reg->auth_username;
1743         if(pv_set_spec_value(msg, &auth_username_spec, 0, &val)!=0) {
1744                 LM_ERR("error while setting auth_username\n");
1745                 goto error;
1746         }
1747
1748         // Set auth_password
1749         val.rs = reg->auth_password;
1750         if(pv_set_spec_value(msg, &auth_password_spec, 0, &val)!=0) {
1751                 LM_ERR("error while setting auth_password\n");
1752                 goto error;
1753         }
1754
1755         lock_release(reg->lock);
1756         return 1;
1757
1758 error:
1759         lock_release(reg->lock);
1760         return -1;
1761 }
1762
1763 /**
1764  *
1765  */
1766 static int uac_reg_update_flag(str *attr, str *val, int mode, int fval)
1767 {
1768         reg_uac_t *reg = NULL;
1769         int ret;
1770
1771         if(_reg_htable==NULL) {
1772                 LM_ERR("uac remote registrations not enabled\n");
1773                 return -1;
1774         }
1775
1776         if(attr->len<=0 || attr->s==NULL || val->len<=0 || val->s==NULL) {
1777                 LM_ERR("bad parameter values\n");
1778                 return -1;
1779         }
1780
1781         ret = reg_ht_get_byfilter(&reg, attr, val);
1782         if (ret == 0) {
1783                 LM_DBG("record not found for %.*s = %.*s\n", attr->len, attr->s,
1784                                 val->len, val->s);
1785                 return -2;
1786         } else if (ret < 0) {
1787                 LM_DBG("unsupported filter attribute %.*s = %.*s\n", attr->len, attr->s,
1788                                 val->len, val->s);
1789                 return -3;
1790         }
1791
1792         if(mode==1) {
1793                 reg->flags |= fval;
1794         } else {
1795                 reg->flags &= ~fval;
1796         }
1797         reg->timer_expires = time(NULL) + 1;
1798
1799         lock_release(reg->lock);
1800         return 1;
1801 }
1802
1803 /**
1804  *
1805  */
1806 int uac_reg_enable(sip_msg_t *msg, str *attr, str *val)
1807 {
1808         counter_add(regdisabled, -1);
1809         return uac_reg_update_flag(attr, val, 0, UAC_REG_DISABLED);
1810 }
1811
1812 /**
1813  *
1814  */
1815 int uac_reg_disable(sip_msg_t *msg, str *attr, str *val)
1816 {
1817         counter_inc(regdisabled);
1818         return uac_reg_update_flag(attr, val, 1, UAC_REG_DISABLED);
1819 }
1820
1821 /**
1822  *
1823  */
1824 static int rpc_uac_reg_add_node_helper(rpc_t* rpc, void* ctx, reg_uac_t *reg, time_t tn)
1825 {
1826         void* th;
1827         str none = {"none", 4};
1828
1829         /* add entry node */
1830         if (rpc->add(ctx, "{", &th) < 0)
1831         {
1832                 rpc->fault(ctx, 500, "Internal error creating rpc");
1833                 return -1;
1834         }
1835         if (rpc->struct_add(th, "SSSSSSSSSSddddddS",
1836                                 "l_uuid",        &reg->l_uuid,
1837                                 "l_username",    &reg->l_username,
1838                                 "l_domain",      &reg->l_domain,
1839                                 "r_username",    &reg->r_username,
1840                                 "r_domain",      &reg->r_domain,
1841                                 "realm",         &reg->realm,
1842                                 "auth_username", &reg->auth_username,
1843                                 "auth_password", (reg->auth_password.len)?
1844                                                                                 &reg->auth_password:&none,
1845                                 "auth_ha1",      (reg->auth_ha1.len)?
1846                                                                                 &reg->auth_ha1:&none,
1847                                 "auth_proxy",    (reg->auth_proxy.len)?
1848                                                                                 &reg->auth_proxy:&none,
1849                                 "expires",       (int)reg->expires,
1850                                 "flags",         (int)reg->flags,
1851                                 "diff_expires",  (int)(reg->timer_expires - tn),
1852                                 "timer_expires", (int)reg->timer_expires,
1853                                 "reg_init",      (int)reg->reg_init,
1854                                 "reg_delay",     (int)reg->reg_delay,
1855                                 "socket",        &reg->socket
1856                                 )<0) {
1857                 rpc->fault(ctx, 500, "Internal error adding item");
1858                 return -1;
1859         }
1860         return 0;
1861 }
1862
1863 static const char* rpc_uac_reg_dump_doc[2] = {
1864         "Dump the contents of user registrations table.",
1865         0
1866 };
1867
1868 static void rpc_uac_reg_dump(rpc_t* rpc, void* ctx)
1869 {
1870         int i;
1871         reg_item_t *reg = NULL;
1872         time_t tn;
1873
1874         if(_reg_htable==NULL)
1875         {
1876                 rpc->fault(ctx, 500, "Not enabled");
1877                 return;
1878         }
1879
1880         tn = time(NULL);
1881
1882         for(i=0; i<_reg_htable->htsize; i++)
1883         {
1884                 lock_get(&_reg_htable->entries[i].lock);
1885                 /* walk through entries */
1886                 reg = _reg_htable->entries[i].byuuid;
1887                 while(reg)
1888                 {
1889                         if (rpc_uac_reg_add_node_helper(rpc, ctx, reg->r, tn)<0)
1890                         {
1891                                 lock_release(&_reg_htable->entries[i].lock);
1892                                 return;
1893                         }
1894                         reg = reg->next;
1895                 }
1896                 lock_release(&_reg_htable->entries[i].lock);
1897         }
1898 }
1899
1900 static const char* rpc_uac_reg_info_doc[2] = {
1901         "Return the details of registration for a particular record.",
1902         0
1903 };
1904
1905 static void rpc_uac_reg_info(rpc_t* rpc, void* ctx)
1906 {
1907         reg_uac_t *reg = NULL;
1908         str attr = {0};
1909         str val = {0};
1910         int ret;
1911
1912         if(_reg_htable==NULL)
1913         {
1914                 rpc->fault(ctx, 500, "Not enabled");
1915                 return;
1916         }
1917
1918         if(rpc->scan(ctx, "S.S", &attr, &val)<2)
1919         {
1920                 rpc->fault(ctx, 400, "Invalid Parameters");
1921                 return;
1922         }
1923         if(attr.len<=0 || attr.s==NULL || val.len<=0 || val.s==NULL)
1924         {
1925                 LM_ERR("bad parameter values\n");
1926                 rpc->fault(ctx, 400, "Invalid Parameter Values");
1927                 return;
1928         }
1929
1930         ret = reg_ht_get_byfilter(&reg, &attr, &val);
1931         if (ret == 0) {
1932                 rpc->fault(ctx, 404, "Record not found");
1933                 return;
1934         } else if (ret < 0) {
1935                 rpc->fault(ctx, 400, "Unsupported filter attribute");
1936                 return;
1937         }
1938
1939         rpc_uac_reg_add_node_helper(rpc, ctx, reg, time(NULL));
1940         lock_release(reg->lock);
1941         return;
1942 }
1943
1944
1945 static void rpc_uac_reg_update_flag(rpc_t* rpc, void* ctx, int mode, int fval)
1946 {
1947         reg_uac_t *reg = NULL;
1948         str attr = {0};
1949         str val = {0};
1950         int ret;
1951
1952         if(_reg_htable==NULL)
1953         {
1954                 rpc->fault(ctx, 500, "Not enabled");
1955                 return;
1956         }
1957
1958         if(rpc->scan(ctx, "S.S", &attr, &val)<2)
1959         {
1960                 rpc->fault(ctx, 400, "Invalid Parameters");
1961                 return;
1962         }
1963         if(attr.len<=0 || attr.s==NULL || val.len<=0 || val.s==NULL)
1964         {
1965                 LM_ERR("bad parameter values\n");
1966                 rpc->fault(ctx, 400, "Invalid Parameter Values");
1967                 return;
1968         }
1969
1970         ret = reg_ht_get_byfilter(&reg, &attr, &val);
1971         if (ret == 0) {
1972                 rpc->fault(ctx, 404, "Record not found");
1973                 return;
1974         } else if (ret < 0) {
1975                 rpc->fault(ctx, 400, "Unsupported filter attribute");
1976                 return;
1977         }
1978
1979         if(mode==1) {
1980                 reg->flags |= fval;
1981         } else {
1982                 reg->flags &= ~fval;
1983         }
1984         reg->timer_expires = time(NULL) + 1;
1985
1986         lock_release(reg->lock);
1987         return;
1988 }
1989
1990 static const char* rpc_uac_reg_enable_doc[2] = {
1991         "Enable registration for a particular record.",
1992         0
1993 };
1994
1995 static void rpc_uac_reg_enable(rpc_t* rpc, void* ctx)
1996 {
1997         rpc_uac_reg_update_flag(rpc, ctx, 0, UAC_REG_DISABLED);
1998         counter_add(regdisabled, -1);
1999 }
2000
2001 static const char* rpc_uac_reg_disable_doc[2] = {
2002         "Disable registration for a particular record.",
2003         0
2004 };
2005
2006 static void rpc_uac_reg_disable(rpc_t* rpc, void* ctx)
2007 {
2008         rpc_uac_reg_update_flag(rpc, ctx, 1, UAC_REG_DISABLED);
2009         counter_inc(regdisabled);
2010 }
2011
2012 static const char* rpc_uac_reg_reload_doc[2] = {
2013         "Reload records from database.",
2014         0
2015 };
2016
2017 static void rpc_uac_reg_reload(rpc_t* rpc, void* ctx)
2018 {
2019         int ret;
2020         if(uac_reg_ht_shift()<0) {
2021                 rpc->fault(ctx, 500, "Failed to shift records - check log messages");
2022                 return;
2023         }
2024         lock_get(_reg_htable_gc_lock);
2025         ret =  uac_reg_load_db();
2026         lock_release(_reg_htable_gc_lock);
2027         if(ret<0) {
2028                 rpc->fault(ctx, 500, "Failed to reload records - check log messages");
2029                 return;
2030         }
2031 }
2032
2033 static const char* rpc_uac_reg_refresh_doc[2] = {
2034         "Refresh a record from database.",
2035         0
2036 };
2037
2038 static void rpc_uac_reg_refresh(rpc_t* rpc, void* ctx)
2039 {
2040         int ret;
2041         str l_uuid;
2042
2043         if(rpc->scan(ctx, "S", &l_uuid)<1)
2044         {
2045                 rpc->fault(ctx, 400, "Invalid Parameters");
2046                 return;
2047         }
2048
2049         ret =  uac_reg_db_refresh(&l_uuid);
2050         if(ret==0) {
2051                 rpc->fault(ctx, 404, "Record not found");
2052                 return;
2053         } else if(ret<0) {
2054                 rpc->fault(ctx, 500, "Failed to refresh record - check log messages");
2055                 return;
2056         }
2057 }
2058
2059 static const char* rpc_uac_reg_remove_doc[2] = {
2060         "Remove a record from memory.",
2061         0
2062 };
2063
2064 static void rpc_uac_reg_remove(rpc_t* rpc, void* ctx)
2065 {
2066         int ret;
2067         str l_uuid;
2068         reg_uac_t *reg;
2069
2070         if(rpc->scan(ctx, "S", &l_uuid)<1)
2071         {
2072                 rpc->fault(ctx, 400, "Invalid Parameters");
2073                 return;
2074         }
2075         reg = reg_ht_get_byuuid(&l_uuid);
2076         if (!reg) {
2077                 rpc->fault(ctx, 404, "Record not found");
2078                 return;
2079         }
2080
2081         ret = reg_ht_rm(reg);
2082         if(ret<0) {
2083                 rpc->fault(ctx, 500, "Failed to remove record - check log messages");
2084                 return;
2085         }
2086 }
2087
2088 static const char* rpc_uac_reg_add_doc[2] = {
2089         "Add a record to memory.",
2090         0
2091 };
2092
2093 static void rpc_uac_reg_add(rpc_t* rpc, void* ctx)
2094 {
2095         int ret;
2096         reg_uac_t reg;
2097         reg_uac_t *cur_reg;
2098
2099         if(rpc->scan(ctx, "SSSSSSSSSSdddS",
2100                                 &reg.l_uuid,
2101                                 &reg.l_username,
2102                                 &reg.l_domain,
2103                                 &reg.r_username,
2104                                 &reg.r_domain,
2105                                 &reg.realm,
2106                                 &reg.auth_username,
2107                                 &reg.auth_password,
2108                                 &reg.auth_ha1,
2109                                 &reg.auth_proxy,
2110                                 &reg.expires,
2111                                 &reg.flags,
2112                                 &reg.reg_delay,
2113                                 &reg.socket
2114                         )<1)
2115         {
2116                 rpc->fault(ctx, 400, "Invalid Parameters");
2117                 return;
2118         }
2119
2120         if(reg.auth_password.len==1 && reg.auth_password.s[0] == '.') {
2121                 reg.auth_password.s = NULL;
2122                 reg.auth_password.len = 0;
2123         }
2124
2125         if(reg.auth_ha1.len==1 && reg.auth_ha1.s[0] == '.') {
2126                 reg.auth_ha1.s = NULL;
2127                 reg.auth_ha1.len = 0;
2128         }
2129
2130         if(uac_reg_check_password(&reg) < 0) {
2131                 rpc->fault(ctx, 500, "Failed to add record - invalid password or ha1");
2132                 return;
2133         }
2134
2135         cur_reg = reg_ht_get_byuuid(&reg.l_uuid);
2136         if (cur_reg) {
2137                 lock_release(cur_reg->lock);
2138                 rpc->fault(ctx, 409, "uuid already exists");
2139                 return;
2140         }
2141
2142         ret = reg_ht_add(&reg);
2143         if(ret<0) {
2144                 rpc->fault(ctx, 500, "Failed to add record - check log messages");
2145                 return;
2146         }
2147 }
2148
2149
2150 static const char* rpc_uac_reg_active_doc[2] = {
2151         "Set remote registration active or inactive for all records.",
2152         0
2153 };
2154
2155 static void rpc_uac_reg_active(rpc_t* rpc, void* ctx)
2156 {
2157         int omode;
2158         int nmode;
2159         void* th;
2160
2161         if(reg_active==NULL) {
2162                 rpc->fault(ctx, 500, "Not initialized");
2163                 return;
2164         }
2165         if(rpc->scan(ctx, "d", &nmode)<1) {
2166                 LM_ERR("missing parameter");
2167                 rpc->fault(ctx, 500, "Missing parameter");
2168                 return;
2169         }
2170         omode = *reg_active;
2171         *reg_active = (nmode)?1:0;
2172
2173         /* add entry node */
2174         if (rpc->add(ctx, "{", &th) < 0) {
2175                 rpc->fault(ctx, 500, "Internal error creating rpc struct");
2176                 return;
2177         }
2178         if(rpc->struct_add(th, "dd", "omode", omode, "nmode", nmode)<0) {
2179                 rpc->fault(ctx, 500, "Internal error creating response");
2180                 return;
2181         }
2182 }
2183
2184 rpc_export_t uac_reg_rpc[] = {
2185         {"uac.reg_dump", rpc_uac_reg_dump, rpc_uac_reg_dump_doc, RET_ARRAY},
2186         {"uac.reg_info", rpc_uac_reg_info, rpc_uac_reg_info_doc, 0},
2187         {"uac.reg_enable",  rpc_uac_reg_enable,  rpc_uac_reg_enable_doc,  0},
2188         {"uac.reg_disable", rpc_uac_reg_disable, rpc_uac_reg_disable_doc, 0},
2189         {"uac.reg_reload",  rpc_uac_reg_reload,  rpc_uac_reg_reload_doc,  0},
2190         {"uac.reg_refresh", rpc_uac_reg_refresh, rpc_uac_reg_refresh_doc, 0},
2191         {"uac.reg_remove", rpc_uac_reg_remove, rpc_uac_reg_remove_doc, 0},
2192         {"uac.reg_add", rpc_uac_reg_add, rpc_uac_reg_add_doc, 0},
2193         {"uac.reg_active", rpc_uac_reg_active, rpc_uac_reg_active_doc, 0},
2194         {0, 0, 0, 0}
2195 };
2196
2197 int uac_reg_init_rpc(void)
2198 {
2199         if (rpc_register_array(uac_reg_rpc)!=0)
2200         {
2201                 LM_ERR("failed to register RPC commands\n");
2202                 return -1;
2203         }
2204         return 0;
2205 }