jabberd2
2.2.16
|
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 }