jabberd2  2.2.17
main.c
Go to the documentation of this file.
1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4  * Ryan Eatmon, Robert Norris
5  *
6  * This program 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  * This program 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., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19  */
20 
21 #include "c2s.h"
22 
23 #include <stringprep.h>
24 
25 static sig_atomic_t c2s_shutdown = 0;
26 sig_atomic_t c2s_lost_router = 0;
27 static sig_atomic_t c2s_logrotate = 0;
28 static sig_atomic_t c2s_sighup = 0;
29 
30 static void _c2s_signal(int signum)
31 {
32  c2s_shutdown = 1;
33  c2s_lost_router = 0;
34 }
35 
36 static void _c2s_signal_hup(int signum)
37 {
38  c2s_logrotate = 1;
39  c2s_sighup = 1;
40 }
41 
42 static void _c2s_signal_usr1(int signum)
43 {
44  set_debug_flag(0);
45 }
46 
47 static void _c2s_signal_usr2(int signum)
48 {
49  set_debug_flag(1);
50 }
51 
53 static void _c2s_pidfile(c2s_t c2s) {
54  char *pidfile;
55  FILE *f;
56  pid_t pid;
57 
58  pidfile = config_get_one(c2s->config, "pidfile", 0);
59  if(pidfile == NULL)
60  return;
61 
62  pid = getpid();
63 
64  if((f = fopen(pidfile, "w+")) == NULL) {
65  log_write(c2s->log, LOG_ERR, "couldn't open %s for writing: %s", pidfile, strerror(errno));
66  return;
67  }
68 
69  if(fprintf(f, "%d", pid) < 0) {
70  log_write(c2s->log, LOG_ERR, "couldn't write to %s: %s", pidfile, strerror(errno));
71  fclose(f);
72  return;
73  }
74 
75  fclose(f);
76 
77  log_write(c2s->log, LOG_INFO, "process id is %d, written to %s", pid, pidfile);
78 }
80 static void _c2s_config_expand(c2s_t c2s)
81 {
82  char *str, *ip, *mask;
83  char *req_domain, *to_address, *to_port;
84  config_elem_t elem;
85  int i;
87 
89 
90  c2s->id = config_get_one(c2s->config, "id", 0);
91  if(c2s->id == NULL)
92  c2s->id = "c2s";
93 
94  c2s->router_ip = config_get_one(c2s->config, "router.ip", 0);
95  if(c2s->router_ip == NULL)
96  c2s->router_ip = "127.0.0.1";
97 
98  c2s->router_port = j_atoi(config_get_one(c2s->config, "router.port", 0), 5347);
99 
100  c2s->router_user = config_get_one(c2s->config, "router.user", 0);
101  if(c2s->router_user == NULL)
102  c2s->router_user = "jabberd";
103  c2s->router_pass = config_get_one(c2s->config, "router.pass", 0);
104  if(c2s->router_pass == NULL)
105  c2s->router_pass = "secret";
106 
107  c2s->router_pemfile = config_get_one(c2s->config, "router.pemfile", 0);
108 
109  c2s->retry_init = j_atoi(config_get_one(c2s->config, "router.retry.init", 0), 3);
110  c2s->retry_lost = j_atoi(config_get_one(c2s->config, "router.retry.lost", 0), 3);
111  if((c2s->retry_sleep = j_atoi(config_get_one(c2s->config, "router.retry.sleep", 0), 2)) < 1)
112  c2s->retry_sleep = 1;
113 
114  c2s->log_type = log_STDOUT;
115  if(config_get(c2s->config, "log") != NULL) {
116  if((str = config_get_attr(c2s->config, "log", 0, "type")) != NULL) {
117  if(strcmp(str, "file") == 0)
118  c2s->log_type = log_FILE;
119  else if(strcmp(str, "syslog") == 0)
120  c2s->log_type = log_SYSLOG;
121  }
122  }
123 
124  if(c2s->log_type == log_SYSLOG) {
125  c2s->log_facility = config_get_one(c2s->config, "log.facility", 0);
126  c2s->log_ident = config_get_one(c2s->config, "log.ident", 0);
127  if(c2s->log_ident == NULL)
128  c2s->log_ident = "jabberd/c2s";
129  } else if(c2s->log_type == log_FILE)
130  c2s->log_ident = config_get_one(c2s->config, "log.file", 0);
131 
132  c2s->packet_stats = config_get_one(c2s->config, "stats.packet", 0);
133 
134  c2s->local_ip = config_get_one(c2s->config, "local.ip", 0);
135  if(c2s->local_ip == NULL)
136  c2s->local_ip = "0.0.0.0";
137 
138  c2s->local_port = j_atoi(config_get_one(c2s->config, "local.port", 0), 0);
139 
140  c2s->local_pemfile = config_get_one(c2s->config, "local.pemfile", 0);
141 
142  c2s->local_cachain = config_get_one(c2s->config, "local.cachain", 0);
143 
144  c2s->local_verify_mode = j_atoi(config_get_one(c2s->config, "local.verify-mode", 0), 0);
145 
146  c2s->local_ssl_port = j_atoi(config_get_one(c2s->config, "local.ssl-port", 0), 0);
147 
148  c2s->http_forward = config_get_one(c2s->config, "local.httpforward", 0);
149 
150  c2s->io_max_fds = j_atoi(config_get_one(c2s->config, "io.max_fds", 0), 1024);
151 
152  c2s->compression = (config_get(c2s->config, "io.compression") != NULL);
153 
154  c2s->io_check_interval = j_atoi(config_get_one(c2s->config, "io.check.interval", 0), 0);
155  c2s->io_check_idle = j_atoi(config_get_one(c2s->config, "io.check.idle", 0), 0);
156  c2s->io_check_keepalive = j_atoi(config_get_one(c2s->config, "io.check.keepalive", 0), 0);
157 
158  c2s->pbx_pipe = config_get_one(c2s->config, "pbx.pipe", 0);
159 
160  elem = config_get(c2s->config, "stream_redirect.redirect");
161  if(elem != NULL)
162  {
163  for(i = 0; i < elem->nvalues; i++)
164  {
166  if(!sr) {
167  log_write(c2s->log, LOG_ERR, "cannot allocate memory for new stream redirection record, aborting");
168  exit(1);
169  }
170  req_domain = j_attr((const char **) elem->attrs[i], "requested_domain");
171  to_address = j_attr((const char **) elem->attrs[i], "to_address");
172  to_port = j_attr((const char **) elem->attrs[i], "to_port");
173 
174  if(req_domain == NULL || to_address == NULL || to_port == NULL) {
175  log_write(c2s->log, LOG_ERR, "Error reading a stream_redirect.redirect element from file, skipping");
176  continue;
177  }
178 
179  // Note that to_address should be RFC 3986 compliant
180  sr->to_address = to_address;
181  sr->to_port = to_port;
182 
183  xhash_put(c2s->stream_redirects, pstrdup(xhash_pool(c2s->stream_redirects), req_domain), sr);
184  }
185  }
186 
187  c2s->ar_module_name = config_get_one(c2s->config, "authreg.module", 0);
188 
189  if(config_get(c2s->config, "authreg.mechanisms.traditional.plain") != NULL) c2s->ar_mechanisms |= AR_MECH_TRAD_PLAIN;
190  if(config_get(c2s->config, "authreg.mechanisms.traditional.digest") != NULL) c2s->ar_mechanisms |= AR_MECH_TRAD_DIGEST;
191 
192  if(config_get(c2s->config, "authreg.ssl-mechanisms.traditional.plain") != NULL) c2s->ar_ssl_mechanisms |= AR_MECH_TRAD_PLAIN;
193  if(config_get(c2s->config, "authreg.ssl-mechanisms.traditional.digest") != NULL) c2s->ar_ssl_mechanisms |= AR_MECH_TRAD_DIGEST;
194 
195  elem = config_get(c2s->config, "io.limits.bytes");
196  if(elem != NULL)
197  {
198  c2s->byte_rate_total = j_atoi(elem->values[0], 0);
199  if(c2s->byte_rate_total != 0)
200  {
201  c2s->byte_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 1);
202  c2s->byte_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 5);
203  }
204  }
205 
206  elem = config_get(c2s->config, "io.limits.stanzas");
207  if(elem != NULL)
208  {
209  c2s->stanza_rate_total = j_atoi(elem->values[0], 0);
210  if(c2s->stanza_rate_total != 0)
211  {
212  c2s->stanza_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 1);
213  c2s->stanza_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 5);
214  }
215  }
216 
217  elem = config_get(c2s->config, "io.limits.connects");
218  if(elem != NULL)
219  {
220  c2s->conn_rate_total = j_atoi(elem->values[0], 0);
221  if(c2s->conn_rate_total != 0)
222  {
223  c2s->conn_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 5);
224  c2s->conn_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 5);
225  }
226  }
227 
228  c2s->stanza_size_limit = j_atoi(config_get_one(c2s->config, "io.limits.stanzasize", 0), 0);
229 
230  /* tweak timed checks with rate times */
231  if(c2s->io_check_interval == 0) {
232  if(c2s->byte_rate_total != 0)
233  c2s->io_check_interval = c2s->byte_rate_wait;
234 
235  if(c2s->stanza_rate_total != 0 && c2s->io_check_interval > c2s->stanza_rate_wait)
237  }
238 
239  str = config_get_one(c2s->config, "io.access.order", 0);
240  if(str == NULL || strcmp(str, "deny,allow") != 0)
241  c2s->access = access_new(0);
242  else
243  c2s->access = access_new(1);
244 
245  elem = config_get(c2s->config, "io.access.allow");
246  if(elem != NULL)
247  {
248  for(i = 0; i < elem->nvalues; i++)
249  {
250  ip = j_attr((const char **) elem->attrs[i], "ip");
251  mask = j_attr((const char **) elem->attrs[i], "mask");
252 
253  if(ip == NULL)
254  continue;
255 
256  if(mask == NULL)
257  mask = "255.255.255.255";
258 
259  access_allow(c2s->access, ip, mask);
260  }
261  }
262 
263  elem = config_get(c2s->config, "io.access.deny");
264  if(elem != NULL)
265  {
266  for(i = 0; i < elem->nvalues; i++)
267  {
268  ip = j_attr((const char **) elem->attrs[i], "ip");
269  mask = j_attr((const char **) elem->attrs[i], "mask");
270 
271  if(ip == NULL)
272  continue;
273 
274  if(mask == NULL)
275  mask = "255.255.255.255";
276 
277  access_deny(c2s->access, ip, mask);
278  }
279  }
280 }
281 
282 static void _c2s_hosts_expand(c2s_t c2s)
283 {
284  char *realm;
285  config_elem_t elem;
286  char id[1024];
287  int i;
288 
289  elem = config_get(c2s->config, "local.id");
290  if(!elem) {
291  log_write(c2s->log, LOG_NOTICE, "no local.id configured - skipping local domains configuration");
292  return;
293  }
294  for(i = 0; i < elem->nvalues; i++) {
295  host_t host = (host_t) pmalloco(xhash_pool(c2s->hosts), sizeof(struct host_st));
296  if(!host) {
297  log_write(c2s->log, LOG_ERR, "cannot allocate memory for new host, aborting");
298  exit(1);
299  }
300 
301  realm = j_attr((const char **) elem->attrs[i], "realm");
302 
303  /* stringprep ids (domain names) so that they are in canonical form */
304  strncpy(id, elem->values[i], 1024);
305  id[1023] = '\0';
306  if (stringprep_nameprep(id, 1024) != 0) {
307  log_write(c2s->log, LOG_ERR, "cannot stringprep id %s, aborting", id);
308  exit(1);
309  }
310 
311  host->realm = (realm != NULL) ? realm : pstrdup(xhash_pool(c2s->hosts), id);
312 
313  host->host_pemfile = j_attr((const char **) elem->attrs[i], "pemfile");
314 
315  host->host_cachain = j_attr((const char **) elem->attrs[i], "cachain");
316 
317  host->host_verify_mode = j_atoi(j_attr((const char **) elem->attrs[i], "verify-mode"), 0);
318 
319 #ifdef HAVE_SSL
320  if(host->host_pemfile != NULL) {
321  if(c2s->sx_ssl == NULL) {
322  c2s->sx_ssl = sx_env_plugin(c2s->sx_env, sx_ssl_init, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode);
323  if(c2s->sx_ssl == NULL) {
324  log_write(c2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm);
325  host->host_pemfile = NULL;
326  }
327  } else {
328  if(sx_ssl_server_addcert(c2s->sx_ssl, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode) != 0) {
329  log_write(c2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm);
330  host->host_pemfile = NULL;
331  }
332  }
333  }
334 #endif
335 
336  host->host_require_starttls = (j_attr((const char **) elem->attrs[i], "require-starttls") != NULL);
337 
338  host->ar_register_enable = (j_attr((const char **) elem->attrs[i], "register-enable") != NULL);
339  host->ar_register_oob = j_attr((const char **) elem->attrs[i], "register-oob");
340  if(host->ar_register_enable || host->ar_register_oob) {
341  host->ar_register_instructions = j_attr((const char **) elem->attrs[i], "instructions");
342  if(host->ar_register_instructions == NULL) {
343  if(host->ar_register_oob)
344  host->ar_register_instructions = "Only web based registration is possible with this server.";
345  else
346  host->ar_register_instructions = "Enter a username and password to register with this server.";
347  }
348  } else
349  host->ar_register_password = (j_attr((const char **) elem->attrs[i], "password-change") != NULL);
350 
351  /* check for empty <id/> CDATA - XXX this "1" is VERY config.c dependant !!! */
352  if(! strcmp(id, "1")) {
353  /* remove the realm even if set */
354  host->realm = NULL;
355 
356  /* skip if vHost already configured */
357  if(! c2s->vhost)
358  c2s->vhost = host;
359 
360  /* add meaningful log "id" */
361  strcpy(id, "default vHost");
362  } else {
363  /* insert into vHosts xhash */
364  xhash_put(c2s->hosts, pstrdup(xhash_pool(c2s->hosts), id), host);
365  }
366 
367  log_write(c2s->log, LOG_NOTICE, "[%s] configured; realm=%s, registration %s, using PEM:%s",
368  id, (host->realm != NULL ? host->realm : "no realm set"), (host->ar_register_enable ? "enabled" : "disabled"),
369  (host->host_pemfile ? host->host_pemfile : "Default"));
370  }
371 }
372 
373 static int _c2s_router_connect(c2s_t c2s) {
374  log_write(c2s->log, LOG_NOTICE, "attempting connection to router at %s, port=%d", c2s->router_ip, c2s->router_port);
375 
376  c2s->fd = mio_connect(c2s->mio, c2s->router_port, c2s->router_ip, NULL, c2s_router_mio_callback, (void *) c2s);
377  if(c2s->fd == NULL) {
378  if(errno == ECONNREFUSED)
379  c2s_lost_router = 1;
380  log_write(c2s->log, LOG_NOTICE, "connection attempt to router failed: %s (%d)", MIO_STRERROR(MIO_ERROR), MIO_ERROR);
381  return 1;
382  }
383 
384  c2s->router = sx_new(c2s->sx_env, c2s->fd->fd, c2s_router_sx_callback, (void *) c2s);
385  sx_client_init(c2s->router, 0, NULL, NULL, NULL, "1.0");
386 
387  return 0;
388 }
389 
390 static int _c2s_sx_sasl_callback(int cb, void *arg, void **res, sx_t s, void *cbarg) {
391  c2s_t c2s = (c2s_t) cbarg;
392  char *my_realm, *mech;
393  sx_sasl_creds_t creds;
394  static char buf[3072];
395  char mechbuf[256];
396  struct jid_st jid;
397  jid_static_buf jid_buf;
398  int i, r;
399 
400  /* init static jid */
401  jid_static(&jid,&jid_buf);
402 
403  switch(cb) {
405 
406  if(s->req_to == NULL) /* this shouldn't happen */
407  my_realm = "";
408 
409  else {
410  host_t host;
411  /* get host for request */
412  host = xhash_get(c2s->hosts, s->req_to);
413  if(host == NULL) {
414  log_write(c2s->log, LOG_ERR, "SASL callback for non-existing host: %s", s->req_to);
415  *res = (void *)NULL;
416  return sx_sasl_ret_FAIL;
417  }
418 
419  my_realm = host->realm;
420  if(my_realm == NULL)
421  my_realm = s->req_to;
422  }
423 
424  strncpy(buf, my_realm, 256);
425  *res = (void *)buf;
426 
427  log_debug(ZONE, "sx sasl callback: get realm: realm is '%s'", buf);
428  return sx_sasl_ret_OK;
429  break;
430 
431  case sx_sasl_cb_GET_PASS:
432  creds = (sx_sasl_creds_t) arg;
433 
434  log_debug(ZONE, "sx sasl callback: get pass (authnid=%s, realm=%s)", creds->authnid, creds->realm);
435 
436  if(c2s->ar->get_password && (c2s->ar->get_password)(c2s->ar, (char *)creds->authnid, (creds->realm != NULL) ? (char *)creds->realm: "", buf) == 0) {
437  *res = buf;
438  return sx_sasl_ret_OK;
439  }
440 
441  return sx_sasl_ret_FAIL;
442 
444  creds = (sx_sasl_creds_t) arg;
445 
446  log_debug(ZONE, "sx sasl callback: check pass (authnid=%s, realm=%s)", creds->authnid, creds->realm);
447 
448  if(c2s->ar->check_password != NULL) {
449  if ((c2s->ar->check_password)(c2s->ar, (char *)creds->authnid, (creds->realm != NULL) ? (char *)creds->realm : "", (char *)creds->pass) == 0)
450  return sx_sasl_ret_OK;
451  else
452  return sx_sasl_ret_FAIL;
453  }
454 
455  if(c2s->ar->get_password != NULL) {
456  if ((c2s->ar->get_password)(c2s->ar, (char *)creds->authnid, (creds->realm != NULL) ? (char *)creds->realm : "", buf) != 0)
457  return sx_sasl_ret_FAIL;
458 
459  if (strcmp(creds->pass, buf)==0)
460  return sx_sasl_ret_OK;
461  }
462 
463  return sx_sasl_ret_FAIL;
464  break;
465 
467  creds = (sx_sasl_creds_t) arg;
468 
469  /* we need authzid to validate */
470  if(creds->authzid == NULL || creds->authzid[0] == '\0')
471  return sx_sasl_ret_FAIL;
472 
473  /* authzid must be a valid jid */
474  if(jid_reset(&jid, creds->authzid, -1) == NULL)
475  return sx_sasl_ret_FAIL;
476 
477  /* and have domain == stream to addr */
478  if(!s->req_to || (strcmp(jid.domain, s->req_to) != 0))
479  return sx_sasl_ret_FAIL;
480 
481  /* and have no resource */
482  if(jid.resource[0] != '\0')
483  return sx_sasl_ret_FAIL;
484 
485  /* and user has right to authorize as */
486  if (c2s->ar->user_authz_allowed) {
487  if (c2s->ar->user_authz_allowed(c2s->ar, (char *)creds->authnid, (char *)creds->realm, (char *)creds->authzid))
488  return sx_sasl_ret_OK;
489  } else {
490  if (strcmp(creds->authnid, jid.node) == 0 &&
491  (c2s->ar->user_exists)(c2s->ar, jid.node, jid.domain))
492  return sx_sasl_ret_OK;
493  }
494 
495  return sx_sasl_ret_FAIL;
496 
498  /* generate a jid for SASL ANONYMOUS */
499  jid_reset(&jid, s->req_to, -1);
500 
501  /* make node a random string */
502  jid_random_part(&jid, jid_NODE);
503 
504  strcpy(buf, jid.node);
505 
506  *res = (void *)buf;
507 
508  return sx_sasl_ret_OK;
509  break;
510 
512  mech = (char *)arg;
513 
514  i=0;
515  while(i<sizeof(mechbuf) && mech[i]!='\0') {
516  mechbuf[i]=tolower(mech[i]);
517  i++;
518  }
519  mechbuf[i]='\0';
520 
521  /* Determine if our configuration will let us use this mechanism.
522  * We support different mechanisms for both SSL and normal use */
523 
524  if (strcmp(mechbuf, "digest-md5") == 0) {
525  /* digest-md5 requires that our authreg support get_password */
526  if (c2s->ar->get_password == NULL)
527  return sx_sasl_ret_FAIL;
528  } else if (strcmp(mechbuf, "plain") == 0) {
529  /* plain requires either get_password or check_password */
530  if (c2s->ar->get_password == NULL && c2s->ar->check_password == NULL)
531  return sx_sasl_ret_FAIL;
532  }
533 
534  /* Using SSF is potentially dangerous, as SASL can also set the
535  * SSF of the connection. However, SASL shouldn't do so until after
536  * we've finished mechanism establishment
537  */
538  if (s->ssf>0) {
539  r = snprintf(buf, sizeof(buf), "authreg.ssl-mechanisms.sasl.%s",mechbuf);
540  if (r < -1 || r > sizeof(buf))
541  return sx_sasl_ret_FAIL;
542  if(config_get(c2s->config,buf) != NULL)
543  return sx_sasl_ret_OK;
544  }
545 
546  r = snprintf(buf, sizeof(buf), "authreg.mechanisms.sasl.%s",mechbuf);
547  if (r < -1 || r > sizeof(buf))
548  return sx_sasl_ret_FAIL;
549 
550  /* Work out if our configuration will let us use this mechanism */
551  if(config_get(c2s->config,buf) != NULL)
552  return sx_sasl_ret_OK;
553  else
554  return sx_sasl_ret_FAIL;
555  default:
556  break;
557  }
558 
559  return sx_sasl_ret_FAIL;
560 }
561 static void _c2s_time_checks(c2s_t c2s) {
562  sess_t sess;
563  time_t now;
564  union xhashv xhv;
565 
566  now = time(NULL);
567 
568  if(xhash_iter_first(c2s->sessions))
569  do {
570  xhv.sess_val = &sess;
571  xhash_iter_get(c2s->sessions, NULL, NULL, xhv.val);
572 
573  if(c2s->io_check_idle > 0 && sess->s && now > sess->last_activity + c2s->io_check_idle) {
574  log_write(c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] timed out", sess->fd->fd, sess->ip, sess->port);
575 
576  sx_error(sess->s, stream_err_HOST_GONE, "connection timed out");
577  sx_close(sess->s);
578 
579  continue;
580  }
581 
582  if(c2s->io_check_keepalive > 0 && now > sess->last_activity + c2s->io_check_keepalive && sess->s->state >= state_STREAM) {
583  log_debug(ZONE, "sending keepalive for %d", sess->fd->fd);
584 
585  sx_raw_write(sess->s, " ", 1);
586  }
587 
588  if(sess->rate != NULL && sess->rate->bad != 0 && rate_check(sess->rate) != 0) {
589  /* read the pending bytes when rate limit is no longer in effect */
590  log_debug(ZONE, "reading throttled %d", sess->fd->fd);
591  sess->s->want_read = 1;
592  sx_can_read(sess->s);
593  }
594 
595  } while(xhash_iter_next(c2s->sessions));
596 }
597 
598 JABBER_MAIN("jabberd2c2s", "Jabber 2 C2S", "Jabber Open Source Server: Client to Server", "jabberd2router\0")
599 {
600  c2s_t c2s;
601  char *config_file;
602  int optchar;
603  int mio_timeout;
604  sess_t sess;
605  bres_t res;
606  union xhashv xhv;
607  time_t check_time = 0;
608  const char *cli_id = 0;
609 
610 #ifdef HAVE_UMASK
611  umask((mode_t) 0027);
612 #endif
613 
614  srand(time(NULL));
615 
616 #ifdef HAVE_WINSOCK2_H
617 /* get winsock running */
618  {
619  WORD wVersionRequested;
620  WSADATA wsaData;
621  int err;
622 
623  wVersionRequested = MAKEWORD( 2, 2 );
624 
625  err = WSAStartup( wVersionRequested, &wsaData );
626  if ( err != 0 ) {
627  /* !!! tell user that we couldn't find a usable winsock dll */
628  return 0;
629  }
630  }
631 #endif
632 
633  jabber_signal(SIGINT, _c2s_signal);
634  jabber_signal(SIGTERM, _c2s_signal);
635 #ifdef SIGHUP
637 #endif
638 #ifdef SIGPIPE
639  jabber_signal(SIGPIPE, SIG_IGN);
640 #endif
643 
644 
645  c2s = (c2s_t) calloc(1, sizeof(struct c2s_st));
646 
647  /* load our config */
648  c2s->config = config_new();
649 
650  config_file = CONFIG_DIR "/c2s.xml";
651 
652  /* cmdline parsing */
653  while((optchar = getopt(argc, argv, "Dc:hi:?")) >= 0)
654  {
655  switch(optchar)
656  {
657  case 'c':
658  config_file = optarg;
659  break;
660  case 'D':
661 #ifdef DEBUG
662  set_debug_flag(1);
663 #else
664  printf("WARN: Debugging not enabled. Ignoring -D.\n");
665 #endif
666  break;
667  case 'i':
668  cli_id = optarg;
669  break;
670  case 'h': case '?': default:
671  fputs(
672  "c2s - jabberd client-to-server connector (" VERSION ")\n"
673  "Usage: c2s <options>\n"
674  "Options are:\n"
675  " -c <config> config file to use [default: " CONFIG_DIR "/c2s.xml]\n"
676  " -i id Override <id> config element\n"
677 #ifdef DEBUG
678  " -D Show debug output\n"
679 #endif
680  ,
681  stdout);
682  config_free(c2s->config);
683  free(c2s);
684  return 1;
685  }
686  }
687 
688  if(config_load_with_id(c2s->config, config_file, cli_id) != 0)
689  {
690  fputs("c2s: couldn't load config, aborting\n", stderr);
691  config_free(c2s->config);
692  free(c2s);
693  return 2;
694  }
695 
696  c2s->stream_redirects = xhash_new(523);
697 
698  _c2s_config_expand(c2s);
699 
700  c2s->log = log_new(c2s->log_type, c2s->log_ident, c2s->log_facility);
701  log_write(c2s->log, LOG_NOTICE, "starting up");
702 
703  _c2s_pidfile(c2s);
704 
705  if(c2s->ar_module_name == NULL) {
706  log_write(c2s->log, LOG_NOTICE, "no authreg module specified in config file");
707  }
708  else if((c2s->ar = authreg_init(c2s, c2s->ar_module_name)) == NULL) {
709  access_free(c2s->access);
710  config_free(c2s->config);
711  log_free(c2s->log);
712  free(c2s);
713  exit(1);
714  }
715 
716  c2s->sessions = xhash_new(1023);
717 
718  c2s->conn_rates = xhash_new(101);
719 
720  c2s->dead = jqueue_new();
721 
722  c2s->dead_sess = jqueue_new();
723 
724  c2s->sx_env = sx_env_new();
725 
726 #ifdef HAVE_SSL
727  /* get the ssl context up and running */
728  if(c2s->local_pemfile != NULL) {
730  if(c2s->sx_ssl == NULL) {
731  log_write(c2s->log, LOG_ERR, "failed to load local SSL pemfile, SSL will not be available to clients");
732  c2s->local_pemfile = NULL;
733  }
734  }
735 
736  /* try and get something online, so at least we can encrypt to the router */
737  if(c2s->sx_ssl == NULL && c2s->router_pemfile != NULL) {
738  c2s->sx_ssl = sx_env_plugin(c2s->sx_env, sx_ssl_init, NULL, c2s->router_pemfile, NULL, NULL);
739  if(c2s->sx_ssl == NULL) {
740  log_write(c2s->log, LOG_ERR, "failed to load router SSL pemfile, channel to router will not be SSL encrypted");
741  c2s->router_pemfile = NULL;
742  }
743  }
744 #endif
745 
746 #ifdef HAVE_LIBZ
747  /* get compression up and running */
748  if(c2s->compression)
750 #endif
751 
752 #ifdef ENABLE_EXPERIMENTAL
753  /* get stanza ack up */
755 
756  /* and user IP address plugin */
758 #endif
759 
760  /* get sasl online */
761  c2s->sx_sasl = sx_env_plugin(c2s->sx_env, sx_sasl_init, "xmpp", _c2s_sx_sasl_callback, (void *) c2s);
762  if(c2s->sx_sasl == NULL) {
763  log_write(c2s->log, LOG_ERR, "failed to initialise SASL context, aborting");
764  exit(1);
765  }
766 
767  /* get bind up */
768  sx_env_plugin(c2s->sx_env, bind_init, c2s);
769 
770  c2s->mio = mio_new(c2s->io_max_fds);
771  if(c2s->mio == NULL) {
772  log_write(c2s->log, LOG_ERR, "failed to create MIO, aborting");
773  exit(1);
774  }
775 
776  /* hosts mapping */
777  c2s->hosts = xhash_new(1021);
778  _c2s_hosts_expand(c2s);
779  c2s->sm_avail = xhash_new(1021);
780 
781  c2s->retry_left = c2s->retry_init;
782  _c2s_router_connect(c2s);
783 
784  mio_timeout = ((c2s->io_check_interval != 0 && c2s->io_check_interval < 5) ?
785  c2s->io_check_interval : 5);
786 
787  while(!c2s_shutdown) {
788  mio_run(c2s->mio, mio_timeout);
789 
790  if(c2s_logrotate) {
792 
793  log_write(c2s->log, LOG_NOTICE, "reopening log ...");
794  log_free(c2s->log);
795  c2s->log = log_new(c2s->log_type, c2s->log_ident, c2s->log_facility);
796  log_write(c2s->log, LOG_NOTICE, "log started");
797 
798  c2s_logrotate = 0;
799  }
800 
801  if(c2s_sighup) {
802  log_write(c2s->log, LOG_NOTICE, "reloading some configuration items ...");
803  config_t conf;
804  conf = config_new();
805  if (conf && config_load(conf, config_file) == 0) {
807  c2s->stream_redirects = xhash_new(523);
808 
809  char *req_domain, *to_address, *to_port;
810  config_elem_t elem;
811  int i;
813 
814  elem = config_get(conf, "stream_redirect.redirect");
815  if(elem != NULL)
816  {
817  for(i = 0; i < elem->nvalues; i++)
818  {
820  if(!sr) {
821  log_write(c2s->log, LOG_ERR, "cannot allocate memory for new stream redirection record, aborting");
822  exit(1);
823  }
824  req_domain = j_attr((const char **) elem->attrs[i], "requested_domain");
825  to_address = j_attr((const char **) elem->attrs[i], "to_address");
826  to_port = j_attr((const char **) elem->attrs[i], "to_port");
827 
828  if(req_domain == NULL || to_address == NULL || to_port == NULL) {
829  log_write(c2s->log, LOG_ERR, "Error reading a stream_redirect.redirect element from file, skipping");
830  continue;
831  }
832 
833  // Note that to_address should be RFC 3986 compliant
834  sr->to_address = to_address;
835  sr->to_port = to_port;
836 
837  xhash_put(c2s->stream_redirects, pstrdup(xhash_pool(c2s->stream_redirects), req_domain), sr);
838  }
839  }
840  config_free(conf);
841  } else {
842  log_write(c2s->log, LOG_WARNING, "couldn't reload config (%s)", config_file);
843  if (conf) config_free(conf);
844  }
845  c2s_sighup = 0;
846  }
847 
848  if(c2s_lost_router) {
849  if(c2s->retry_left < 0) {
850  log_write(c2s->log, LOG_NOTICE, "attempting reconnect");
851  sleep(c2s->retry_sleep);
852  c2s_lost_router = 0;
853  if (c2s->router) sx_free(c2s->router);
854  _c2s_router_connect(c2s);
855  }
856 
857  else if(c2s->retry_left == 0) {
858  c2s_shutdown = 1;
859  }
860 
861  else {
862  log_write(c2s->log, LOG_NOTICE, "attempting reconnect (%d left)", c2s->retry_left);
863  c2s->retry_left--;
864  sleep(c2s->retry_sleep);
865  c2s_lost_router = 0;
866  if (c2s->router) sx_free(c2s->router);
867  _c2s_router_connect(c2s);
868  }
869  }
870 
871  /* cleanup dead sess (before sx_t as sess->result uses sx_t nad cache) */
872  while(jqueue_size(c2s->dead_sess) > 0) {
873  sess = (sess_t) jqueue_pull(c2s->dead_sess);
874 
875  /* free sess data */
876  if(sess->ip != NULL) free(sess->ip);
877  if(sess->smcomp != NULL) free(sess->smcomp);
878  if(sess->result != NULL) nad_free(sess->result);
879  if(sess->resources != NULL)
880  for(res = sess->resources; res != NULL;) {
881  bres_t tmp = res->next;
882  jid_free(res->jid);
883  free(res);
884  res = tmp;
885  }
886  if(sess->rate != NULL) rate_free(sess->rate);
887  if(sess->stanza_rate != NULL) rate_free(sess->stanza_rate);
888 
889  free(sess);
890  }
891 
892  /* cleanup dead sx_ts */
893  while(jqueue_size(c2s->dead) > 0)
894  sx_free((sx_t) jqueue_pull(c2s->dead));
895 
896  /* time checks */
897  if(c2s->io_check_interval > 0 && time(NULL) >= c2s->next_check) {
898  log_debug(ZONE, "running time checks");
899 
900  _c2s_time_checks(c2s);
901 
902  c2s->next_check = time(NULL) + c2s->io_check_interval;
903  log_debug(ZONE, "next time check at %d", c2s->next_check);
904  }
905 
906  if(time(NULL) > check_time + 60) {
907 #ifdef POOL_DEBUG
908  pool_stat(1);
909 #endif
910  if(c2s->packet_stats != NULL) {
911  int fd = open(c2s->packet_stats, O_TRUNC | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP);
912  if (fd >= 0) {
913  char buf[100];
914  int len = snprintf(buf, 100, "%lld\n", c2s->packet_count);
915  if (write(fd, buf, len) != len) {
916  close(fd);
917  fd = -1;
918  } else close(fd);
919  }
920  if (fd < 0) {
921  log_write(c2s->log, LOG_ERR, "failed to write packet statistics to: %s", c2s->packet_stats);
922  c2s_shutdown = 1;
923  }
924  }
925 
926  check_time = time(NULL);
927  }
928  }
929 
930  log_write(c2s->log, LOG_NOTICE, "shutting down");
931 
932  if(xhash_iter_first(c2s->sessions))
933  do {
934  xhv.sess_val = &sess;
935  xhash_iter_get(c2s->sessions, NULL, NULL, xhv.val);
936 
937  if(sess->active && sess->s)
938  sx_close(sess->s);
939 
940  } while(xhash_iter_next(c2s->sessions));
941 
942  /* cleanup dead sess */
943  while(jqueue_size(c2s->dead_sess) > 0) {
944  sess = (sess_t) jqueue_pull(c2s->dead_sess);
945 
946  /* free sess data */
947  if(sess->ip != NULL) free(sess->ip);
948  if(sess->result != NULL) nad_free(sess->result);
949  if(sess->resources != NULL)
950  for(res = sess->resources; res != NULL;) {
951  bres_t tmp = res->next;
952  jid_free(res->jid);
953  free(res);
954  res = tmp;
955  }
956 
957  free(sess);
958  }
959 
960  while(jqueue_size(c2s->dead) > 0)
961  sx_free((sx_t) jqueue_pull(c2s->dead));
962 
963  if (c2s->fd != NULL) mio_close(c2s->mio, c2s->fd);
964  sx_free(c2s->router);
965 
966  sx_env_free(c2s->sx_env);
967 
968  mio_free(c2s->mio);
969 
970  xhash_free(c2s->sessions);
971 
972  authreg_free(c2s->ar);
973 
974  xhash_free(c2s->conn_rates);
975 
977 
978  xhash_free(c2s->sm_avail);
979 
980  xhash_free(c2s->hosts);
981 
982  jqueue_free(c2s->dead);
983 
984  jqueue_free(c2s->dead_sess);
985 
986  access_free(c2s->access);
987 
988  log_free(c2s->log);
989 
990  config_free(c2s->config);
991 
992  free(c2s);
993 
994 #ifdef POOL_DEBUG
995  pool_stat(1);
996 #endif
997 
998 #ifdef HAVE_WINSOCK2_H
999  WSACleanup();
1000 #endif
1001 
1002  return 0;
1003 }