static void _sm_hosts_expand(sm_t sm) { config_elem_t elem; char id[1024]; int i; elem = config_get(sm->config, "local.id"); if(!elem) { /* use SM id */ xhash_put(sm->hosts, pstrdup(xhash_pool(sm->hosts), sm->id), sm); log_write(sm->log, LOG_NOTICE, "id: %s", sm->id); return; } for(i = 0; i < elem->nvalues; i++) { /* stringprep ids (domain names) so that they are in canonical form */ strncpy(id, elem->values[i], 1024); id[1023] = '\0'; if (stringprep_nameprep(id, 1024) != 0) { log_write(sm->log, LOG_ERR, "cannot stringprep id %s, aborting", id); exit(1); } /* insert into vHosts xhash */ xhash_put(sm->hosts, pstrdup(xhash_pool(sm->hosts), id), sm); log_write(sm->log, LOG_NOTICE, "[%s] configured", id); } }
static void _s2s_hosts_expand(s2s_t s2s) { char *realm; config_elem_t elem; char id[1024]; int i; elem = config_get(s2s->config, "local.id"); if (elem) for(i = 0; i < elem->nvalues; i++) { host_t host = (host_t) pmalloco(xhash_pool(s2s->hosts), sizeof(struct host_st)); if(!host) { log_write(s2s->log, LOG_ERR, "cannot allocate memory for new host, aborting"); exit(1); } realm = j_attr((const char **) elem->attrs[i], "realm"); /* stringprep ids (domain names) so that they are in canonical form */ strncpy(id, elem->values[i], 1024); id[1023] = '\0'; if (stringprep_nameprep(id, 1024) != 0) { log_write(s2s->log, LOG_ERR, "cannot stringprep id %s, aborting", id); exit(1); } host->realm = (realm != NULL) ? realm : pstrdup(xhash_pool(s2s->hosts), id); host->host_pemfile = j_attr((const char **) elem->attrs[i], "pemfile"); host->host_cachain = j_attr((const char **) elem->attrs[i], "cachain"); host->host_verify_mode = j_atoi(j_attr((const char **) elem->attrs[i], "verify-mode"), 0); #ifdef HAVE_SSL if(host->host_pemfile != NULL) { if(s2s->sx_ssl == NULL) { s2s->sx_ssl = sx_env_plugin(s2s->sx_env, sx_ssl_init, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode); if(s2s->sx_ssl == NULL) { log_write(s2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm); host->host_pemfile = NULL; } } else { if(sx_ssl_server_addcert(s2s->sx_ssl, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode) != 0) { log_write(s2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm); host->host_pemfile = NULL; } } } #endif /* insert into vHosts xhash */ xhash_put(s2s->hosts, pstrdup(xhash_pool(s2s->hosts), id), host); log_write(s2s->log, LOG_NOTICE, "[%s] configured; realm=%s", id, host->realm); } }
/** do stringprep on the pieces */ static int jid_prep_pieces(char *node, char *domain, char *resource) { if(node[0] != '\0') if(stringprep_xmpp_nodeprep(node, 1024) != 0) return 1; if(stringprep_nameprep(domain, 1024) != 0) return 1; if(resource[0] != '\0') if(stringprep_xmpp_resourceprep(resource, 1024) != 0) return 1; return 0; }
/** * idna_to_ascii_4i * @in: input array with unicode code points. * @inlen: length of input array with unicode code points. * @out: output zero terminated string that must have room for at * least 63 characters plus the terminating zero. * @flags: IDNA flags, e.g. IDNA_ALLOW_UNASSIGNED or IDNA_USE_STD3_ASCII_RULES. * * The ToASCII operation takes a sequence of Unicode code points that make * up one label and transforms it into a sequence of code points in the * ASCII range (0..7F). If ToASCII succeeds, the original sequence and the * resulting sequence are equivalent labels. * * It is important to note that the ToASCII operation can fail. ToASCII * fails if any step of it fails. If any step of the ToASCII operation * fails on any label in a domain name, that domain name MUST NOT be used * as an internationalized domain name. The method for deadling with this * failure is application-specific. * * The inputs to ToASCII are a sequence of code points, the AllowUnassigned * flag, and the UseSTD3ASCIIRules flag. The output of ToASCII is either a * sequence of ASCII code points or a failure condition. * * ToASCII never alters a sequence of code points that are all in the ASCII * range to begin with (although it could fail). Applying the ToASCII * operation multiple times has exactly the same effect as applying it just * once. * * Return value: Returns 0 on success, or an error code. */ int idna_to_ascii_4i (const uint32_t * in, size_t inlen, char *out, int flags) { size_t len, outlen; uint32_t *src; /* XXX don't need to copy data? */ int rc; /* * ToASCII consists of the following steps: * * 1. If all code points in the sequence are in the ASCII range (0..7F) * then skip to step 3. */ { size_t i; int inasciirange; inasciirange = 1; for (i = 0; i < inlen; i++) if (in[i] > 0x7F) inasciirange = 0; if (inasciirange) { src = malloc (sizeof (in[0]) * (inlen + 1)); if (src == NULL) return IDNA_MALLOC_ERROR; memcpy (src, in, sizeof (in[0]) * inlen); src[inlen] = 0; goto step3; } } /* * 2. Perform the steps specified in [NAMEPREP] and fail if there is * an error. The AllowUnassigned flag is used in [NAMEPREP]. */ { char *p; p = stringprep_ucs4_to_utf8 (in, inlen, NULL, NULL); if (p == NULL) return IDNA_MALLOC_ERROR; len = strlen (p); do { char *newp; len = 2 * len + 10; /* XXX better guess? */ newp = realloc (p, len); if (newp == NULL) { free (p); return IDNA_MALLOC_ERROR; } p = newp; if (flags & IDNA_ALLOW_UNASSIGNED) rc = stringprep_nameprep (p, len); else rc = stringprep_nameprep_no_unassigned (p, len); } while (rc == STRINGPREP_TOO_SMALL_BUFFER); if (rc != STRINGPREP_OK) { free (p); return IDNA_STRINGPREP_ERROR; } src = stringprep_utf8_to_ucs4 (p, -1, NULL); free (p); } step3: /* * 3. If the UseSTD3ASCIIRules flag is set, then perform these checks: * * (a) Verify the absence of non-LDH ASCII code points; that is, * the absence of 0..2C, 2E..2F, 3A..40, 5B..60, and 7B..7F. * * (b) Verify the absence of leading and trailing hyphen-minus; * that is, the absence of U+002D at the beginning and end of * the sequence. */ if (flags & IDNA_USE_STD3_ASCII_RULES) { size_t i; for (i = 0; src[i]; i++) if (src[i] <= 0x2C || src[i] == 0x2E || src[i] == 0x2F || (src[i] >= 0x3A && src[i] <= 0x40) || (src[i] >= 0x5B && src[i] <= 0x60) || (src[i] >= 0x7B && src[i] <= 0x7F)) { free (src); return IDNA_CONTAINS_NON_LDH; } if (src[0] == 0x002D || (i > 0 && src[i - 1] == 0x002D)) { free (src); return IDNA_CONTAINS_MINUS; } } /* * 4. If all code points in the sequence are in the ASCII range * (0..7F), then skip to step 8. */ { size_t i; int inasciirange; inasciirange = 1; for (i = 0; src[i]; i++) { if (src[i] > 0x7F) inasciirange = 0; /* copy string to output buffer if we are about to skip to step8 */ if (i < 64) out[i] = src[i]; } if (i < 64) out[i] = '\0'; if (inasciirange) goto step8; } /* * 5. Verify that the sequence does NOT begin with the ACE prefix. * */ { size_t i; int match; match = 1; for (i = 0; match && i < strlen (IDNA_ACE_PREFIX); i++) if (((uint32_t) IDNA_ACE_PREFIX[i] & 0xFF) != src[i]) match = 0; if (match) { free (src); return IDNA_CONTAINS_ACE_PREFIX; } } /* * 6. Encode the sequence using the encoding algorithm in [PUNYCODE] * and fail if there is an error. */ for (len = 0; src[len]; len++) ; src[len] = '\0'; outlen = 63 - strlen (IDNA_ACE_PREFIX); rc = punycode_encode (len, src, NULL, &outlen, &out[strlen (IDNA_ACE_PREFIX)]); if (rc != PUNYCODE_SUCCESS) { free (src); return IDNA_PUNYCODE_ERROR; } out[strlen (IDNA_ACE_PREFIX) + outlen] = '\0'; /* * 7. Prepend the ACE prefix. */ memcpy (out, IDNA_ACE_PREFIX, strlen (IDNA_ACE_PREFIX)); /* * 8. Verify that the number of code points is in the range 1 to 63 * inclusive (0 is excluded). */ step8: free (src); if (strlen (out) < 1 || strlen (out) > 63) return IDNA_INVALID_LENGTH; return IDNA_SUCCESS; }
/* ToUnicode(). May realloc() utf8in. */ static int idna_to_unicode_internal (char *utf8in, uint32_t * out, size_t * outlen, int flags) { int rc; char tmpout[64]; size_t utf8len = strlen (utf8in) + 1; size_t addlen = 0; /* * ToUnicode consists of the following steps: * * 1. If the sequence contains any code points outside the ASCII range * (0..7F) then proceed to step 2, otherwise skip to step 3. */ { size_t i; int inasciirange; inasciirange = 1; for (i = 0; utf8in[i]; i++) if (utf8in[i] & ~0x7F) inasciirange = 0; if (inasciirange) goto step3; } /* * 2. Perform the steps specified in [NAMEPREP] and fail if there is an * error. (If step 3 of ToASCII is also performed here, it will not * affect the overall behavior of ToUnicode, but it is not * necessary.) The AllowUnassigned flag is used in [NAMEPREP]. */ do { char *newp = realloc (utf8in, utf8len + addlen); if (newp == NULL) { free (utf8in); return IDNA_MALLOC_ERROR; } utf8in = newp; if (flags & IDNA_ALLOW_UNASSIGNED) rc = stringprep_nameprep (utf8in, utf8len + addlen); else rc = stringprep_nameprep_no_unassigned (utf8in, utf8len + addlen); addlen += 1; } while (rc == STRINGPREP_TOO_SMALL_BUFFER); if (rc != STRINGPREP_OK) { free (utf8in); return IDNA_STRINGPREP_ERROR; } /* 3. Verify that the sequence begins with the ACE prefix, and save a * copy of the sequence. */ step3: if (memcmp (IDNA_ACE_PREFIX, utf8in, strlen (IDNA_ACE_PREFIX)) != 0) { free (utf8in); return IDNA_NO_ACE_PREFIX; } /* 4. Remove the ACE prefix. */ memmove (utf8in, &utf8in[strlen (IDNA_ACE_PREFIX)], strlen (utf8in) - strlen (IDNA_ACE_PREFIX) + 1); /* 5. Decode the sequence using the decoding algorithm in [PUNYCODE] * and fail if there is an error. Save a copy of the result of * this step. */ (*outlen)--; /* reserve one for the zero */ rc = punycode_decode (strlen (utf8in), utf8in, outlen, out, NULL); if (rc != PUNYCODE_SUCCESS) { free (utf8in); return IDNA_PUNYCODE_ERROR; } out[*outlen] = 0; /* add zero */ /* 6. Apply ToASCII. */ rc = idna_to_ascii_4i (out, *outlen, tmpout, flags); if (rc != IDNA_SUCCESS) { free (utf8in); return rc; } /* 7. Verify that the result of step 6 matches the saved copy from * step 3, using a case-insensitive ASCII comparison. */ if (strcasecmp (utf8in, tmpout + strlen (IDNA_ACE_PREFIX)) != 0) { free (utf8in); return IDNA_ROUNDTRIP_VERIFY_ERROR; } /* 8. Return the saved copy from step 5. */ free (utf8in); return IDNA_SUCCESS; }
static void _c2s_hosts_expand(c2s_t c2s) { char *realm; config_elem_t elem; char id[1024]; int i; elem = config_get(c2s->config, "local.id"); if(!elem) { log_write(c2s->log, LOG_NOTICE, "no local.id configured - skipping local domains configuration"); return; } for(i = 0; i < elem->nvalues; i++) { host_t host = (host_t) pmalloco(xhash_pool(c2s->hosts), sizeof(struct host_st)); if(!host) { log_write(c2s->log, LOG_ERR, "cannot allocate memory for new host, aborting"); exit(1); } realm = j_attr((const char **) elem->attrs[i], "realm"); /* stringprep ids (domain names) so that they are in canonical form */ strncpy(id, elem->values[i], 1024); id[1023] = '\0'; if (stringprep_nameprep(id, 1024) != 0) { log_write(c2s->log, LOG_ERR, "cannot stringprep id %s, aborting", id); exit(1); } host->realm = (realm != NULL) ? realm : pstrdup(xhash_pool(c2s->hosts), id); host->host_pemfile = j_attr((const char **) elem->attrs[i], "pemfile"); host->host_cachain = j_attr((const char **) elem->attrs[i], "cachain"); 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, 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, host->host_private_key_password) != 0) { log_write(c2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm); host->host_pemfile = NULL; } } } #endif host->host_require_starttls = (j_attr((const char **) elem->attrs[i], "require-starttls") != NULL); host->ar_register_enable = (j_attr((const char **) elem->attrs[i], "register-enable") != NULL); host->ar_register_oob = j_attr((const char **) elem->attrs[i], "register-oob"); if(host->ar_register_enable || host->ar_register_oob) { host->ar_register_instructions = j_attr((const char **) elem->attrs[i], "instructions"); if(host->ar_register_instructions == NULL) { if(host->ar_register_oob) host->ar_register_instructions = "Only web based registration is possible with this server."; else host->ar_register_instructions = "Enter a username and password to register with this server."; } } else host->ar_register_password = (j_attr((const char **) elem->attrs[i], "password-change") != NULL); /* check for empty <id/> CDATA - XXX this "1" is VERY config.c dependant !!! */ if(! strcmp(id, "1")) { /* remove the realm even if set */ host->realm = NULL; /* skip if vHost already configured */ if(! c2s->vhost) c2s->vhost = host; /* add meaningful log "id" */ strcpy(id, "default vHost"); } else { /* insert into vHosts xhash */ xhash_put(c2s->hosts, pstrdup(xhash_pool(c2s->hosts), id), host); } log_write(c2s->log, LOG_NOTICE, "[%s] configured; realm=%s, registration %s, using PEM:%s", id, (host->realm != NULL ? host->realm : "no realm set"), (host->ar_register_enable ? "enabled" : "disabled"), (host->host_pemfile ? host->host_pemfile : "Default")); } }
static JabberID* jabber_idn_validate(const char *str, const char *at, const char *slash, const char *null) { const char *node = NULL; const char *domain = NULL; const char *resource = NULL; int node_len = 0; int domain_len = 0; int resource_len = 0; char *out; JabberID *jid; /* Ensure no parts are > 1023 bytes */ if (at) { node = str; node_len = at - str; domain = at + 1; if (slash) { domain_len = slash - (at + 1); resource = slash + 1; resource_len = null - (slash + 1); } else { domain_len = null - (at + 1); } } else { domain = str; if (slash) { domain_len = slash - str; resource = slash; resource_len = null - (slash + 1); } else { domain_len = null - (str + 1); } } if (node && node_len > 1023) return NULL; if (domain_len > 1023) return NULL; if (resource && resource_len > 1023) return NULL; jid = g_new0(JabberID, 1); if (node) { strncpy(idn_buffer, node, node_len); idn_buffer[node_len] = '\0'; if (!jabber_nodeprep(idn_buffer, sizeof(idn_buffer))) { jabber_id_free(jid); jid = NULL; goto out; } jid->node = g_strdup(idn_buffer); } /* domain *must* be here */ strncpy(idn_buffer, domain, domain_len); idn_buffer[domain_len] = '\0'; if (domain[0] == '[') { /* IPv6 address */ gboolean valid = FALSE; if (idn_buffer[domain_len - 1] == ']') { idn_buffer[domain_len - 1] = '\0'; valid = purple_ipv6_address_is_valid(idn_buffer + 1); } if (!valid) { jabber_id_free(jid); jid = NULL; goto out; } } else { /* Apply nameprep */ if (stringprep_nameprep(idn_buffer, sizeof(idn_buffer)) != STRINGPREP_OK) { jabber_id_free(jid); jid = NULL; goto out; } /* And now ToASCII */ if (idna_to_ascii_8z(idn_buffer, &out, IDNA_USE_STD3_ASCII_RULES) != IDNA_SUCCESS) { jabber_id_free(jid); jid = NULL; goto out; } /* This *MUST* be freed using 'free', not 'g_free' */ free(out); jid->domain = g_strdup(idn_buffer); } if (resource) { strncpy(idn_buffer, resource, resource_len); idn_buffer[resource_len] = '\0'; if (!jabber_resourceprep(idn_buffer, sizeof(idn_buffer))) { jabber_id_free(jid); jid = NULL; goto out; } else jid->resource = g_strdup(idn_buffer); } out: return jid; }