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