jabberd2  2.2.16
c2s/main.c
Go to the documentation of this file.
00001 /*
00002  * jabberd - Jabber Open Source Server
00003  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
00004  *                    Ryan Eatmon, Robert Norris
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
00019  */
00020 
00021 #include "c2s.h"
00022 
00023 #include <stringprep.h>
00024 
00025 static sig_atomic_t c2s_shutdown = 0;
00026 sig_atomic_t c2s_lost_router = 0;
00027 static sig_atomic_t c2s_logrotate = 0;
00028 static sig_atomic_t c2s_sighup = 0;
00029 
00030 static void _c2s_signal(int signum)
00031 {
00032     c2s_shutdown = 1;
00033     c2s_lost_router = 0;
00034 }
00035 
00036 static void _c2s_signal_hup(int signum)
00037 {
00038     c2s_logrotate = 1;
00039     c2s_sighup = 1;
00040 }
00041 
00042 static void _c2s_signal_usr1(int signum)
00043 {
00044     set_debug_flag(0);
00045 }
00046 
00047 static void _c2s_signal_usr2(int signum)
00048 {
00049     set_debug_flag(1);
00050 }
00051 
00053 static void _c2s_pidfile(c2s_t c2s) {
00054     char *pidfile;
00055     FILE *f;
00056     pid_t pid;
00057 
00058     pidfile = config_get_one(c2s->config, "pidfile", 0);
00059     if(pidfile == NULL)
00060         return;
00061 
00062     pid = getpid();
00063 
00064     if((f = fopen(pidfile, "w+")) == NULL) {
00065         log_write(c2s->log, LOG_ERR, "couldn't open %s for writing: %s", pidfile, strerror(errno));
00066         return;
00067     }
00068 
00069     if(fprintf(f, "%d", pid) < 0) {
00070         log_write(c2s->log, LOG_ERR, "couldn't write to %s: %s", pidfile, strerror(errno));
00071         fclose(f);
00072         return;
00073     }
00074 
00075     fclose(f);
00076 
00077     log_write(c2s->log, LOG_INFO, "process id is %d, written to %s", pid, pidfile);
00078 }
00080 static void _c2s_config_expand(c2s_t c2s)
00081 {
00082     char *str, *ip, *mask;
00083     char *req_domain, *to_address, *to_port;
00084     config_elem_t elem;
00085     int i;
00086     stream_redirect_t sr;
00087 
00088     set_debug_log_from_config(c2s->config);
00089 
00090     c2s->id = config_get_one(c2s->config, "id", 0);
00091     if(c2s->id == NULL)
00092         c2s->id = "c2s";
00093 
00094     c2s->router_ip = config_get_one(c2s->config, "router.ip", 0);
00095     if(c2s->router_ip == NULL)
00096         c2s->router_ip = "127.0.0.1";
00097 
00098     c2s->router_port = j_atoi(config_get_one(c2s->config, "router.port", 0), 5347);
00099 
00100     c2s->router_user = config_get_one(c2s->config, "router.user", 0);
00101     if(c2s->router_user == NULL)
00102         c2s->router_user = "jabberd";
00103     c2s->router_pass = config_get_one(c2s->config, "router.pass", 0);
00104     if(c2s->router_pass == NULL)
00105         c2s->router_pass = "secret";
00106 
00107     c2s->router_pemfile = config_get_one(c2s->config, "router.pemfile", 0);
00108 
00109     c2s->retry_init = j_atoi(config_get_one(c2s->config, "router.retry.init", 0), 3);
00110     c2s->retry_lost = j_atoi(config_get_one(c2s->config, "router.retry.lost", 0), 3);
00111     if((c2s->retry_sleep = j_atoi(config_get_one(c2s->config, "router.retry.sleep", 0), 2)) < 1)
00112         c2s->retry_sleep = 1;
00113 
00114     c2s->log_type = log_STDOUT;
00115     if(config_get(c2s->config, "log") != NULL) {
00116         if((str = config_get_attr(c2s->config, "log", 0, "type")) != NULL) {
00117             if(strcmp(str, "file") == 0)
00118                 c2s->log_type = log_FILE;
00119             else if(strcmp(str, "syslog") == 0)
00120                 c2s->log_type = log_SYSLOG;
00121         }
00122     }
00123 
00124     if(c2s->log_type == log_SYSLOG) {
00125         c2s->log_facility = config_get_one(c2s->config, "log.facility", 0);
00126         c2s->log_ident = config_get_one(c2s->config, "log.ident", 0);
00127         if(c2s->log_ident == NULL)
00128             c2s->log_ident = "jabberd/c2s";
00129     } else if(c2s->log_type == log_FILE)
00130         c2s->log_ident = config_get_one(c2s->config, "log.file", 0);
00131 
00132     c2s->packet_stats = config_get_one(c2s->config, "stats.packet", 0);
00133 
00134     c2s->local_ip = config_get_one(c2s->config, "local.ip", 0);
00135     if(c2s->local_ip == NULL)
00136         c2s->local_ip = "0.0.0.0";
00137 
00138     c2s->local_port = j_atoi(config_get_one(c2s->config, "local.port", 0), 0);
00139 
00140     c2s->local_pemfile = config_get_one(c2s->config, "local.pemfile", 0);
00141 
00142     c2s->local_cachain = config_get_one(c2s->config, "local.cachain", 0);
00143 
00144     c2s->local_verify_mode = j_atoi(config_get_one(c2s->config, "local.verify-mode", 0), 0);
00145 
00146     c2s->local_ssl_port = j_atoi(config_get_one(c2s->config, "local.ssl-port", 0), 0);
00147 
00148     c2s->http_forward = config_get_one(c2s->config, "local.httpforward", 0);
00149 
00150     c2s->io_max_fds = j_atoi(config_get_one(c2s->config, "io.max_fds", 0), 1024);
00151 
00152     c2s->compression = (config_get(c2s->config, "io.compression") != NULL);
00153 
00154     c2s->io_check_interval = j_atoi(config_get_one(c2s->config, "io.check.interval", 0), 0);
00155     c2s->io_check_idle = j_atoi(config_get_one(c2s->config, "io.check.idle", 0), 0);
00156     c2s->io_check_keepalive = j_atoi(config_get_one(c2s->config, "io.check.keepalive", 0), 0);
00157 
00158     c2s->pbx_pipe = config_get_one(c2s->config, "pbx.pipe", 0);
00159 
00160     elem = config_get(c2s->config, "stream_redirect.redirect");
00161     if(elem != NULL)
00162     {
00163         for(i = 0; i < elem->nvalues; i++)
00164         {
00165             sr = (stream_redirect_t) pmalloco(xhash_pool(c2s->stream_redirects), sizeof(struct stream_redirect_st));
00166             if(!sr) {
00167                 log_write(c2s->log, LOG_ERR, "cannot allocate memory for new stream redirection record, aborting");
00168                 exit(1);
00169             }
00170             req_domain = j_attr((const char **) elem->attrs[i], "requested_domain");
00171             to_address = j_attr((const char **) elem->attrs[i], "to_address");
00172             to_port = j_attr((const char **) elem->attrs[i], "to_port");
00173 
00174             if(req_domain == NULL || to_address == NULL || to_port == NULL) {
00175                 log_write(c2s->log, LOG_ERR, "Error reading a stream_redirect.redirect element from file, skipping");
00176                 continue;
00177             }
00178 
00179             // Note that to_address should be RFC 3986 compliant
00180             sr->to_address = to_address;
00181             sr->to_port = to_port;
00182             
00183             xhash_put(c2s->stream_redirects, pstrdup(xhash_pool(c2s->stream_redirects), req_domain), sr);
00184         }
00185     }
00186 
00187     c2s->ar_module_name = config_get_one(c2s->config, "authreg.module", 0);
00188 
00189     if(config_get(c2s->config, "authreg.mechanisms.traditional.plain") != NULL) c2s->ar_mechanisms |= AR_MECH_TRAD_PLAIN;
00190     if(config_get(c2s->config, "authreg.mechanisms.traditional.digest") != NULL) c2s->ar_mechanisms |= AR_MECH_TRAD_DIGEST;
00191 
00192     if(config_get(c2s->config, "authreg.ssl-mechanisms.traditional.plain") != NULL) c2s->ar_ssl_mechanisms |= AR_MECH_TRAD_PLAIN;
00193     if(config_get(c2s->config, "authreg.ssl-mechanisms.traditional.digest") != NULL) c2s->ar_ssl_mechanisms |= AR_MECH_TRAD_DIGEST;
00194 
00195     elem = config_get(c2s->config, "io.limits.bytes");
00196     if(elem != NULL)
00197     {
00198         c2s->byte_rate_total = j_atoi(elem->values[0], 0);
00199         if(c2s->byte_rate_total != 0)
00200         {
00201             c2s->byte_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 1);
00202             c2s->byte_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 5);
00203         }
00204     }
00205 
00206     elem = config_get(c2s->config, "io.limits.stanzas");
00207     if(elem != NULL)
00208     {
00209         c2s->stanza_rate_total = j_atoi(elem->values[0], 0);
00210         if(c2s->stanza_rate_total != 0)
00211         {
00212             c2s->stanza_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 1);
00213             c2s->stanza_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 5);
00214         }
00215     }
00216 
00217     elem = config_get(c2s->config, "io.limits.connects");
00218     if(elem != NULL)
00219     {
00220         c2s->conn_rate_total = j_atoi(elem->values[0], 0);
00221         if(c2s->conn_rate_total != 0)
00222         {
00223             c2s->conn_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 5);
00224             c2s->conn_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 5);
00225         }
00226     }
00227 
00228     c2s->stanza_size_limit = j_atoi(config_get_one(c2s->config, "io.limits.stanzasize", 0), 0);
00229 
00230     /* tweak timed checks with rate times */
00231     if(c2s->io_check_interval == 0) {
00232         if(c2s->byte_rate_total != 0)
00233             c2s->io_check_interval = c2s->byte_rate_wait;
00234 
00235         if(c2s->stanza_rate_total != 0 && c2s->io_check_interval > c2s->stanza_rate_wait)
00236             c2s->io_check_interval = c2s->stanza_rate_wait;
00237     }
00238 
00239     str = config_get_one(c2s->config, "io.access.order", 0);
00240     if(str == NULL || strcmp(str, "deny,allow") != 0)
00241         c2s->access = access_new(0);
00242     else
00243         c2s->access = access_new(1);
00244 
00245     elem = config_get(c2s->config, "io.access.allow");
00246     if(elem != NULL)
00247     {
00248         for(i = 0; i < elem->nvalues; i++)
00249         {
00250             ip = j_attr((const char **) elem->attrs[i], "ip");
00251             mask = j_attr((const char **) elem->attrs[i], "mask");
00252 
00253             if(ip == NULL)
00254                 continue;
00255 
00256             if(mask == NULL)
00257                 mask = "255.255.255.255";
00258 
00259             access_allow(c2s->access, ip, mask);
00260         }
00261     }
00262 
00263     elem = config_get(c2s->config, "io.access.deny");
00264     if(elem != NULL)
00265     {
00266         for(i = 0; i < elem->nvalues; i++)
00267         {
00268             ip = j_attr((const char **) elem->attrs[i], "ip");
00269             mask = j_attr((const char **) elem->attrs[i], "mask");
00270 
00271             if(ip == NULL)
00272                 continue;
00273 
00274             if(mask == NULL)
00275                 mask = "255.255.255.255";
00276 
00277             access_deny(c2s->access, ip, mask);
00278         }
00279     }
00280 }
00281 
00282 static void _c2s_hosts_expand(c2s_t c2s)
00283 {
00284     char *realm;
00285     config_elem_t elem;
00286     char id[1024];
00287     int i;
00288 
00289     elem = config_get(c2s->config, "local.id");
00290     if(!elem) {
00291         log_write(c2s->log, LOG_NOTICE, "no local.id configured - skipping local domains configuration");
00292         return;
00293     }
00294     for(i = 0; i < elem->nvalues; i++) {
00295         host_t host = (host_t) pmalloco(xhash_pool(c2s->hosts), sizeof(struct host_st));
00296         if(!host) {
00297             log_write(c2s->log, LOG_ERR, "cannot allocate memory for new host, aborting");
00298             exit(1);
00299         }
00300 
00301         realm = j_attr((const char **) elem->attrs[i], "realm");
00302 
00303         /* stringprep ids (domain names) so that they are in canonical form */
00304         strncpy(id, elem->values[i], 1024);
00305         id[1023] = '\0';
00306         if (stringprep_nameprep(id, 1024) != 0) {
00307             log_write(c2s->log, LOG_ERR, "cannot stringprep id %s, aborting", id);
00308             exit(1);
00309         }
00310 
00311         host->realm = (realm != NULL) ? realm : pstrdup(xhash_pool(c2s->hosts), id);
00312 
00313         host->host_pemfile = j_attr((const char **) elem->attrs[i], "pemfile");
00314 
00315         host->host_cachain = j_attr((const char **) elem->attrs[i], "cachain");
00316 
00317         host->host_verify_mode = j_atoi(j_attr((const char **) elem->attrs[i], "verify-mode"), 0);
00318 
00319 #ifdef HAVE_SSL
00320         if(host->host_pemfile != NULL) {
00321             if(c2s->sx_ssl == NULL) {
00322                 c2s->sx_ssl = sx_env_plugin(c2s->sx_env, sx_ssl_init, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode);
00323                 if(c2s->sx_ssl == NULL) {
00324                     log_write(c2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm);
00325                     host->host_pemfile = NULL;
00326                 }
00327             } else {
00328                 if(sx_ssl_server_addcert(c2s->sx_ssl, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode) != 0) {
00329                     log_write(c2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm);
00330                     host->host_pemfile = NULL;
00331                 }
00332             }
00333         }
00334 #endif
00335 
00336         host->host_require_starttls = (j_attr((const char **) elem->attrs[i], "require-starttls") != NULL);
00337 
00338         host->ar_register_enable = (j_attr((const char **) elem->attrs[i], "register-enable") != NULL);
00339         host->ar_register_oob = j_attr((const char **) elem->attrs[i], "register-oob");
00340         if(host->ar_register_enable || host->ar_register_oob) {
00341             host->ar_register_instructions = j_attr((const char **) elem->attrs[i], "instructions");
00342             if(host->ar_register_instructions == NULL) {
00343                 if(host->ar_register_oob)
00344                     host->ar_register_instructions = "Only web based registration is possible with this server.";
00345                 else
00346                     host->ar_register_instructions = "Enter a username and password to register with this server.";
00347             }
00348         } else
00349             host->ar_register_password = (j_attr((const char **) elem->attrs[i], "password-change") != NULL);
00350 
00351         /* check for empty <id/> CDATA - XXX this "1" is VERY config.c dependant !!! */
00352         if(! strcmp(id, "1")) {
00353             /* remove the realm even if set */
00354             host->realm = NULL;
00355 
00356             /* skip if vHost already configured */
00357             if(! c2s->vhost)
00358                 c2s->vhost = host;
00359 
00360             /* add meaningful log "id" */
00361             strcpy(id, "default vHost");
00362         } else {
00363             /* insert into vHosts xhash */
00364             xhash_put(c2s->hosts, pstrdup(xhash_pool(c2s->hosts), id), host);
00365         }
00366 
00367         log_write(c2s->log, LOG_NOTICE, "[%s] configured; realm=%s, registration %s, using PEM:%s",
00368                   id, (host->realm != NULL ? host->realm : "no realm set"), (host->ar_register_enable ? "enabled" : "disabled"),
00369                   (host->host_pemfile ? host->host_pemfile : "Default"));
00370     }
00371 }
00372 
00373 static int _c2s_router_connect(c2s_t c2s) {
00374     log_write(c2s->log, LOG_NOTICE, "attempting connection to router at %s, port=%d", c2s->router_ip, c2s->router_port);
00375 
00376     c2s->fd = mio_connect(c2s->mio, c2s->router_port, c2s->router_ip, NULL, c2s_router_mio_callback, (void *) c2s);
00377     if(c2s->fd == NULL) {
00378         if(errno == ECONNREFUSED)
00379             c2s_lost_router = 1;
00380         log_write(c2s->log, LOG_NOTICE, "connection attempt to router failed: %s (%d)", MIO_STRERROR(MIO_ERROR), MIO_ERROR);
00381         return 1;
00382     }
00383 
00384     c2s->router = sx_new(c2s->sx_env, c2s->fd->fd, c2s_router_sx_callback, (void *) c2s);
00385     sx_client_init(c2s->router, 0, NULL, NULL, NULL, "1.0");
00386 
00387     return 0;
00388 }
00389 
00390 static int _c2s_sx_sasl_callback(int cb, void *arg, void **res, sx_t s, void *cbarg) {
00391     c2s_t c2s = (c2s_t) cbarg;
00392     char *my_realm, *mech;
00393     sx_sasl_creds_t creds;
00394     static char buf[3072];
00395     char mechbuf[256];
00396     struct jid_st jid;
00397     jid_static_buf jid_buf;
00398     int i, r;
00399 
00400     /* init static jid */
00401     jid_static(&jid,&jid_buf);
00402 
00403     switch(cb) {
00404         case sx_sasl_cb_GET_REALM:
00405 
00406             if(s->req_to == NULL)   /* this shouldn't happen */
00407                 my_realm = "";
00408 
00409             else {
00410                 host_t host;
00411                 /* get host for request */
00412                 host = xhash_get(c2s->hosts, s->req_to);
00413                 if(host == NULL) {
00414                     log_write(c2s->log, LOG_ERR, "SASL callback for non-existing host: %s", s->req_to);
00415                     *res = (void *)NULL;
00416                     return sx_sasl_ret_FAIL;
00417                 }
00418 
00419                 my_realm = host->realm;
00420                 if(my_realm == NULL)
00421                     my_realm = s->req_to;
00422             }
00423 
00424             strncpy(buf, my_realm, 256);
00425             *res = (void *)buf;
00426 
00427             log_debug(ZONE, "sx sasl callback: get realm: realm is '%s'", buf);
00428             return sx_sasl_ret_OK;
00429             break;
00430 
00431         case sx_sasl_cb_GET_PASS:
00432             creds = (sx_sasl_creds_t) arg;
00433 
00434             log_debug(ZONE, "sx sasl callback: get pass (authnid=%s, realm=%s)", creds->authnid, creds->realm);
00435 
00436             if(c2s->ar->get_password && (c2s->ar->get_password)(c2s->ar, (char *)creds->authnid, (creds->realm != NULL) ? (char *)creds->realm: "", buf) == 0) {
00437                 *res = buf;
00438                 return sx_sasl_ret_OK;
00439             }
00440 
00441             return sx_sasl_ret_FAIL;
00442 
00443         case sx_sasl_cb_CHECK_PASS:
00444             creds = (sx_sasl_creds_t) arg;
00445 
00446             log_debug(ZONE, "sx sasl callback: check pass (authnid=%s, realm=%s)", creds->authnid, creds->realm);
00447 
00448             if(c2s->ar->check_password != NULL) {
00449                 if ((c2s->ar->check_password)(c2s->ar, (char *)creds->authnid, (creds->realm != NULL) ? (char *)creds->realm : "", (char *)creds->pass) == 0)
00450                     return sx_sasl_ret_OK;
00451                 else
00452                     return sx_sasl_ret_FAIL;
00453             }
00454 
00455             if(c2s->ar->get_password != NULL) {
00456                 if ((c2s->ar->get_password)(c2s->ar, (char *)creds->authnid, (creds->realm != NULL) ? (char *)creds->realm : "", buf) != 0)
00457                     return sx_sasl_ret_FAIL;
00458 
00459                 if (strcmp(creds->pass, buf)==0)
00460                     return sx_sasl_ret_OK;
00461             }
00462 
00463             return sx_sasl_ret_FAIL;
00464             break;
00465 
00466         case sx_sasl_cb_CHECK_AUTHZID:
00467             creds = (sx_sasl_creds_t) arg;
00468 
00469             /* we need authzid to validate */
00470             if(creds->authzid == NULL || creds->authzid[0] == '\0')
00471                 return sx_sasl_ret_FAIL;
00472 
00473             /* authzid must be a valid jid */
00474             if(jid_reset(&jid, creds->authzid, -1) == NULL)
00475                 return sx_sasl_ret_FAIL;
00476 
00477             /* and have domain == stream to addr */
00478             if(!s->req_to || (strcmp(jid.domain, s->req_to) != 0))
00479                 return sx_sasl_ret_FAIL;
00480 
00481             /* and have no resource */
00482             if(jid.resource[0] != '\0')
00483                 return sx_sasl_ret_FAIL;
00484 
00485             /* and user has right to authorize as */
00486             if (c2s->ar->user_authz_allowed) {
00487                 if (c2s->ar->user_authz_allowed(c2s->ar, (char *)creds->authnid, (char *)creds->realm, (char *)creds->authzid))
00488                         return sx_sasl_ret_OK;
00489             } else {
00490                 if (strcmp(creds->authnid, jid.node) == 0 &&
00491                     (c2s->ar->user_exists)(c2s->ar, jid.node, jid.domain))
00492                     return sx_sasl_ret_OK;
00493             }
00494 
00495             return sx_sasl_ret_FAIL;
00496 
00497         case sx_sasl_cb_GEN_AUTHZID:
00498             /* generate a jid for SASL ANONYMOUS */
00499             jid_reset(&jid, s->req_to, -1);
00500 
00501             /* make node a random string */
00502             jid_random_part(&jid, jid_NODE);
00503 
00504             strcpy(buf, jid.node);
00505 
00506             *res = (void *)buf;
00507 
00508             return sx_sasl_ret_OK;
00509             break;
00510 
00511         case sx_sasl_cb_CHECK_MECH:
00512             mech = (char *)arg;
00513 
00514             i=0;
00515             while(i<sizeof(mechbuf) && mech[i]!='\0') {
00516                 mechbuf[i]=tolower(mech[i]);
00517                 i++;
00518             }
00519             mechbuf[i]='\0';
00520 
00521             /* Determine if our configuration will let us use this mechanism.
00522              * We support different mechanisms for both SSL and normal use */
00523 
00524             if (strcmp(mechbuf, "digest-md5") == 0) {
00525                 /* digest-md5 requires that our authreg support get_password */
00526                 if (c2s->ar->get_password == NULL)
00527                     return sx_sasl_ret_FAIL;
00528             } else if (strcmp(mechbuf, "plain") == 0) {
00529                 /* plain requires either get_password or check_password */
00530                 if (c2s->ar->get_password == NULL && c2s->ar->check_password == NULL)
00531                     return sx_sasl_ret_FAIL;
00532             }
00533 
00534             /* Using SSF is potentially dangerous, as SASL can also set the
00535              * SSF of the connection. However, SASL shouldn't do so until after
00536              * we've finished mechanism establishment
00537              */
00538             if (s->ssf>0) {
00539                 r = snprintf(buf, sizeof(buf), "authreg.ssl-mechanisms.sasl.%s",mechbuf);
00540                 if (r < -1 || r > sizeof(buf))
00541                     return sx_sasl_ret_FAIL;
00542                 if(config_get(c2s->config,buf) != NULL)
00543                     return sx_sasl_ret_OK;
00544             }
00545 
00546             r = snprintf(buf, sizeof(buf), "authreg.mechanisms.sasl.%s",mechbuf);
00547             if (r < -1 || r > sizeof(buf))
00548                 return sx_sasl_ret_FAIL;
00549 
00550             /* Work out if our configuration will let us use this mechanism */
00551             if(config_get(c2s->config,buf) != NULL)
00552                 return sx_sasl_ret_OK;
00553             else
00554                 return sx_sasl_ret_FAIL;
00555         default:
00556             break;
00557     }
00558 
00559     return sx_sasl_ret_FAIL;
00560 }
00561 static void _c2s_time_checks(c2s_t c2s) {
00562     sess_t sess;
00563     time_t now;
00564     union xhashv xhv;
00565 
00566     now = time(NULL);
00567 
00568     if(xhash_iter_first(c2s->sessions))
00569         do {
00570             xhv.sess_val = &sess;
00571             xhash_iter_get(c2s->sessions, NULL, NULL, xhv.val);
00572 
00573             if(c2s->io_check_idle > 0 && sess->s && now > sess->last_activity + c2s->io_check_idle) {
00574                 log_write(c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] timed out", sess->fd->fd, sess->ip, sess->port);
00575 
00576                 sx_error(sess->s, stream_err_HOST_GONE, "connection timed out");
00577                 sx_close(sess->s);
00578 
00579                 continue;
00580             }
00581 
00582             if(c2s->io_check_keepalive > 0 && now > sess->last_activity + c2s->io_check_keepalive && sess->s->state >= state_STREAM) {
00583                 log_debug(ZONE, "sending keepalive for %d", sess->fd->fd);
00584 
00585                 sx_raw_write(sess->s, " ", 1);
00586             }
00587 
00588             if(sess->rate != NULL && sess->rate->bad != 0 && rate_check(sess->rate) != 0) {
00589                 /* read the pending bytes when rate limit is no longer in effect */
00590                 log_debug(ZONE, "reading throttled %d", sess->fd->fd);
00591                 sess->s->want_read = 1;
00592                 sx_can_read(sess->s);
00593             }
00594 
00595         } while(xhash_iter_next(c2s->sessions));
00596 }
00597 
00598 JABBER_MAIN("jabberd2c2s", "Jabber 2 C2S", "Jabber Open Source Server: Client to Server", "jabberd2router\0")
00599 {
00600     c2s_t c2s;
00601     char *config_file;
00602     int optchar;
00603     int mio_timeout;
00604     sess_t sess;
00605     bres_t res;
00606     union xhashv xhv;
00607     time_t check_time = 0;
00608     const char *cli_id = 0;
00609 
00610 #ifdef HAVE_UMASK
00611     umask((mode_t) 0027);
00612 #endif
00613 
00614     srand(time(NULL));
00615 
00616 #ifdef HAVE_WINSOCK2_H
00617 /* get winsock running */
00618     {
00619         WORD wVersionRequested;
00620         WSADATA wsaData;
00621         int err;
00622 
00623         wVersionRequested = MAKEWORD( 2, 2 );
00624 
00625         err = WSAStartup( wVersionRequested, &wsaData );
00626         if ( err != 0 ) {
00627             /* !!! tell user that we couldn't find a usable winsock dll */
00628             return 0;
00629         }
00630     }
00631 #endif
00632 
00633     jabber_signal(SIGINT, _c2s_signal);
00634     jabber_signal(SIGTERM, _c2s_signal);
00635 #ifdef SIGHUP
00636     jabber_signal(SIGHUP, _c2s_signal_hup);
00637 #endif
00638 #ifdef SIGPIPE
00639     jabber_signal(SIGPIPE, SIG_IGN);
00640 #endif
00641     jabber_signal(SIGUSR1, _c2s_signal_usr1);
00642     jabber_signal(SIGUSR2, _c2s_signal_usr2);
00643 
00644 
00645     c2s = (c2s_t) calloc(1, sizeof(struct c2s_st));
00646 
00647     /* load our config */
00648     c2s->config = config_new();
00649 
00650     config_file = CONFIG_DIR "/c2s.xml";
00651 
00652     /* cmdline parsing */
00653     while((optchar = getopt(argc, argv, "Dc:hi:?")) >= 0)
00654     {
00655         switch(optchar)
00656         {
00657             case 'c':
00658                 config_file = optarg;
00659                 break;
00660             case 'D':
00661 #ifdef DEBUG
00662                 set_debug_flag(1);
00663 #else
00664                 printf("WARN: Debugging not enabled.  Ignoring -D.\n");
00665 #endif
00666                 break;
00667             case 'i':
00668                 cli_id = optarg;
00669                 break;
00670             case 'h': case '?': default:
00671                 fputs(
00672                     "c2s - jabberd client-to-server connector (" VERSION ")\n"
00673                     "Usage: c2s <options>\n"
00674                     "Options are:\n"
00675                     "   -c <config>     config file to use [default: " CONFIG_DIR "/c2s.xml]\n"
00676                     "   -i id           Override <id> config element\n"
00677 #ifdef DEBUG
00678                     "   -D              Show debug output\n"
00679 #endif
00680                     ,
00681                     stdout);
00682                 config_free(c2s->config);
00683                 free(c2s);
00684                 return 1;
00685         }
00686     }
00687 
00688     if(config_load_with_id(c2s->config, config_file, cli_id) != 0)
00689     {
00690         fputs("c2s: couldn't load config, aborting\n", stderr);
00691         config_free(c2s->config);
00692         free(c2s);
00693         return 2;
00694     }
00695 
00696     c2s->stream_redirects = xhash_new(523);
00697 
00698     _c2s_config_expand(c2s);
00699 
00700     c2s->log = log_new(c2s->log_type, c2s->log_ident, c2s->log_facility);
00701     log_write(c2s->log, LOG_NOTICE, "starting up");
00702 
00703     _c2s_pidfile(c2s);
00704 
00705     if(c2s->ar_module_name == NULL) {
00706         log_write(c2s->log, LOG_NOTICE, "no authreg module specified in config file");
00707     }
00708     else if((c2s->ar = authreg_init(c2s, c2s->ar_module_name)) == NULL) {
00709         access_free(c2s->access);
00710         config_free(c2s->config);
00711         log_free(c2s->log);
00712         free(c2s);
00713         exit(1);
00714     }
00715 
00716     c2s->sessions = xhash_new(1023);
00717 
00718     c2s->conn_rates = xhash_new(101);
00719 
00720     c2s->dead = jqueue_new();
00721 
00722     c2s->dead_sess = jqueue_new();
00723 
00724     c2s->sx_env = sx_env_new();
00725 
00726 #ifdef HAVE_SSL
00727     /* get the ssl context up and running */
00728     if(c2s->local_pemfile != NULL) {
00729         c2s->sx_ssl = sx_env_plugin(c2s->sx_env, sx_ssl_init, NULL, c2s->local_pemfile, c2s->local_cachain, c2s->local_verify_mode);
00730         if(c2s->sx_ssl == NULL) {
00731             log_write(c2s->log, LOG_ERR, "failed to load local SSL pemfile, SSL will not be available to clients");
00732             c2s->local_pemfile = NULL;
00733         }
00734     }
00735 
00736     /* try and get something online, so at least we can encrypt to the router */
00737     if(c2s->sx_ssl == NULL && c2s->router_pemfile != NULL) {
00738         c2s->sx_ssl = sx_env_plugin(c2s->sx_env, sx_ssl_init, NULL, c2s->router_pemfile, NULL, NULL);
00739         if(c2s->sx_ssl == NULL) {
00740             log_write(c2s->log, LOG_ERR, "failed to load router SSL pemfile, channel to router will not be SSL encrypted");
00741             c2s->router_pemfile = NULL;
00742         }
00743     }
00744 #endif
00745 
00746 #ifdef HAVE_LIBZ
00747     /* get compression up and running */
00748     if(c2s->compression)
00749         sx_env_plugin(c2s->sx_env, sx_compress_init);
00750 #endif
00751 
00752 #ifdef ENABLE_EXPERIMENTAL
00753     /* get stanza ack up */
00754     sx_env_plugin(c2s->sx_env, sx_ack_init);
00755 
00756     /* and user IP address plugin */
00757     sx_env_plugin(c2s->sx_env, sx_address_init);
00758 #endif
00759 
00760     /* get sasl online */
00761     c2s->sx_sasl = sx_env_plugin(c2s->sx_env, sx_sasl_init, "xmpp", _c2s_sx_sasl_callback, (void *) c2s);
00762     if(c2s->sx_sasl == NULL) {
00763         log_write(c2s->log, LOG_ERR, "failed to initialise SASL context, aborting");
00764         exit(1);
00765     }
00766 
00767     /* get bind up */
00768     sx_env_plugin(c2s->sx_env, bind_init, c2s);
00769 
00770     c2s->mio = mio_new(c2s->io_max_fds);
00771     if(c2s->mio == NULL) {
00772         log_write(c2s->log, LOG_ERR, "failed to create MIO, aborting");
00773         exit(1);
00774     }
00775 
00776     /* hosts mapping */
00777     c2s->hosts = xhash_new(1021);
00778     _c2s_hosts_expand(c2s);
00779     c2s->sm_avail = xhash_new(1021);
00780 
00781     c2s->retry_left = c2s->retry_init;
00782     _c2s_router_connect(c2s);
00783 
00784     mio_timeout = ((c2s->io_check_interval != 0 && c2s->io_check_interval < 5) ?
00785         c2s->io_check_interval : 5);
00786 
00787     while(!c2s_shutdown) {
00788         mio_run(c2s->mio, mio_timeout);
00789 
00790         if(c2s_logrotate) {
00791             set_debug_log_from_config(c2s->config);
00792 
00793             log_write(c2s->log, LOG_NOTICE, "reopening log ...");
00794             log_free(c2s->log);
00795             c2s->log = log_new(c2s->log_type, c2s->log_ident, c2s->log_facility);
00796             log_write(c2s->log, LOG_NOTICE, "log started");
00797 
00798             c2s_logrotate = 0;
00799         }
00800 
00801         if(c2s_sighup) {
00802             log_write(c2s->log, LOG_NOTICE, "reloading some configuration items ...");
00803             config_t conf;
00804             conf = config_new();
00805             if (conf && config_load(conf, config_file) == 0) {
00806                 xhash_free(c2s->stream_redirects);
00807                 c2s->stream_redirects = xhash_new(523);
00808 
00809                 char *req_domain, *to_address, *to_port;
00810                 config_elem_t elem;
00811                 int i;
00812                 stream_redirect_t sr;
00813 
00814                 elem = config_get(conf, "stream_redirect.redirect");
00815                 if(elem != NULL)
00816                 {
00817                     for(i = 0; i < elem->nvalues; i++)
00818                     {
00819                         sr = (stream_redirect_t) pmalloco(xhash_pool(c2s->stream_redirects), sizeof(struct stream_redirect_st));
00820                         if(!sr) {
00821                             log_write(c2s->log, LOG_ERR, "cannot allocate memory for new stream redirection record, aborting");
00822                             exit(1);
00823                         }
00824                         req_domain = j_attr((const char **) elem->attrs[i], "requested_domain");
00825                         to_address = j_attr((const char **) elem->attrs[i], "to_address");
00826                         to_port = j_attr((const char **) elem->attrs[i], "to_port");
00827 
00828                         if(req_domain == NULL || to_address == NULL || to_port == NULL) {
00829                             log_write(c2s->log, LOG_ERR, "Error reading a stream_redirect.redirect element from file, skipping");
00830                             continue;
00831                         }
00832 
00833                         // Note that to_address should be RFC 3986 compliant
00834                         sr->to_address = to_address;
00835                         sr->to_port = to_port;
00836                         
00837                         xhash_put(c2s->stream_redirects, pstrdup(xhash_pool(c2s->stream_redirects), req_domain), sr);
00838                     }
00839                 }
00840                 config_free(conf);
00841             } else {
00842                 log_write(c2s->log, LOG_WARNING, "couldn't reload config (%s)", config_file);
00843                 if (conf) config_free(conf);
00844             }
00845             c2s_sighup = 0;
00846         }
00847 
00848         if(c2s_lost_router) {
00849             if(c2s->retry_left < 0) {
00850                 log_write(c2s->log, LOG_NOTICE, "attempting reconnect");
00851                 sleep(c2s->retry_sleep);
00852                 c2s_lost_router = 0;
00853                 if (c2s->router) sx_free(c2s->router);
00854                 _c2s_router_connect(c2s);
00855             }
00856 
00857             else if(c2s->retry_left == 0) {
00858                 c2s_shutdown = 1;
00859             }
00860 
00861             else {
00862                 log_write(c2s->log, LOG_NOTICE, "attempting reconnect (%d left)", c2s->retry_left);
00863                 c2s->retry_left--;
00864                 sleep(c2s->retry_sleep);
00865                 c2s_lost_router = 0;
00866                 if (c2s->router) sx_free(c2s->router);
00867                 _c2s_router_connect(c2s);
00868             }
00869         }
00870 
00871         /* cleanup dead sess (before sx_t as sess->result uses sx_t nad cache) */
00872         while(jqueue_size(c2s->dead_sess) > 0) {
00873             sess = (sess_t) jqueue_pull(c2s->dead_sess);
00874 
00875             /* free sess data */
00876             if(sess->ip != NULL) free(sess->ip);
00877             if(sess->smcomp != NULL) free(sess->smcomp);
00878             if(sess->result != NULL) nad_free(sess->result);
00879             if(sess->resources != NULL)
00880                 for(res = sess->resources; res != NULL;) {
00881                     bres_t tmp = res->next;
00882                     jid_free(res->jid);
00883                     free(res);
00884                     res = tmp;
00885                 }
00886             if(sess->rate != NULL) rate_free(sess->rate);
00887             if(sess->stanza_rate != NULL) rate_free(sess->stanza_rate);
00888 
00889             free(sess);
00890         }
00891 
00892         /* cleanup dead sx_ts */
00893         while(jqueue_size(c2s->dead) > 0)
00894             sx_free((sx_t) jqueue_pull(c2s->dead));
00895 
00896         /* time checks */
00897         if(c2s->io_check_interval > 0 && time(NULL) >= c2s->next_check) {
00898             log_debug(ZONE, "running time checks");
00899 
00900             _c2s_time_checks(c2s);
00901 
00902             c2s->next_check = time(NULL) + c2s->io_check_interval;
00903             log_debug(ZONE, "next time check at %d", c2s->next_check);
00904         }
00905 
00906         if(time(NULL) > check_time + 60) {
00907 #ifdef POOL_DEBUG
00908             pool_stat(1);
00909 #endif
00910             if(c2s->packet_stats != NULL) {
00911                 int fd = open(c2s->packet_stats, O_TRUNC | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP);
00912                 if (fd >= 0) {
00913                     char buf[100];
00914                     int len = snprintf(buf, 100, "%lld\n", c2s->packet_count);
00915                     if (write(fd, buf, len) != len) {
00916                         close(fd);
00917                         fd = -1;
00918                     } else close(fd);
00919                 }
00920                 if (fd < 0) {
00921                     log_write(c2s->log, LOG_ERR, "failed to write packet statistics to: %s", c2s->packet_stats);
00922                     c2s_shutdown = 1;
00923                 }
00924             }
00925 
00926             check_time = time(NULL);
00927         }
00928     }
00929 
00930     log_write(c2s->log, LOG_NOTICE, "shutting down");
00931 
00932     if(xhash_iter_first(c2s->sessions))
00933         do {
00934             xhv.sess_val = &sess;
00935             xhash_iter_get(c2s->sessions, NULL, NULL, xhv.val);
00936 
00937             if(sess->active && sess->s)
00938                 sx_close(sess->s);
00939 
00940         } while(xhash_iter_next(c2s->sessions));
00941 
00942     /* cleanup dead sess */
00943     while(jqueue_size(c2s->dead_sess) > 0) {
00944         sess = (sess_t) jqueue_pull(c2s->dead_sess);
00945 
00946         /* free sess data */
00947         if(sess->ip != NULL) free(sess->ip);
00948         if(sess->result != NULL) nad_free(sess->result);
00949         if(sess->resources != NULL)
00950             for(res = sess->resources; res != NULL;) {
00951                 bres_t tmp = res->next;
00952                 jid_free(res->jid);
00953                 free(res);
00954                 res = tmp;
00955             }
00956 
00957         free(sess);
00958     }
00959 
00960     while(jqueue_size(c2s->dead) > 0)
00961         sx_free((sx_t) jqueue_pull(c2s->dead));
00962 
00963     if (c2s->fd != NULL) mio_close(c2s->mio, c2s->fd);
00964     sx_free(c2s->router);
00965 
00966     sx_env_free(c2s->sx_env);
00967 
00968     mio_free(c2s->mio);
00969 
00970     xhash_free(c2s->sessions);
00971 
00972     authreg_free(c2s->ar);
00973 
00974     xhash_free(c2s->conn_rates);
00975 
00976     xhash_free(c2s->stream_redirects);
00977 
00978     xhash_free(c2s->sm_avail);
00979 
00980     xhash_free(c2s->hosts);
00981 
00982     jqueue_free(c2s->dead);
00983 
00984     jqueue_free(c2s->dead_sess);
00985 
00986     access_free(c2s->access);
00987 
00988     log_free(c2s->log);
00989 
00990     config_free(c2s->config);
00991 
00992     free(c2s);
00993 
00994 #ifdef POOL_DEBUG
00995     pool_stat(1);
00996 #endif
00997 
00998 #ifdef HAVE_WINSOCK2_H
00999     WSACleanup();
01000 #endif
01001 
01002     return 0;
01003 }