main.c.patch   [plain text]


--- /tmp/jabberd-2.2.13/c2s/main.c	2011-02-23 08:24:34.000000000 -0800
+++ ./jabberd2/c2s/main.c	2011-05-26 13:21:43.000000000 -0700
@@ -25,6 +25,7 @@
 static sig_atomic_t c2s_shutdown = 0;
 sig_atomic_t c2s_lost_router = 0;
 static sig_atomic_t c2s_logrotate = 0;
+static sig_atomic_t c2s_sighup = 0;
 
 static void _c2s_signal(int signum)
 {
@@ -35,6 +36,7 @@ static void _c2s_signal(int signum)
 static void _c2s_signal_hup(int signum)
 {
     c2s_logrotate = 1;
+    c2s_sighup = 1;
 }
 
 /** store the process id */
@@ -42,6 +44,10 @@ static void _c2s_pidfile(c2s_t c2s) {
     char *pidfile;
     FILE *f;
     pid_t pid;
+    char piddir[PATH_MAX] = "";
+    struct stat statbuf;
+    int i, last;
+    int i_slash = 0;
 
     pidfile = config_get_one(c2s->config, "pidfile", 0);
     if(pidfile == NULL)
@@ -49,6 +55,39 @@ static void _c2s_pidfile(c2s_t c2s) {
 
     pid = getpid();
 
+    // Get the pid directory from the full file path
+    for (i = 0; pidfile[i] != '\0'; i++) {
+        if (pidfile[i] == '/')
+            i_slash = i;
+    }
+    do { // not a loop
+        if (i_slash == 0) {
+            // no directory provided in pidfile preference, or only one slash found in path... skip creation attempt
+            break;
+        } else {
+            last = i_slash+1;
+        }
+        if (i_slash > sizeof(piddir)) {
+            log_write(c2s->log, LOG_ERR, "specified PID path exceeds the maximum allowed length");
+            return;
+        }
+        strlcpy(piddir, pidfile, last);
+
+        // Create the pid directory if it does not exist (don't attempt to create intermediate directories)
+        if (stat(piddir, &statbuf)) {
+            log_debug(ZONE, "pid directory appears to not exist, trying to create it...");
+            if (mkdir(piddir, 0755)) {
+                if ((errno == EEXIST) && (! stat(piddir, &statbuf))) {
+                    log_debug(ZONE, "working around probable race condition, pid directory now exists");
+                    break;
+                }
+                log_write(c2s->log, LOG_ERR, "couldn't create pid directory %s: %s", piddir, strerror(errno));
+                return;
+            }
+            log_debug(ZONE, "created pid directory: %s", piddir);
+        }
+    } while(0); // not a loop
+
     if((f = fopen(pidfile, "w+")) == NULL) {
         log_write(c2s->log, LOG_ERR, "couldn't open %s for writing: %s", pidfile, strerror(errno));
         return;
@@ -68,8 +107,10 @@ static void _c2s_pidfile(c2s_t c2s) {
 static void _c2s_config_expand(c2s_t c2s)
 {
     char *str, *ip, *mask;
+    char *req_domain, *to_address, *to_port;
     config_elem_t elem;
     int i;
+    stream_redirect_t sr;
 
     c2s->id = config_get_one(c2s->config, "id", 0);
     if(c2s->id == NULL)
@@ -90,6 +131,10 @@ static void _c2s_config_expand(c2s_t c2s
 
     c2s->router_pemfile = config_get_one(c2s->config, "router.pemfile", 0);
 
+    c2s->router_cachain = config_get_one(c2s->config, "router.cachain", 0);
+
+    c2s->router_private_key_password = config_get_one(c2s->config, "router.private_key_password", 0);
+
     c2s->retry_init = j_atoi(config_get_one(c2s->config, "router.retry.init", 0), 3);
     c2s->retry_lost = j_atoi(config_get_one(c2s->config, "router.retry.lost", 0), 3);
     if((c2s->retry_sleep = j_atoi(config_get_one(c2s->config, "router.retry.sleep", 0), 2)) < 1)
@@ -125,6 +170,8 @@ static void _c2s_config_expand(c2s_t c2s
 
     c2s->local_cachain = config_get_one(c2s->config, "local.cachain", 0);
 
+    c2s->local_private_key_password = config_get_one(c2s->config, "local.private_key_password", 0);
+
     c2s->local_verify_mode = j_atoi(config_get_one(c2s->config, "local.verify-mode", 0), 0);
 
     c2s->local_ssl_port = j_atoi(config_get_one(c2s->config, "local.ssl-port", 0), 0);
@@ -141,13 +188,44 @@ static void _c2s_config_expand(c2s_t c2s
 
     c2s->pbx_pipe = config_get_one(c2s->config, "pbx.pipe", 0);
 
+    elem = config_get(c2s->config, "stream_redirect.redirect");
+    if(elem != NULL)
+    {
+        for(i = 0; i < elem->nvalues; i++)
+        {
+            sr = (stream_redirect_t) pmalloco(xhash_pool(c2s->stream_redirects), sizeof(struct stream_redirect_st));
+            if(!sr) {
+                log_write(c2s->log, LOG_ERR, "cannot allocate memory for new stream redirection record, aborting");
+                exit(1);
+            }
+            req_domain = j_attr((const char **) elem->attrs[i], "requested_domain");
+            to_address = j_attr((const char **) elem->attrs[i], "to_address");
+            to_port = j_attr((const char **) elem->attrs[i], "to_port");
+
+            if(req_domain == NULL || to_address == NULL || to_port == NULL) {
+                log_write(c2s->log, LOG_ERR, "Error reading a stream_redirect.redirect element from file, skipping");
+                continue;
+            }
+
+            // Note that to_address should be RFC 3986 compliant
+            sr->to_address = to_address;
+            sr->to_port = to_port;
+            
+            xhash_put(c2s->stream_redirects, pstrdup(xhash_pool(c2s->stream_redirects), req_domain), sr);
+        }
+    }
+
     c2s->ar_module_name = config_get_one(c2s->config, "authreg.module", 0);
 
     if(config_get(c2s->config, "authreg.mechanisms.traditional.plain") != NULL) c2s->ar_mechanisms |= AR_MECH_TRAD_PLAIN;
     if(config_get(c2s->config, "authreg.mechanisms.traditional.digest") != NULL) c2s->ar_mechanisms |= AR_MECH_TRAD_DIGEST;
+    if(config_get(c2s->config, "authreg.mechanisms.traditional.cram-md5") != NULL) c2s->ar_mechanisms |= AR_MECH_TRAD_CRAMMD5;
 
     if(config_get(c2s->config, "authreg.ssl-mechanisms.traditional.plain") != NULL) c2s->ar_ssl_mechanisms |= AR_MECH_TRAD_PLAIN;
     if(config_get(c2s->config, "authreg.ssl-mechanisms.traditional.digest") != NULL) c2s->ar_ssl_mechanisms |= AR_MECH_TRAD_DIGEST;
+    if(config_get(c2s->config, "authreg.ssl-mechanisms.traditional.cram-md5") != NULL) c2s->ar_ssl_mechanisms |= AR_MECH_TRAD_CRAMMD5;
+
+    c2s->ar_authorization_sacl_name = config_get_one(c2s->config, "authreg.authorization_sacl", 0);
 
     elem = config_get(c2s->config, "io.limits.bytes");
     if(elem != NULL)
@@ -273,16 +351,18 @@ static void _c2s_hosts_expand(c2s_t c2s)
 
         host->host_verify_mode = j_atoi(j_attr((const char **) elem->attrs[i], "verify-mode"), 0);
 
+        host->host_private_key_password = j_attr((const char **) elem->attrs[i], "private-key-password");
+
 #ifdef HAVE_SSL
         if(host->host_pemfile != NULL) {
             if(c2s->sx_ssl == NULL) {
-                c2s->sx_ssl = sx_env_plugin(c2s->sx_env, sx_ssl_init, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode);
+                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);
                 if(c2s->sx_ssl == NULL) {
                     log_write(c2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm);
                     host->host_pemfile = NULL;
                 }
             } else {
-                if(sx_ssl_server_addcert(c2s->sx_ssl, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode) != 0) {
+                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) != 0) {
                     log_write(c2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm);
                     host->host_pemfile = NULL;
                 }
@@ -477,15 +557,16 @@ static int _c2s_sx_sasl_callback(int cb,
             /* Determine if our configuration will let us use this mechanism.
              * We support different mechanisms for both SSL and normal use */
 
-            if (strcmp(mechbuf, "digest-md5") == 0) {
+            // Apple OD auth does not require get_password or check_password
+            //if (strcmp(mechbuf, "digest-md5") == 0) {
                 /* digest-md5 requires that our authreg support get_password */
-                if (c2s->ar->get_password == NULL)
-                    return sx_sasl_ret_FAIL;
-            } else if (strcmp(mechbuf, "plain") == 0) {
+            //    if (c2s->ar->get_password == NULL)
+            //        return sx_sasl_ret_FAIL;
+            //} else if (strcmp(mechbuf, "plain") == 0) {
                 /* plain requires either get_password or check_password */
-                if (c2s->ar->get_password == NULL && c2s->ar->check_password == NULL)
-                    return sx_sasl_ret_FAIL;
-            }
+            //    if (c2s->ar->get_password == NULL && c2s->ar->check_password == NULL)
+            //        return sx_sasl_ret_FAIL;
+            //}
 
             /* Using SSF is potentially dangerous, as SASL can also set the
              * SSF of the connection. However, SASL shouldn't do so until after
@@ -641,6 +722,8 @@ JABBER_MAIN("jabberd2c2s", "Jabber 2 C2S
         return 2;
     }
 
+    c2s->stream_redirects = xhash_new(523);
+
     _c2s_config_expand(c2s);
 
     c2s->log = log_new(c2s->log_type, c2s->log_ident, c2s->log_facility);
@@ -672,7 +755,7 @@ JABBER_MAIN("jabberd2c2s", "Jabber 2 C2S
 #ifdef HAVE_SSL
     /* get the ssl context up and running */
     if(c2s->local_pemfile != NULL) {
-        c2s->sx_ssl = sx_env_plugin(c2s->sx_env, sx_ssl_init, NULL, c2s->local_pemfile, c2s->local_cachain, c2s->local_verify_mode);
+        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);
         if(c2s->sx_ssl == NULL) {
             log_write(c2s->log, LOG_ERR, "failed to load local SSL pemfile, SSL will not be available to clients");
             c2s->local_pemfile = NULL;
@@ -681,7 +764,7 @@ JABBER_MAIN("jabberd2c2s", "Jabber 2 C2S
 
     /* try and get something online, so at least we can encrypt to the router */
     if(c2s->sx_ssl == NULL && c2s->router_pemfile != NULL) {
-        c2s->sx_ssl = sx_env_plugin(c2s->sx_env, sx_ssl_init, NULL, c2s->router_pemfile, NULL, NULL);
+        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);
         if(c2s->sx_ssl == NULL) {
             log_write(c2s->log, LOG_ERR, "failed to load router SSL pemfile, channel to router will not be SSL encrypted");
             c2s->router_pemfile = NULL;
@@ -742,6 +825,53 @@ JABBER_MAIN("jabberd2c2s", "Jabber 2 C2S
             c2s_logrotate = 0;
         }
 
+        if(c2s_sighup) {
+            log_write(c2s->log, LOG_NOTICE, "reloading some configuration items ...");
+            config_t conf;
+            conf = config_new();
+            if (conf && config_load(conf, config_file) == 0) {
+                xhash_free(c2s->stream_redirects);
+                c2s->stream_redirects = xhash_new(523);
+
+                char *req_domain, *to_address, *to_port;
+                config_elem_t elem;
+                int i;
+                stream_redirect_t sr;
+
+                elem = config_get(conf, "stream_redirect.redirect");
+                if(elem != NULL)
+                {
+                    for(i = 0; i < elem->nvalues; i++)
+                    {
+                        sr = (stream_redirect_t) pmalloco(xhash_pool(c2s->stream_redirects), sizeof(struct stream_redirect_st));
+                        if(!sr) {
+                            log_write(c2s->log, LOG_ERR, "cannot allocate memory for new stream redirection record, aborting");
+                            exit(1);
+                        }
+                        req_domain = j_attr((const char **) elem->attrs[i], "requested_domain");
+                        to_address = j_attr((const char **) elem->attrs[i], "to_address");
+                        to_port = j_attr((const char **) elem->attrs[i], "to_port");
+
+                        if(req_domain == NULL || to_address == NULL || to_port == NULL) {
+                            log_write(c2s->log, LOG_ERR, "Error reading a stream_redirect.redirect element from file, skipping");
+                            continue;
+                        }
+
+                        // Note that to_address should be RFC 3986 compliant
+                        sr->to_address = to_address;
+                        sr->to_port = to_port;
+                        
+                        xhash_put(c2s->stream_redirects, pstrdup(xhash_pool(c2s->stream_redirects), req_domain), sr);
+                    }
+                }
+                config_free(conf);
+            } else {
+                log_write(c2s->log, LOG_WARNING, "couldn't reload config (%s)", config_file);
+                if (conf) config_free(conf);
+            }
+            c2s_sighup = 0;
+        }
+
         if(c2s_lost_router) {
             if(c2s->retry_left < 0) {
                 log_write(c2s->log, LOG_NOTICE, "attempting reconnect");
@@ -870,6 +1000,8 @@ JABBER_MAIN("jabberd2c2s", "Jabber 2 C2S
 
     xhash_free(c2s->conn_rates);
 
+    xhash_free(c2s->stream_redirects);
+
     xhash_free(c2s->sm_avail);
 
     xhash_free(c2s->hosts);