SIP Witch 1.9.15
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
server.cpp
Go to the documentation of this file.
1 // Copyright (C) 2006-2014 David Sugar, Tycho Softworks.
2 // Copyright (C) 2015 Cherokees of Idaho.
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 #include "server.h"
18 #include <signal.h>
19 #include <ctype.h>
20 
21 #ifdef HAVE_PWD_H
22 #include <pwd.h>
23 #include <grp.h>
24 #endif
25 
26 #ifdef HAVE_NET_IF_H
27 #include <net/if.h>
28 #include <arpa/inet.h>
29 #ifdef HAVE_IOCTL_H
30 #include <ioctl.h>
31 #else
32 #include <sys/ioctl.h>
33 #endif
34 #endif
35 
36 #ifdef HAVE_SYS_SOCKIO_H
37 #include <sys/sockio.h>
38 #endif
39 
40 namespace sipwitch {
41 
42 static mempager mempool(PAGING_SIZE);
43 static bool running = true;
44 
45 static bool activating(int argc, char **args, voip::context_t context)
46 {
47  assert(args != NULL);
48 
49  registry::mapped *reg;
50  bool rtn = true;
51 
52  Socket::address *addr;
53  if(argc < 2 || argc > 3)
54  return false;
55  if(argc == 3)
56  addr = stack::getAddress(args[2]);
57  else
58  addr = server::getContact(args[1]);
59  if(!addr)
60  return false;
61  if(NULL == (reg = registry::allocate(args[1]))) {
62  delete addr;
63  return false;
64  }
65  time(&reg->created);
66  if(!reg->setTargets(*addr, context))
67  rtn = false;
68  server::activate(reg);
69  registry::detach(reg);
70  delete addr;
71  return rtn;
72 }
73 
74 unsigned server::uid = 1000;
75 const char *server::sipusers = "sipusers";
76 const char *server::sipadmin = "wheel";
77 shell::logmode_t server::logmode = shell::SYSTEM_LOG;
78 int server::exit_code = 0;
79 
80 server::server(const char *id) :
82 {
83  assert(id != NULL && *id != 0);
84 
85  memset(keys, 0, sizeof(keys));
86  acl = NULL;
87 }
88 
89 const char *server::referRemote(MappedRegistry *rr, const char *target, char *buffer, size_t size)
90 {
91  assert(target != NULL && *target != 0);
92  assert(buffer != NULL);
93  assert(size > 0);
94 
95  const char *refer = NULL;
96  linked_pointer<modules::sipwitch> cb = getModules();
97 
98  if(!rr)
99  return NULL;
100 
101  while(!refer && is(cb)) {
102  refer = cb->referRemote(rr, target, buffer, size);
103  cb.next();
104  }
105  return refer;
106 }
107 
108 const char *server::referLocal(MappedRegistry *rr, const char *target, char *buffer, size_t size)
109 {
110  assert(target != NULL && *target != 0);
111  assert(buffer != NULL);
112  assert(size > 0);
113 
114  const char *refer = NULL;
115  linked_pointer<modules::sipwitch> cb = getModules();
116 
117  if(!rr)
118  return NULL;
119 
120  while(!refer && is(cb)) {
121  refer = cb->referLocal(rr, target, buffer, size);
122  cb.next();
123  }
124  return refer;
125 }
126 
127 bool server::authenticate(voip::reg_t id, const char *realm)
128 {
129  linked_pointer<modules::sipwitch> cb = getModules();
130 
131  while(is(cb)) {
132  if(cb->authenticate(id, realm))
133  return true;
134  cb.next();
135  }
136  return false;
137 }
138 
140 {
141  linked_pointer<modules::sipwitch> cb = getModules();
142 
143  while(is(cb)) {
144  cb->registration(id, mode);
145  cb.next();
146  }
147 }
148 
150 {
151  linked_pointer<modules::sipwitch> cb = getModules();
152  logging(rr, "activating");
153 
154  events::activate(rr);
155 
156  while(is(cb)) {
157  cb->activating(rr);
158  cb.next();
159  }
160 }
161 
163 {
164  linked_pointer<modules::sipwitch> cb = getModules();
165 
166  logging(rr, "releasing");
167 
168  while(is(cb)) {
169  cb->expiring(rr);
170  cb.next();
171  }
172  events::release(rr);
173 }
174 
175 void server::logging(MappedRegistry *rr, const char *reason)
176 {
177  DateTimeString dt;
178  printlog("%s %s %s\n", reason, rr->userid, (const char *)dt);
179 }
180 
181 bool server::announce(MappedRegistry *rr, const char *msgtype, const char *event, const char *expires, const char *body)
182 {
183  linked_pointer<modules::sipwitch> cb = getModules();
184  bool rtn = false;
185 
186  while(!rtn && is(cb)) {
187  rtn = cb->announce(rr, msgtype, event, expires, body);
188  cb.next();
189  }
190  return rtn;
191 }
192 
194 {
195  assert(id != NULL && *id != 0);
196 
197  unsigned path = NamedObject::keyindex(id, CONFIG_KEY_SIZE);
198  linked_pointer<keymap> map = keys[path];
199 
200  while(map) {
201  if(!stricmp(map->id, id))
202  return map->node;
203  map.next();
204  }
205  return NULL;
206 }
207 
208 bool server::create(const char *id, keynode *node)
209 {
210  assert(id != NULL && *id != 0);
211  assert(node != NULL);
212 
213  keymap *map = (keymap *)alloc(sizeof(keymap));
214  unsigned path = NamedObject::keyindex(id, CONFIG_KEY_SIZE);
215 
216  if(find(id))
217  return true;
218 
219  map->id = id;
220  map->node = node;
221  map->enlist(&keys[path]);
222  return false;
223 }
224 
225 void server::confirm(void)
226 {
227  dir_t dir;
228  keynode *access = getPath("access");
229  char *id = NULL, *secret = NULL;
230  const char *ext;
231  linked_pointer<service::keynode> node;
232  service::keynode *leaf;
233  FILE *fp;
234  char buf[128];
235  char filename[65];
236  void *mp;
237  profile *pp, *ppd;
238  const char *state = root.getPointer();
239  const char *realm = registry::getRealm();
240  unsigned prefix = registry::getPrefix();
241  unsigned range = registry::getRange();
242  unsigned number;
243  const char *dirpath = ".";
244  const char *fn;
245  digest_t digest(registry::getDigest());
246 
247  // add any missing keys
248  getPath("devices");
249 
250  // construct default profiles
251 
252  provision = getPath("provision");
253  extmap = NULL;
254  if(range) {
255  extmap = new keynode*[range];
256  memset(extmap, 0, sizeof(keynode *) * range);
257  }
258  profiles = NULL;
259  mp = alloc(sizeof(profile));
260  ppd = new(mp) profile(&profiles);
261  String::set(ppd->value.id, sizeof(ppd->value.id), "*");
262  ppd->value.level = 1;
263  ppd->value.features = USER_PROFILE_DEFAULT;
264 
265  mp = alloc(sizeof(profile));
266  pp = new(mp) profile(&profiles);
267  memcpy(&pp->value, &ppd->value, sizeof(profile_t));
268  String::set(pp->value.id, sizeof(pp->value.id), "restricted");
269  pp->value.level = 0;
270  pp->value.features = USER_PROFILE_RESTRICTED;
271 
272  mp = alloc(sizeof(profile));
273  pp = new(mp) profile(&profiles);
274  memcpy(&pp->value, &ppd->value, sizeof(profile_t));
275  String::set(pp->value.id, sizeof(pp->value.id), "local");
276  pp->value.level = 1;
277  pp->value.features = USER_PROFILE_LOCAL;
278 
279  mp = alloc(sizeof(profile));
280  pp = new(mp) profile(&profiles);
281  memcpy(&pp->value, &ppd->value, sizeof(profile_t));
282  String::set(pp->value.id, sizeof(pp->value.id), "device");
283  pp->value.level = 0;
284  pp->value.features = USER_PROFILE_DEVICE;
285 
286  mp = alloc(sizeof(profile));
287  pp = new(mp) profile(&profiles);
288  memcpy(&pp->value, &ppd->value, sizeof(profile_t));
289  String::set(pp->value.id, sizeof(pp->value.id), "service");
290  pp->value.level = 0;
291  pp->value.features = USER_PROFILE_SERVICE;
292 
293  mp = alloc(sizeof(profile));
294  pp = new(mp) profile(&profiles);
295  memcpy(&pp->value, &ppd->value, sizeof(profile_t));
296  String::set(pp->value.id, sizeof(pp->value.id), "admin");
297  pp->value.level = 9;
298  pp->value.features = USER_PROFILE_ADMIN;
299 
300 #ifdef _MSWINDOWS_
301  dirpath = _STR(control::path("prefix") + "\\users");
302 #else
303  dirpath = control::env("users"); // /etc/sipwitch.d
304  if(!dirpath)
305  dirpath = control::env("prefix");
306 #endif
307  dir.open(dirpath);
308  shell::log(DEBUG1, "scanning config from %s", dirpath);
309  while(is(dir) && dir.read(filename, sizeof(filename)) > 0) {
310  ext = strrchr(filename, '.');
311  if(!ext || !String::equal(ext, ".xml"))
312  continue;
313  if(state) {
314  snprintf(buf, sizeof(buf), "%s/%s/%s", dirpath, state, filename);
315  fp = fopen(buf, "r");
316  }
317  else
318  fp = NULL;
319  if(!fp) {
320  snprintf(buf, sizeof(buf), "%s/%s", dirpath, filename);
321  fp = fopen(buf, "r");
322  }
323  fn = strrchr(buf, '/');
324  if(fn)
325  ++fn;
326  else
327  fn = buf;
328  if(fp) {
329  if(!load(fp, provision))
330  shell::log(shell::ERR, "cannot load %s", fn);
331  else
332  shell::log(DEBUG1, "loaded %s", fn);
333  }
334  }
335 
336  dir.close();
337 
338  mp = alloc(sizeof(stack::subnet));
339  new(mp) stack::subnet(&acl, "127.0.0.0/8", "loopback");
340 
341  mp = alloc(sizeof(stack::subnet));
342  new(mp) stack::subnet(&acl, "::1", "loopback");
343 
344 #if defined(HAVE_NET_IF_H) || defined(HAVE_PWD_H)
345  int ifcount = 0;
346 #endif
347 
348 #ifdef HAVE_NET_IF_H
349  char ifbuf[8192];
350  struct ifconf ifc;
351  struct ifreq *ifr;
352  int index = 0;
353 
354  ifc.ifc_len = sizeof(ifbuf);
355  ifc.ifc_buf = ifbuf;
356  int ifd = ::socket(AF_INET, SOCK_DGRAM, 0);
357  if(ifd < 0)
358  shell::log(shell::FAIL, "cannot access network");
359  else if(ioctl(ifd, SIOCGIFCONF, &ifc) == -1) {
360  ::close(ifd);
361  ifd = -1;
362  shell::log(shell::ERR, "cannot list interfaces");
363  }
364  if(ifd > 0)
365  ifcount = ifc.ifc_len / sizeof(ifreq);
366 
367  while(index < ifcount) {
368  ifr = &ifc.ifc_req[index++];
369  if(ifr->ifr_addr.sa_family != AF_INET)
370  continue;
371  struct sockaddr_in *saddr = (struct sockaddr_in *)&(ifr->ifr_addr);
372  snprintf(buf, sizeof(buf), "%s/", inet_ntoa(saddr->sin_addr));
373  if(ioctl(ifd, SIOCGIFNETMASK, ifr) == 0) {
374  saddr = (struct sockaddr_in *)&(ifr->ifr_addr);
375  String::add(buf, sizeof(buf), inet_ntoa(saddr->sin_addr));
376  mp = alloc(sizeof(stack::subnet));
377  new(mp) stack::subnet(&acl, buf, ifr->ifr_name);
378  }
379  }
380  ::close(ifd);
381 #endif
382 
383  node = access->getFirst();
384  while(node) {
385  id = node->getId();
386  leaf = NULL;
387  if(id && node->getPointer()) {
388  mp = alloc(sizeof(stack::subnet));
389  new(mp) stack::subnet(&acl, node->getPointer(), id);
390  }
391  node.next();
392  }
393 
394  node = provision->getFirst();
395  while(is(node)) {
396  number = 0;
397  leaf = node->leaf("id");
398  id = NULL;
399  if(leaf)
400  id = leaf->getPointer();
401 
402  if(leaf && !registry::isUserid(id))
403  id = NULL;
404 
405  if(leaf && id && !strcmp(node->getId(), "profile")) {
406  mp = alloc(sizeof(profile));
407  pp = new(mp) profile(&profiles);
408  memcpy(&pp->value, &ppd->value, sizeof(profile_t));
409  String::set(pp->value.id, sizeof(pp->value.id), id);
410  leaf = node->leaf("trs");
411  if(leaf && leaf->getPointer())
412  pp->value.level = atoi(leaf->getPointer());
413  shell::debug(2, "adding profile %s", id);
414  if(!stricmp(id, "*"))
415  ppd = pp;
416  }
417  else if(leaf && id) {
418  id = leaf->getPointer();
419  if(create(id, *node)) {
420  shell::log(shell::WARN, "duplicate identity %s", id);
421  node->setPointer((char *)"duplicate");
422  }
423  else {
424  shell::debug(2, "adding %s %s", node->getId(), id);
425  if(!stricmp(node->getId(), "reject"))
426  registry::remove(id);
427  }
428  leaf = node->leaf("secret");
429  if(leaf)
430  secret = leaf->getPointer();
431  if(leaf && secret && *secret && !node->leaf("digest")) {
432  if(digest.puts((string_t)id + ":" + (string_t)realm + ":" + (string_t)secret)) {
433  mp = alloc(sizeof(keynode));
434  leaf = new(mp) keynode(node, (char *)"digest");
435  leaf->setPointer(dup(*digest));
436  }
437  digest.reset();
438  }
439  leaf = node->leaf("extension");
440  if(leaf && range && leaf->getPointer())
441  number = atoi(leaf->getPointer());
442  if(number >= prefix && number < prefix + range)
443  extmap[number - prefix] = *node;
444  }
445  node.next();
446  }
447 
448  if(!sipadmin && !sipusers)
449  return;
450 
451 #ifdef HAVE_PWD_H
452  ifcount = 0;
453  char *member;
454  const char *tempname;
455  keynode *base = getPath("accounts");
456  keyclone *clone, *entry;
457  linked_pointer<keynode> temp;
458  char *cp;
459 
460  struct passwd *pwd;
461  struct group *grp = NULL;
462 
463  if(sipusers)
464  grp = getgrnam(sipusers);
465 
466  // if no separated privilege, then use sipadmin
467  if(!grp && sipadmin)
468  grp = getgrnam(sipadmin);
469 
470  if(grp && !grp->gr_mem)
471  goto final;
472 
473  if(uid || grp)
474  shell::log(DEBUG1, "scanning users and groups");
475 
476  // if no groups at all, try to add base user if enabled....
477  // this allows fully automated service for primary desktop user...
478  if(!grp && uid) {
479  pwd = getpwuid(uid);
480  if(!pwd)
481  return;
482  leaf = addNode(base, "user", NULL);
483  addNode(leaf, "id", pwd->pw_name);
484  }
485  else while(NULL != (member = grp->gr_mem[ifcount++])) {
486  leaf = addNode(base, "user", NULL);
487  addNode(leaf, "id", member);
488  }
489 
490  if(sipadmin)
491  grp = getgrnam(sipadmin);
492 
493  node = base->getFirst();
494  while(is(node)) {
495  id = NULL;
496  leaf = node->leaf("id");
497  if(leaf && leaf->getPointer())
498  id = leaf->getPointer();
499 
500  pwd = NULL;
501  if(id)
502  pwd = getpwnam(id);
503 
504  if(!pwd) {
505  node->setPointer((char *)"invalid");
506  node.next();
507  continue;
508  }
509 
510  if(create(id, *node)) {
511  node->setPointer((char *)"duplicate");
512  node.next();
513  continue;
514  }
515 
516  id = pwd->pw_gecos;
517 
518  cp = strchr(id, ',');
519  if(cp)
520  *(cp++) = 0;
521  addNode(*node, "display", id);
522 
523  // add extension node only if prefix is used...
524  if(prefix && range) {
525  if(cp)
526  number = atoi(cp);
527  else
528  number = 0;
529  if(!number && pwd->pw_uid >= uid && uid > 0)
530  number = pwd->pw_uid - uid + prefix;
531 
532  if(number >= prefix && number < prefix + range && extmap[number - prefix] == NULL)
533  extmap[number - prefix] = *node;
534 
535  if(number) {
536  snprintf(buf, 16, "%d", number);
537  addNode(*node, "extension", buf);
538  }
539  }
540 
541  entry = (keyclone *)(*node);
542  ifcount = 0;
543  tempname = "templates.user";
544  while(grp && grp->gr_mem && NULL != (member = grp->gr_mem[ifcount++])) {
545  if(String::equal(member, pwd->pw_name)) {
546  tempname = "templates.admin";
547  entry->reset("admin");
548  break;
549  }
550  }
551 
552  shell::debug(2, "adding %s %s", node->getId(), pwd->pw_name);
553 
554  clone = (keyclone *)getPath(tempname);
555  if(!clone) {
556  node.next();
557  continue;
558  }
559 
560  temp = clone->getFirst();
561  while(is(temp)) {
562  clone = (keyclone *)alloc(sizeof(keynode));
563  copy_unsafe<keyclone>(clone, (keyclone *)*temp);
564  clone->splice(entry);
565  temp.next();
566  }
567 
568  node.next();
569  }
570 
571 final:
572  endpwent();
573  endgrent();
574 #endif
575 }
576 
578 {
579  if(node)
580  locking.release();
581 }
582 
584 {
585  if(user.heap)
586  delete user.heap;
587  else
588  service::release(user.keys);
589 
590  user.keys = NULL;
591  user.heap = NULL;
592 }
593 
595 {
596  if(access)
597  locking.release();
598 }
599 
600 bool server::isLocal(const struct sockaddr *addr)
601 {
602  bool rtn = false;
603 
604  assert(addr != NULL);
605  assert(cfg != NULL);
606  cidr *access = getPolicy(addr);
607  if(access) {
608  rtn = true;
609  locking.release();
610  }
611  return rtn;
612 }
613 
615 {
616  locking.access();
617 
618  linked_pointer<stack::subnet> np = (((server *)(cfg))->acl);
619 
620  while(is(np)) {
621  if(String::equal(np->getId(), id))
622  return *np;
623  np.next();
624  }
625  locking.release();
626  return NULL;
627 }
628 
629 void server::listPolicy(FILE *fp)
630 {
631  linked_pointer<stack::subnet> pp;
632  char buf[128], baddr[128], bmask[128];
633  struct sockaddr_storage addr, mask;
634  struct sockaddr_in *ipv4;
635 #ifdef AF_INET6
636  struct sockaddr_in6 *ipv6;
637 #endif
638  struct hostaddr_internet ha;
639 
640  locking.access();
641  pp = ((server *)(cfg))->acl;
642  while(is(pp)) {
643  const char *id = pp->getId();
644  int fam = pp->getFamily();
645  switch(fam) {
646 #ifdef AF_INET6
647  case AF_INET6:
648  ipv6 = (struct sockaddr_in6 *)&addr;
649  ha = pp->getNetwork();
650  memcpy(&ipv6->sin6_addr, &ha, sizeof(ipv6->sin6_addr));
651  ipv6->sin6_family = AF_INET6;
652  Socket::query((struct sockaddr *)ipv6, baddr, sizeof(baddr));
653  ipv6 = (struct sockaddr_in6 *)&mask;
654  ha = pp->getNetmask();
655  memcpy(&ipv6->sin6_addr, &ha, sizeof(ipv6->sin6_addr));
656  ipv6->sin6_family = AF_INET6;
657  Socket::query((struct sockaddr *)ipv6, bmask, sizeof(bmask));
658  break;
659 #endif
660  case AF_INET:
661  ipv4 = (struct sockaddr_in *)&addr;
662  ha = pp->getNetwork();
663  memcpy(&ipv4->sin_addr, &ha, sizeof(ipv4->sin_addr));
664  ipv4->sin_family = AF_INET;
665  Socket::query((struct sockaddr *)ipv4, baddr, sizeof(baddr));
666  ipv4 = (struct sockaddr_in *)&mask;
667  ha = pp->getNetmask();
668  memcpy(&ipv4->sin_addr, &ha, sizeof(ipv4->sin_addr));
669  ipv4->sin_family = AF_INET;
670  Socket::query((struct sockaddr *)ipv4, bmask, sizeof(bmask));
671  break;
672  default:
673  String::set(baddr, sizeof(baddr), "?");
674  String::set(bmask, sizeof(bmask), "?");
675  }
676  Socket::query(pp->getInterface(), buf, sizeof(buf));
677  if(pp->offline())
678  fprintf(fp, "offline %s; interface=%s, %s/%s\n", id, buf, baddr, bmask);
679  else
680  fprintf(fp, "policy %s; interface=%s, %s/%s\n", id, buf, baddr, bmask);
681  pp.next();
682  }
683  locking.release();
684 }
685 
686 stack::subnet *server::getPolicy(const struct sockaddr *addr)
687 {
688  assert(addr != NULL);
689  assert(cfg != NULL);
690 
691  stack::subnet *policy;
692 
693  if(!cfg)
694  return NULL;
695 
696  locking.access();
697  policy = (stack::subnet *)cidr::find(((server *)(cfg))->acl, addr);
698  if(!policy)
699  locking.release();
700  return policy;
701 }
702 
703 profile_t *server::getProfile(const char *pro)
704 {
705  assert(pro != NULL);
706  assert(cfg != NULL);
707 
708  server *cfgp;
709  linked_pointer<profile> pp;
710  profile_t *ppd = NULL;
711 
712  cfgp = static_cast<server*>(cfg);
713  if(!cfgp) {
714  return NULL;
715  }
716  pp = cfgp->profiles;
717  while(pp) {
718  // we depend on default always being last...
719  if(!ppd && !stricmp(pp->value.id, "*"))
720  ppd = &pp->value;
721  if(!stricmp(pp->value.id, pro))
722  break;
723  pp.next();
724  }
725  if(!ppd && !*pp) {
726  return NULL;
727  }
728  if(pp)
729  return &(pp->value);
730  return ppd;
731 }
732 
734 {
735  locking.access();
736  if(!cfg) {
737  locking.release();
738  return NULL;
739  }
740 
741  return (keynode *)cfg;
742 }
743 
744 Socket::address *server::getContact(const char *cuid)
745 {
746  assert(cuid != NULL && *cuid != 0);
747  assert(cfg != NULL);
748 
749  usernode user;
750 
751  getProvision(cuid, user);
752  Socket::address *addr = NULL;
753 
754  if(!user.keys)
755  return NULL;
756 
757  service::keynode *node = user.keys->leaf("contact");
758  if(node)
759  addr = stack::getAddress(node->getPointer());
760  server::release(user);
761  return addr;
762 }
763 
765 {
766  assert(id != NULL && *id != 0);
767  assert(cfg != NULL);
768 
769  linked_pointer<keynode> node;
770  const char *cp;
771 
772  // never re-route in-dialing nodes...
773 
774  if(registry::isExtension(id))
775  return NULL;
776 
777  if(!cfg)
778  return NULL;
779 
780  locking.access();
781  node = cfg->getList("routing");
782  while(is(node)) {
783  cp = getValue(*node, "pattern");
784  if(cp && match(id, cp, false))
785  return *node;
786  // we can use fixed identities instead of patterns...
787  cp = getValue(*node, "identity");
788  if(cp && !stricmp(cp, id))
789  return *node;
790  node.next();
791  }
792  locking.release();
793  return NULL;
794 }
795 
796 bool server::checkId(const char *cuid)
797 {
798  assert(cuid != NULL && *cuid != 0);
799  assert(cfg != NULL);
800  keynode *node = NULL;
801  server *cfgp;
802 
803  locking.access();
804  cfgp = static_cast<server*>(cfg);
805  if(!cfgp) {
806  locking.release();
807  return false;
808  }
809  node = cfgp->find(cuid);
810  locking.release();
811  if(node)
812  return true;
813  return false;
814 }
815 
816 void server::getDialing(const char *cuid, usernode& user)
817 {
818  assert(cuid != NULL && *cuid != 0);
819  assert(cfg != NULL);
820 
821  keynode *leaf = NULL;
822  keynode *node;
823  server *cfgp;
824  unsigned range = registry::getRange();
825  unsigned prefix = registry::getPrefix();
826  unsigned ext = atoi(cuid);
827 
828  server::release(user);
829 
830  locking.access();
831  cfgp = static_cast<server*>(cfg);
832  if(!cfgp) {
833  locking.release();
834  return;
835  }
836  node = cfgp->find(cuid);
837  if(node)
838  leaf = node->leaf("extension");
839  if(node && leaf && service::dialmode == service::EXT_DIALING)
840  node = NULL;
841 
842  if(!node && service::dialmode != service::USER_DIALING && range && ext >= prefix && ext < prefix + range)
843  node = cfgp->extmap[ext - prefix];
844 
845  if(!node)
846  locking.release();
847  user.keys = node;
848 }
849 
850 void server::getProvision(const char *cuid, usernode& user)
851 {
852  assert(cuid != NULL && *cuid != 0);
853  assert(cfg != NULL);
854 
855  keynode *node;
856  server *cfgp;
857  unsigned range = registry::getRange();
858  unsigned prefix = registry::getPrefix();
859  unsigned ext = atoi(cuid);
860 
861  server::release(user);
862 
863  locking.access();
864  cfgp = static_cast<server*>(cfg);
865  if(!cfgp) {
866  locking.release();
867  return;
868  }
869  node = cfgp->find(cuid);
870  if(!node && range && ext >= prefix && ext < prefix + range)
871  node = cfgp->extmap[ext - prefix];
872  if(!node)
873  locking.release();
874  user.keys = node;
875 }
876 
877 bool server::check(void)
878 {
879  shell::log(shell::INFO, "checking config...");
880  locking.modify();
881  locking.commit();
882  shell::log(shell::INFO, "checking components...");
883  if(service::check()) {
884  shell::log(shell::INFO, "checking complete");
885  return true;
886  }
887  shell::log(shell::WARN, "checking failed");
888  return false;
889 }
890 
891 void server::dump(FILE *fp)
892 {
893  assert(fp != NULL);
894  assert(cfg != NULL);
895 
896  fprintf(fp, "Server:\n");
897  fprintf(fp, " allocated pages: %d\n", server::allocate());
898  fprintf(fp, " configure pages: %d\n", cfg->pages());
899  fprintf(fp, " memory paging: %ld\n", (long)PAGING_SIZE);
900  keynode *reg = getPath("registry");
901  if(reg && reg->getFirst()) {
902  fprintf(fp, " registry keys:\n");
903  service::dump(fp, reg->getFirst(), 4);
904  }
905  reg = getPath("sip");
906  if(reg && reg->getFirst()) {
907  fprintf(fp, " sip stack keys:\n");
908  service::dump(fp, reg->getFirst(), 4);
909  }
910 }
911 
912 void server::reload(void)
913 {
914  char buf[256];
915  FILE *state = NULL;
916  const char *cp;
917  keynode *node;
918 
919 #ifdef _MSWINDOWS_
920  GetEnvironmentVariable("APPDATA", buf, 192);
921  unsigned len = strlen(buf);
922  snprintf(buf + len, sizeof(buf) - len, "\\sipwitch\\state.xml");
923  state = fopen(buf, "r");
924 #else
925  snprintf(buf, sizeof(buf), DEFAULT_VARPATH "/run/sipwitch/state.xml");
926  state = fopen(buf, "r");
927 #endif
928 
929  server *cfgp = new server("sipwitch");
930 
931  crit(cfgp != NULL, "reload without config");
932 
933  if(state) {
934  shell::log(DEBUG1, "pre-loading state configuration");
935  if(!cfgp->load(state))
936  shell::log(shell::ERR, "invalid state");
937  }
938 
939  FILE *fp = fopen(control::env("config"), "r");
940  if(fp)
941  if(!cfgp->load(fp)) {
942  shell::log(shell::ERR, "invalid config %s", control::env("config"));
943  delete cfgp;
944  return;
945  }
946 
947  shell::log(shell::NOTIFY, "loaded config from %s", control::env("config"));
948  cp = cfgp->root.getPointer();
949  if(cp)
950  shell::log(shell::INFO, "activating for state \"%s\"", cp);
951 
952  // load cache. These may be set by external crontab scripts or
953  // utilities which dump databases or fetch from remote web sites, and
954  // output xml files for sipwitch to then consume. cache is used to
955  // separate user editable local provisioning in /etc/sipwitch.d from
956  // such global data as part of a complete solution.
957 
958  node = cfgp->getPath("access");
959  if(node)
960  fp = fopen(_STR(control::path("cache") + "/policy.xml"), "r");
961  if(node && fp) {
962  if(!cfgp->load(fp, node))
963  shell::log(shell::ERR, "cannot load policy cache");
964  }
965 
966  node = cfgp->getPath("provision");
967 
968  // can load profiles separate from user provisioning...
969  if(node)
970  fp = fopen(_STR(control::path("cache") + "/profile.xml"), "r");
971  if(node && fp) {
972  if(!cfgp->load(fp, node))
973  shell::log(shell::ERR, "cannot load profile cache");
974  }
975 
976  if(node)
977  fp = fopen(_STR(control::path("cache") + "/provision.xml"), "r");
978  if(node && fp) {
979  if(!cfgp->load(fp, node))
980  shell::log(shell::ERR, "cannot load provisioning cache");
981  }
982 
983  // scan for user records individually also...
984  const char *dirpath = _STR(control::path("cache"));
985  char filename[65];
986  dir_t dir(dirpath);
987  while(node && is(dir) && dir.read(filename, sizeof(filename)) > 0) {
988  const char *ext = strrchr(filename, '.');
989  if(!ext || !String::equal(ext, ".xml"))
990  continue;
991  if(!String::equal(filename, "user-", 5))
992  continue;
993  snprintf(buf, sizeof(buf), "%s/%s", dirpath, filename);
994  fp = fopen(buf, "r");
995  if(!fp)
996  continue;
997  if(!cfgp->load(fp, node))
998  shell::log(shell::ERR, "cannot load user cache %s", filename);
999  }
1000  dir.close();
1001 
1002  node = cfgp->getPath("provider");
1003  if(node)
1004  fp = fopen(_STR(control::path("cache") + "/provider.xml"), "r");
1005  if(node && fp) {
1006  if(!cfgp->load(fp, node))
1007  shell::log(shell::ERR, "cannot load provider cache");
1008  }
1009 
1010  node = cfgp->getPath("routing");
1011  if(node)
1012  fp = fopen(_STR(control::path("cache") + "/routing.xml"), "r");
1013  if(node && fp) {
1014  if(!cfgp->load(fp, node))
1015  shell::log(shell::ERR, "cannot load routing cache");
1016  }
1017 
1018  cfgp->commit();
1019  if(!cfg) {
1020  shell::log(shell::FAIL, "no configuration");
1021  exit(2);
1022  }
1023 }
1024 
1025 unsigned server::allocate(void)
1026 {
1027  return mempool.pages();
1028 }
1029 
1030 void *server::allocate(size_t size, LinkedObject **list, volatile unsigned *count)
1031 {
1032  assert(size > 0);
1033  void *mp;
1034  if(list && *list) {
1035  mp = *list;
1036  *list = (*list)->getNext();
1037  }
1038  else {
1039  if(count)
1040  ++(*count);
1041  mp = mempool.alloc(size);
1042  }
1043  memset(mp, 0, size);
1044  return mp;
1045 }
1046 
1047 #ifdef _MSWINDOWS_
1048 #define LIB_PREFIX "_libs"
1049 #else
1050 #define LIB_PREFIX ".libs"
1051 #endif
1052 
1053 void server::plugins(const char *prefix, const char *list)
1054 {
1055  char buffer[256];
1056  char path[256];
1057  char *tp = NULL;
1058  const char *cp;
1059  fsys module;
1060  dir_t dir;
1061  char *ep;
1062  unsigned el;
1063 
1064  if(!list || !*list || eq(list, "none"))
1065  return;
1066 
1067  if(eq(list, "auto") || eq(list, "all")) {
1068  String::set(path, sizeof(path), prefix);
1069  el = strlen(path);
1070  dir.open(path);
1071  while(is(dir) && dir.read(buffer, sizeof(buffer)) > 0) {
1072  ep = strrchr(buffer, '.');
1073  if(!ep || !eq(ep, MODULE_EXT))
1074  continue;
1075  if(eq(buffer, "lib", 3))
1076  continue;
1077  snprintf(path + el, sizeof(path) - el, "/%s", buffer);
1078  shell::log(shell::INFO, "loading %s%s", buffer, MODULE_EXT);
1079  if(fsys::load(path))
1080  shell::log(shell::ERR, "failed loading %s", path);
1081  }
1082  dir.close();
1083  }
1084  else {
1085  String::set(buffer, sizeof(buffer), list);
1086  while(NULL != (cp = String::token(buffer, &tp, ", ;:\r\n"))) {
1087  snprintf(path, sizeof(path), "%s/%s%s", prefix, cp, MODULE_EXT);
1088  shell::log(shell::INFO, "loading %s" MODULE_EXT, cp);
1089  if(fsys::load(path))
1090  shell::log(shell::ERR, "failed loading %s", path);
1091  }
1092  }
1093 }
1094 
1095 void server::stop(void)
1096 {
1097  running = false;
1098 }
1099 
1100 void server::run(void)
1101 {
1102  int argc;
1103  char buf[256];
1104  char *argv[65];
1105  char *state;
1106  char *cp, *tokens;
1107  FILE *fp;
1108 
1109  DateTimeString logtime;
1110 
1111  // initial load of digest cache
1112  digests::load();
1113 
1114  printlog("server starting %s\n", (const char *)logtime);
1115 
1116  while(running && NULL != (cp = control::receive())) {
1117  shell::debug(9, "received request %s\n", cp);
1118 
1119  logtime.set();
1120 
1121  if(eq(cp, "reload")) {
1122  printlog("server reloading %s\n", (const char *)logtime);
1123  reload();
1124  continue;
1125  }
1126 
1127  if(eq(cp, "check")) {
1128  if(!check())
1129  control::reply("check failed");
1130  continue;
1131  }
1132 
1133  if(eq(cp, "stop") || eq(cp, "down") || eq(cp, "exit"))
1134  break;
1135 
1136  if(eq(cp, "restart")) {
1137  exit_code = SIGABRT;
1138  break;
1139  }
1140 
1141  if(eq(cp, "snapshot")) {
1143  continue;
1144  }
1145 
1146  if(eq(cp, "usercache")) {
1147  cache::userdump();
1148  continue;
1149  }
1150 
1151  if(eq(cp, "dump")) {
1153  continue;
1154  }
1155 
1156  if(eq(cp, "contact")) {
1157  FILE *out = control::output(NULL);
1158  string_t tmp = service::getContact();
1159  fprintf(out, "%s\n", *tmp);
1160  fclose(out);
1161  continue;
1162  }
1163 
1164  if(eq(cp, "siplog")) {
1165  FILE *out = control::output(NULL);
1166  if(!out)
1167  continue;
1168  FILE *log = fopen(control::env("siplogs"), "r");
1169  if(!log) {
1170  fclose(out);
1171  continue;
1172  }
1173 
1174  while(fgets(buf, sizeof(buf), log) != NULL) {
1175  cp = String::strip(buf, " \t\r\n");
1176  fprintf(out, "%s\n", cp);
1177  }
1178  fclose(out);
1179  fclose(log);
1180  continue;
1181  }
1182 
1183  if(eq(cp, "abort")) {
1184  abort();
1185  continue;
1186  }
1187 
1188  argc = 0;
1189  tokens = NULL;
1190  while(argc < 64 && NULL != (cp = const_cast<char *>(String::token(cp, &tokens, " \t", "{}")))) {
1191  argv[argc++] = cp;
1192  }
1193  argv[argc] = NULL;
1194  if(argc < 1)
1195  continue;
1196 
1197  if(eq(argv[0], "ifup")) {
1198  if(argc != 2)
1199  goto invalid;
1200  printlog("server reloading %s\n", (const char *)logtime);
1201  reload();
1202  continue;
1203  }
1204 
1205  if(eq(argv[0], "ifdown")) {
1206  if(argc != 2)
1207  goto invalid;
1208  printlog("server reloading %s\n", (const char *)logtime);
1209  reload();
1210  continue;
1211  }
1212 
1213  if(eq(argv[0], "drop")) {
1214  if(argc != 2)
1215  goto invalid;
1216  continue;
1217  }
1218 
1219  if(eq(argv[0], "trace")) {
1220  if(argc != 2)
1221  goto invalid;
1222  if(!stricmp(argv[1], "on"))
1224  else if(!stricmp(argv[1], "off"))
1226  else if(!stricmp(argv[1], "clear"))
1228  else
1229  goto invalid;
1230  continue;
1231  }
1232 
1233  if(eq(argv[0], "uid")) {
1234  if(argc != 2) {
1235 invalid:
1236  control::reply("invalid argument");
1237  continue;
1238  }
1239  server::uid = atoi(argv[1]);
1240  printlog("uid %d %s\n", server::uid, (const char *)logtime);
1241  reload();
1242  continue;
1243  }
1244 
1245  if(eq(argv[0], "history")) {
1246  if(argc > 2)
1247  goto invalid;
1248  else if(argc == 2)
1249  history::set(atoi(argv[1]));
1250  else
1251  history::out();
1252  continue;
1253  }
1254 
1255  if(eq(argv[0], "verbose")) {
1256  if(argc != 2)
1257  goto invalid;
1258 
1259  shell::log("sipwitch", (shell::loglevel_t)(atoi(argv[1])), logmode); continue;
1260  }
1261 
1262  if(eq(argv[0], "digest")) {
1263  if(argc != 3)
1264  goto invalid;
1265 
1266  if(!digests::set(argv[1], argv[2]))
1267  control::reply("invalid digest");
1268  continue;
1269  }
1270 
1271  if(eq(argv[0], "realm")) {
1272  if(argc != 2)
1273  goto invalid;
1274 
1275  printlog("realm %s %s\n", argv[1], (const char *)logtime);
1276  reload();
1277  continue;
1278  }
1279 
1280  if(eq(argv[0], "period")) {
1281  if(argc != 2)
1282  goto invalid;
1283  if(service::period(atol(argv[1])))
1284  printlog("server period %s\n", (const char *)logtime);
1285  continue;
1286  }
1287 
1288  if(eq(argv[0], "policy") || eq(argv[0], "network")) {
1289  if(argc != 1)
1290  goto invalid;
1291  FILE *out = control::output(NULL);
1292  if(!out)
1293  continue;
1294  struct sockaddr_storage peer;
1295  service::published(&peer);
1296  Socket::query((struct sockaddr *)&peer, buf, sizeof(buf));
1297  if(service::getInterface())
1298  fprintf(out, "binding to %s:%u\n", service::getInterface(), service::getPort());
1299  else
1300  fprintf(out, "binding to *:%u\n", service::getPort());
1301  if(buf[0])
1302  fprintf(out, "peering as %s\n", buf);
1303 
1304  listPolicy(out);
1305  fclose(out);
1306  continue;
1307  }
1308 
1309  if(eq(argv[0], "address")) {
1310  if(argc != 2)
1311  goto invalid;
1312  state = String::unquote(argv[1], "\"\"\'\'()[]{}");
1313  service::publish(state);
1314  shell::log(shell::NOTIFY, "published address is %s", state);
1315  continue;
1316  }
1317 
1318  if(eq(argv[0], "state")) {
1319  if(argc != 2)
1320  goto invalid;
1321  state = String::unquote(argv[1], "\"\"\'\'()[]{}");
1322  if(!control::state(state))
1323  control::reply("invalid state");
1324  fp = fopen(DEFAULT_VARPATH "/run/sipwitch/state.def", "w");
1325  if(fp) {
1326  fputs(state, fp);
1327  fclose(fp);
1328  }
1329  printlog("state %s %s\n", state, (const char *)logtime);
1330  shell::log(shell::NOTIFY, "state changed to %s", state);
1331  events::state(state);
1332  reload();
1333  continue;
1334  }
1335 
1336  if(eq(argv[0], "concurrency")) {
1337  if(argc != 2)
1338  goto invalid;
1339  Thread::concurrency(atoi(argv[1]));
1340  continue;
1341  }
1342 
1343  if(eq(argv[0], "message")) {
1344  if(argc != 3)
1345  goto invalid;
1346  if(messages::system(argv[1], argv[2]) != SIP_OK)
1347  control::reply("cannot message");
1348  continue;
1349  }
1350 
1351  if(eq(argv[0], "activate")) {
1352  // TODO: we will need protocol entry in future
1353  if(!activating(argc, argv, stack::sip.out_context))
1354  control::reply("cannot activate");
1355  continue;
1356  }
1357 
1358  if(eq(argv[0], "release")) {
1359  if(argc != 2)
1360  goto invalid;
1361  if(!registry::remove(argv[1]))
1362  control::reply("cannot release");
1363  continue;
1364  }
1365 
1366  control::reply("unknown command");
1367  }
1368 
1369  logtime.set();
1370  printlog("server shutdown %s\n", (const char *)logtime);
1371 }
1372 
1373 void server::printlog(const char *fmt, ...)
1374 {
1375  assert(fmt != NULL && *fmt != 0);
1376 
1377  fsys_t log;
1378  va_list vargs;
1379  char buf[1024];
1380  int len;
1381  char *cp;
1382 
1383  va_start(vargs, fmt);
1384 
1385  log.open(control::env("logfile"), fsys::GROUP_PRIVATE, fsys::APPEND);
1386  vsnprintf(buf, sizeof(buf) - 1, fmt, vargs);
1387  len = strlen(buf);
1388  if(buf[len - 1] != '\n')
1389  buf[len++] = '\n';
1390 
1391  if(is(log)) {
1392  log.write(buf, strlen(buf));
1393  log.close();
1394  }
1395  cp = strchr(buf, '\n');
1396  if(cp)
1397  *cp = 0;
1398 
1399  shell::debug(2, "logfile: %s", buf);
1400  va_end(vargs);
1401 }
1402 
1403 } // end namespace
linked_value< profile_t, LinkedObject > profile
Definition: server.h:480
static const char * sipusers
Definition: server.h:496
static void activate(MappedRegistry *user)
Send event for first instance of user registration.
Definition: events.cpp:284
void confirm(void)
Definition: server.cpp:225
unsigned count
Definition: cgiserver.cpp:92
static bool remove(const char *id)
Definition: registry.cpp:365
static void reload(void)
Definition: server.cpp:912
static void out(void)
Definition: history.cpp:85
static bool isLocal(const struct sockaddr *addr)
Definition: server.cpp:600
static void release(keynode *node)
Definition: service.cpp:394
stringbuf< 1024 > buffer
Definition: service.h:339
static void userdump(void)
Definition: cache.cpp:82
static String path(const char *id)
Get a string from a server environment variable.
Definition: control.h:141
static Socket::address * getAddress(const char *uri, Socket::address *addr=NULL)
Definition: stack.cpp:1146
Pointer to a provisioned user xml subtree.
Definition: service.h:119
service::keynode * keys
Definition: service.h:122
User profiles are used to map features and toll restriction level together under a common identifier...
Definition: mapped.h:83
cidr::policy * acl
Definition: server.h:482
static void reply(const char *error=NULL)
Used by the server to send replies back to control requests.
Definition: control.cpp:218
static volatile dialmode_t dialmode
Definition: service.h:252
keynode * find(const char *id)
Definition: server.cpp:193
static const char * getInterface(void)
Definition: service.h:312
static keynode * getConfig(void)
Definition: server.cpp:733
#define USER_PROFILE_DEFAULT
Definition: mapped.h:63
static stack::subnet * getPolicy(const struct sockaddr *addr)
Definition: server.cpp:686
Representation of a mapped active user record.
Definition: mapped.h:95
Used to splice new chains onto an existing xml tree.
Definition: service.h:105
keynode * getList(const char *path)
Definition: service.cpp:376
#define USER_PROFILE_DEVICE
Definition: mapped.h:60
static unsigned getRange(void)
Definition: server.h:190
void dump(FILE *fp)
Definition: server.cpp:891
static void snapshot(void)
Definition: service.cpp:861
static void publish(const char *addr)
Set and publish public "appearing" address of the server.
Definition: service.cpp:272
static bool set(const char *id, const char *hash)
Definition: digests.cpp:74
Linked list of named xml node locations.
Definition: service.h:331
static LinkedObject * getModules(void)
Definition: service.h:270
#define CONFIG_KEY_SIZE
Definition: service.h:65
static bool authenticate(voip::reg_t id, const char *realm)
Definition: server.cpp:127
static void dumpfile(void)
Definition: service.cpp:773
#define USER_PROFILE_ADMIN
Definition: mapped.h:58
keynode root
Definition: service.h:338
static void dump(FILE *fp, keynode *node, unsigned level)
Definition: service.cpp:735
static unsigned allocate(void)
Definition: server.cpp:1025
static keynode * getRouting(const char *id)
Definition: server.cpp:764
bool load(FILE *file, keynode *node=NULL)
Load xml file into xml tree.
Definition: service.cpp:565
#define SIP_OK
Definition: osip_const.h:97
static void enableDumping(void)
Definition: stack.cpp:325
bool create(const char *id, keynode *node)
Definition: server.cpp:208
static void logging(MappedRegistry *rr, const char *reason)
Definition: server.cpp:175
static void run(void)
Definition: server.cpp:1100
static const char * getRealm(void)
Definition: server.h:178
char state[32]
Definition: events.h:103
static condlock_t locking
Definition: service.h:344
static bool static char * receive(void)
Used by the server to pull pending fifo requests.
Definition: control.cpp:87
keynode * addNode(keynode *base, define *defs)
Definition: service.cpp:458
static void printlog(const char *fmt,...) __PRINTF(1
Definition: server.cpp:1373
static stack sip
Definition: server.h:398
static service * cfg
Definition: service.h:343
static bool isUserid(const char *id)
Definition: registry.cpp:956
static void published(struct sockaddr_storage *peer)
Definition: service.cpp:295
static bool static FILE * output(const char *id)
Used to open an output session for returning control data.
Definition: control.cpp:380
static const char * referLocal(MappedRegistry *rr, const char *target, char *buffer, size_t size)
Definition: server.cpp:108
void reset(const char *tag)
Definition: service.h:110
static int exit_code
Definition: server.h:498
static bool match(const char *digits, const char *pattern, bool partial)
Definition: service.cpp:954
static void release(stack::subnet *access)
Definition: server.cpp:594
static keynode * path(const char *p)
Definition: service.cpp:310
static void stop(void)
Definition: server.cpp:1095
static unsigned short getPort(void)
Definition: service.h:315
static void registration(voip::reg_t id, modules::regmode_t mode)
Definition: server.cpp:139
static unsigned uid
Definition: server.h:495
static const char * referRemote(MappedRegistry *rr, const char *target, char *buffer, size_t size)
Definition: server.cpp:89
static bool check(void)
Definition: server.cpp:877
LinkedObject * profiles
Definition: server.h:485
static bool state(const char *value)
Sets server run state configuration.
Definition: control.cpp:354
#define USER_PROFILE_SERVICE
Definition: mapped.h:61
static string_t getContact(void)
Definition: service.cpp:792
static const char * sipadmin
Definition: server.h:497
static shell::logmode_t logmode
Definition: server.h:494
static bool isExtension(const char *id)
Definition: registry.cpp:972
static keynode * list(const char *p)
Definition: service.cpp:320
static void detach(mapped *m)
Definition: registry.cpp:1100
static stack::subnet * getSubnet(const char *id)
Definition: server.cpp:614
service::keynode * node
Definition: service.h:334
#define USER_PROFILE_RESTRICTED
Definition: mapped.h:64
static const char * getDigest(void)
Definition: server.h:181
static int system(const char *to, const char *message)
Definition: messages.cpp:181
static void getProvision(const char *id, usernode &user)
Definition: server.cpp:850
void * context_t
Definition: voip.h:53
static bool period(long slice)
Definition: service.cpp:828
static void disableDumping(void)
Definition: stack.cpp:314
static bool checkId(const char *id)
Definition: server.cpp:796
static void clearDumping(void)
Definition: stack.cpp:319
short argc
Definition: cgiserver.cpp:93
void set(shell::loglevel_t lid, const char *msg)
Definition: history.cpp:33
static void release(MappedRegistry *user)
Send event for last instance of user expired or de-registering.
Definition: events.cpp:294
static bool check(void)
Definition: service.cpp:894
server(const char *id)
Definition: server.cpp:80
int reg_t
Definition: voip.h:59
keynode ** extmap
Definition: server.h:483
static void load(void)
Definition: digests.cpp:101
#define PAGING_SIZE
Definition: server.h:40
System configuration instance and service functions.
Definition: service.h:78
#define USER_PROFILE_LOCAL
Definition: mapped.h:59
keynode * provision
Definition: server.h:484
static unsigned getPrefix(void)
Definition: server.h:187
static void activate(MappedRegistry *rr)
Definition: server.cpp:149
static void getDialing(const char *id, usernode &user)
Definition: server.cpp:816
static void expire(MappedRegistry *rr)
Definition: server.cpp:162
char * map[96]
Definition: cgiserver.cpp:89
static const char * getValue(keynode *base, const char *id)
Definition: service.cpp:446
static void listPolicy(FILE *fp)
Definition: server.cpp:629
static mapped * allocate(const char *id)
Definition: registry.cpp:678
keynode * getPath(const char *path)
Definition: service.cpp:400
static profile_t * getProfile(const char *id)
Definition: server.cpp:703
static void plugins(const char *argv0, const char *names)
Definition: server.cpp:1053
static const char * env(const char *id)
Return the value of a server environment variable.
Definition: control.h:131
LinkedObject * keys[177]
Definition: service.h:340
treemap< char * > keynode
Definition of a xml node.
Definition: service.h:84
void commit(void)
Definition: service.cpp:910
static bool announce(MappedRegistry *rr, const char *msgtype, const char *event, const char *expires, const char *body)
Definition: server.cpp:181
#define DEBUG1
Definition: control.h:49