/**Check that we support all features which UAC requires. * * The list of supported features is compared with the list of features * required by the UAC. If some features are not listed as supported, return * 420. If @a irq is non-NULL, the 420 response message is sent to the * client along with list of unsupported features in the @Unsupported * header, too. * * @param irq incoming transaction object (may be NULL). * @param sip contents of the SIP message * @param supported list of protocol features supported * @param tag, value, ... optional list of tagged arguments used * when responding to the transaction * * @return 0 if successful. * 420 if any of the required features is not supported. */ int nta_check_required(nta_incoming_t *irq, sip_t const *sip, sip_supported_t const *supported, tag_type_t tag, tag_value_t value, ...) { int status = 0; if (sip->sip_require) { su_home_t home[SU_HOME_AUTO_SIZE(512)]; sip_unsupported_t *us; su_home_auto(home, sizeof home); us = sip_has_unsupported(home, supported, sip->sip_require); if (us) { status = 420; if (irq) { ta_list ta; ta_start(ta, tag, value); nta_incoming_treply(irq, SIP_420_BAD_EXTENSION, SIPTAG_UNSUPPORTED(us), SIPTAG_SUPPORTED(supported), ta_tags(ta)); ta_end(ta); } } su_home_deinit(home); } return status; }
/** Create a http site object. * * The function nth_site_create() allocates and initializes a web site * object. A web site object can be either * - a primary http server (@a parent is NULL), * - a virtual http server (@a address contains hostpart), or * - a site within a server * (@a address does not have hostpart, only path part). * * @param parent pointer to parent site * (NULL when creating a primary server object) * @param callback pointer to callback function called when * a request is received * @param magic application context included in callback parameters * @param address absolute or relative URI specifying the address of * site * @param tag, value, ... list of tagged parameters * * @TAGS * If the @a parent is NULL, the list of tagged parameters must contain * NTHTAG_ROOT() used to create the server engine. Tags supported when @a * parent is NULL are NTHTAG_ROOT(), NTHTAG_MCLASS(), TPTAG_REUSE(), * HTTPTAG_SERVER(), and HTTPTAG_SERVER_STR(). All the tags are passed to * tport_tcreate() and tport_tbind(), too. * * @since Support for multiple sites was added to @VERSION_1_12_4 */ nth_site_t *nth_site_create(nth_site_t *parent, nth_request_f *callback, nth_site_magic_t *magic, url_string_t const *address, tag_type_t tag, tag_value_t value, ...) { nth_site_t *site = NULL, **prev = NULL; su_home_t home[SU_HOME_AUTO_SIZE(256)]; url_t *url, url0[1]; server_t *srv = NULL; ta_list ta; char *path = NULL; size_t usize; int is_host, is_path, wildcard = 0; su_home_auto(home, sizeof home); if (parent && url_is_string(address)) { char const *s = (char const *)address; size_t sep = strcspn(s, "/:"); if (parent->site_path) { /* subpath */ url_init(url0, (enum url_type_e)parent->site_url->url_type); url0->url_path = s; address = (url_string_t*)url0; } else if (s[sep] == ':') /* absolute URL with scheme */; else if (s[sep] == '\0' && strchr(s, '.') && host_is_valid(s)) { /* looks like a domain name */; url_init(url0, (enum url_type_e)parent->site_url->url_type); url0->url_host = s; address = (url_string_t*)url0; } else { /* looks like a path */ url_init(url0, (enum url_type_e)parent->site_url->url_type); url0->url_path = s; address = (url_string_t*)url0; } } url = url_hdup(home, address->us_url); if (!url || !callback) return NULL; is_host = url->url_host != NULL; is_path = url->url_path != NULL; if (is_host && is_path) { SU_DEBUG_3(("nth_site_create(): virtual host and path simultanously\n")); errno = EINVAL; goto error; } if (!parent && !is_host) { SU_DEBUG_3(("nth_site_create(): host is required\n")); errno = EINVAL; goto error; } if (parent) { if (!parent->site_isdir) { SU_DEBUG_3(("nth_site_create(): invalid parent resource \n")); errno = EINVAL; goto error; } srv = parent->site_server; assert(srv); if (is_host) { prev = site_get_host(&srv->srv_sites, url->url_host, url->url_port); if (prev == NULL) { SU_DEBUG_3(("nth_site_create(): host %s:%s already exists\n", url->url_host, url->url_port ? url->url_port : "")); errno = EEXIST; goto error; } } else { size_t i, j; path = (char *)url->url_path; while (path[0] == '/') path++; /* Remove duplicate // */ for (i = j = 0; path[i];) { while (path[i] == '/' && path[i + 1] == '/') i++; path[j++] = path[i++]; } path[j] = path[i]; url = url0, *url = *parent->site_url; if (url->url_path) { url->url_path = su_strcat(home, url->url_path, path); if (!url->url_path) goto error; path = (char *)url->url_path + strlen(parent->site_url->url_path); } else url->url_path = path; prev = site_get_rslot(parent, path, &path); if (!prev || path[0] == '\0') { SU_DEBUG_3(("nth_site_create(): directory \"%s\" already exists\n", url->url_path)); errno = EEXIST; goto error; } } } if (!parent) { if (strcmp(url->url_host, "*") == 0 || host_cmp(url->url_host, "0.0.0.0") == 0 || host_cmp(url->url_host, "::") == 0) wildcard = 1, url->url_host = "*"; } usize = sizeof(*url) + url_xtra(url); ta_start(ta, tag, value); if (!parent) { srv = server_create(url, ta_tags(ta)); prev = &srv->srv_sites; } if (srv && (site = su_zalloc(srv->srv_home, (sizeof *site) + usize))) { site->site_url = (url_t *)(site + 1); url_dup((void *)(site->site_url + 1), usize - sizeof(*url), site->site_url, url); assert(prev); if ((site->site_next = *prev)) site->site_next->site_prev = &site->site_next; *prev = site, site->site_prev = prev; site->site_server = srv; if (path) { size_t path_len; site->site_path = site->site_url->url_path + (path - url->url_path); path_len = strlen(site->site_path); assert(path_len > 0); if (path_len > 0 && site->site_path[path_len - 1] == '/') path_len--, site->site_isdir = 1; site->site_path_len = path_len; } else { site->site_isdir = is_host; site->site_path = ""; site->site_path_len = 0; } site->site_wildcard = wildcard; site->site_callback = callback; site->site_magic = magic; if (parent) site->site_auth = parent->site_auth; nth_site_set_params(site, ta_tags(ta)); } ta_end(ta); error: su_home_deinit(home); return site; }
/** * Updates the modified copy of local SDP based * on application provided local SDP and remote SDP. */ static int offer_answer_step(soa_session_t *ss, enum offer_answer_action action, char const *by) { soa_static_session_t *sss = (soa_static_session_t *)ss; sdp_session_t *local = ss->ss_local->ssd_sdp; sdp_session_t local0[1]; sdp_session_t *user = ss->ss_user->ssd_sdp; unsigned user_version = ss->ss_user_version; sdp_session_t *remote = ss->ss_remote->ssd_sdp; unsigned remote_version = ss->ss_remote_version; int fresh = 0; sdp_origin_t o[1] = {{ sizeof(o) }}; sdp_connection_t *c, c0[1] = {{ sizeof(c0) }}; char c0_buffer[64]; sdp_time_t t[1] = {{ sizeof(t) }}; int *u2s = NULL, *s2u = NULL, *tbf; sdp_session_t *latest = NULL, *previous = NULL; char const *phrase = "Internal Media Error"; su_home_t tmphome[SU_HOME_AUTO_SIZE(8192)]; su_home_auto(tmphome, sizeof tmphome); SU_DEBUG_7(("soa_static_offer_answer_action(%p, %s): called\n", (void *)ss, by)); if (user == NULL) return soa_set_status(ss, 500, "No session set by user"); if (action == generate_offer) remote = NULL; else if (remote == NULL) return soa_set_status(ss, 500, "No remote SDP"); /* Pre-negotiation Step: Expand truncated remote SDP */ if (local && remote) switch (action) { case generate_answer: case process_answer: if (sdp_media_count(remote, sdp_media_any, "*", (sdp_proto_e)0, (sdp_text_t)0) < sdp_media_count(local, sdp_media_any, "*", (sdp_proto_e)0, (sdp_text_t)0)) { SU_DEBUG_5(("%s: remote %s is truncated: expanding\n", by, action == generate_answer ? "offer" : "answer")); remote = soa_sdp_expand_media(tmphome, remote, local); if (remote == NULL) return soa_set_status(ss, 500, "Cannot expand remote session"); } default: break; } /* Step A: Create local SDP session (based on user-supplied SDP) */ if (local == NULL) switch (action) { case generate_offer: case generate_answer: SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by, "generating local description")); fresh = 1; local = local0; *local = *user, local->sdp_media = NULL; o->o_username = "******"; o->o_address = c0; c0->c_address = c0_buffer; if (!local->sdp_origin) local->sdp_origin = o; break; case process_answer: default: goto internal_error; } /* Step B: upgrade local SDP (add m= lines to it) */ switch (action) { case generate_offer: /* Upgrade local SDP based on user SDP */ if (local != local0 && ss->ss_local_user_version == user_version) break; if (local != local0) *local0 = *local, local = local0; SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by, "upgrade with local description")); if (soa_sdp_upgrade(ss, tmphome, local, user, NULL, &u2s, &s2u) < 0) goto internal_error; break; case generate_answer: /* Upgrade local SDP based on remote SDP */ if (ss->ss_local_user_version == user_version && ss->ss_local_remote_version == remote_version) break; if (1) { if (local != local0) *local0 = *local, local = local0; SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by, "upgrade with remote description")); if (soa_sdp_upgrade(ss, tmphome, local, user, remote, &u2s, &s2u) < 0) goto internal_error; } break; case process_answer: default: break; } /* Step C: reject media */ switch (action) { case generate_offer: /* Local media is marked as rejected already in upgrade phase */ break; case generate_answer: case process_answer: if (ss->ss_local_remote_version == remote_version) break; if (soa_sdp_reject_is_needed(local, remote)) { if (local != local0) { *local0 = *local, local = local0; #define DUP_LOCAL(local) \ do { \ if (!local->sdp_media) break; \ local->sdp_media = \ sdp_media_dup_all(tmphome, local->sdp_media, local); \ if (!local->sdp_media) \ goto internal_error; \ } while (0) DUP_LOCAL(local); } SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by, "marking rejected media")); soa_sdp_reject(tmphome, local, remote); } break; default: break; } /* Step D: Set media mode bits */ switch (action) { int const *s2u_; case generate_offer: case generate_answer: case process_answer: s2u_ = s2u; if (!s2u_) s2u_ = sss->sss_s2u; if (soa_sdp_mode_set(user, s2u_, local, remote, ss->ss_hold, 1)) { if (local != local0) { *local0 = *local, local = local0; DUP_LOCAL(local); } soa_sdp_mode_set(user, s2u_, local, remote, ss->ss_hold, 0); } break; default: break; } /* Step E: Upgrade codecs by answer. */ switch (action) { case process_answer: /* Upgrade local SDP based on remote SDP */ if (ss->ss_local_remote_version == remote_version) break; if (1 /* We don't have good test for codecs */) { SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by, "upgrade codecs with remote description")); if (local != local0) { *local0 = *local, local = local0; DUP_LOCAL(local); } soa_sdp_session_upgrade_rtpmaps(ss, local, remote); } break; case generate_offer: case generate_answer: default: break; } /* Step F0: Initialize o= line */ if (fresh) { if (user->sdp_origin) { o->o_username = user->sdp_origin->o_username; if (user->sdp_origin->o_address) o->o_address = user->sdp_origin->o_address; if (user->sdp_origin->o_id) o->o_id = user->sdp_origin->o_id; if (user->sdp_origin->o_version && user->sdp_origin->o_version != o->o_version) { o->o_version = user->sdp_origin->o_version; o->o_version--; } } if (soa_init_sdp_origin_with_session(ss, o, c0_buffer, local) < 0) { phrase = "Cannot Get IP Address for Session Description"; goto internal_error; } local->sdp_origin = o; } /* Step F: Update c= line(s) */ switch (action) { sdp_connection_t *user_c, *local_c; case generate_offer: case generate_answer: user_c = user->sdp_connection; if (!soa_check_sdp_connection(user_c)) user_c = NULL; local_c = local->sdp_connection; if (!soa_check_sdp_connection(local_c)) local_c = NULL; if (ss->ss_local_user_version != user_version || local_c == NULL || (user_c != NULL && sdp_connection_cmp(local_c, user_c))) { sdp_media_t *m; if (user_c) c = user_c; else c = local->sdp_origin->o_address; /* Every m= line (even rejected one) must have a c= line * or there must be a c= line at session level */ for (m = local->sdp_media; m; m = m->m_next) if (m->m_connections == NULL) break; if (m) { if (local != local0) { *local0 = *local, local = local0; DUP_LOCAL(local); } local->sdp_connection = c; } } break; default: break; } soa_description_free(ss, ss->ss_previous); su_free(ss->ss_home, sss->sss_previous.u2s), sss->sss_previous.u2s = NULL; su_free(ss->ss_home, sss->sss_previous.s2u), sss->sss_previous.s2u = NULL; if (u2s) { u2s = u2s_alloc(ss->ss_home, u2s); s2u = u2s_alloc(ss->ss_home, s2u); if (!u2s || !s2u) goto internal_error; } if (ss->ss_local->ssd_sdp != local && sdp_session_cmp(ss->ss_local->ssd_sdp, local)) { int bump; switch (action) { case generate_offer: bump = sdp_session_cmp(local, sss->sss_latest); break; case generate_answer: bump = 1; break; case process_answer: default: bump = 0; break; } if (bump) { /* Upgrade the version number */ if (local->sdp_origin != o) *o = *local->sdp_origin, local->sdp_origin = o; o->o_version++; } /* Do sanity checks for the created SDP */ if (!local->sdp_subject) /* s= is mandatory */ local->sdp_subject = "-"; if (!local->sdp_time) /* t= is mandatory */ local->sdp_time = t; if (action == generate_offer) { /* Keep a copy of previous session state */ int *previous_u2s = u2s_alloc(ss->ss_home, sss->sss_u2s); int *previous_s2u = u2s_alloc(ss->ss_home, sss->sss_s2u); if ((sss->sss_u2s && !previous_u2s) || (sss->sss_s2u && !previous_s2u)) goto internal_error; *ss->ss_previous = *ss->ss_local; memset(ss->ss_local, 0, (sizeof *ss->ss_local)); ss->ss_previous_user_version = ss->ss_local_user_version; ss->ss_previous_remote_version = ss->ss_local_remote_version; sss->sss_previous.u2s = previous_u2s; sss->sss_previous.s2u = previous_s2u; } SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by, "storing local description")); /* Update the unparsed and pretty-printed descriptions */ if (soa_description_set(ss, ss->ss_local, local, NULL, 0) < 0) { if (action == generate_offer) { /* Remove 2nd reference to local session state */ memset(ss->ss_previous, 0, (sizeof *ss->ss_previous)); ss->ss_previous_user_version = 0; ss->ss_previous_remote_version = 0; su_free(ss->ss_home, sss->sss_previous.u2s), sss->sss_previous.u2s = NULL; su_free(ss->ss_home, sss->sss_previous.s2u), sss->sss_previous.s2u = NULL; } su_free(ss->ss_home, u2s), su_free(ss->ss_home, s2u); goto internal_error; } if (bump) { latest = sdp_session_dup(ss->ss_home, ss->ss_local->ssd_sdp); previous = sss->sss_latest; } } if (u2s) { tbf = sss->sss_u2s, sss->sss_u2s = u2s, su_free(ss->ss_home, tbf); tbf = sss->sss_s2u, sss->sss_s2u = s2u, su_free(ss->ss_home, tbf); } /* Update version numbers */ switch (action) { case generate_offer: ss->ss_local_user_version = user_version; sss->sss_latest = latest; break; case generate_answer: ss->ss_local_user_version = user_version; ss->ss_local_remote_version = remote_version; sss->sss_latest = latest; break; case process_answer: ss->ss_local_remote_version = remote_version; default: break; } if (previous) su_free(ss->ss_home, previous); su_home_deinit(tmphome); return 0; internal_error: su_home_deinit(tmphome); return soa_set_status(ss, 500, phrase); }
static int tport_ws_init_primary_secure(tport_primary_t *pri, tp_name_t tpn[1], su_addrinfo_t *ai, tagi_t const *tags, char const **return_culprit) { tport_ws_primary_t *wspri = (tport_ws_primary_t *)pri; const char *cert = "/ssl.pem"; const char *key = "/ssl.pem"; char *homedir; char *tbf = NULL; su_home_t autohome[SU_HOME_AUTO_SIZE(1024)]; char const *path = NULL; int ret = -1; su_home_auto(autohome, sizeof autohome); tl_gets(tags, TPTAG_CERTIFICATE_REF(path), TAG_END()); if (!path) { homedir = getenv("HOME"); if (!homedir) homedir = ""; path = tbf = su_sprintf(autohome, "%s/.sip/auth", homedir); } if (path) { key = su_sprintf(autohome, "%s/%s", path, "wss.key"); if (access(key, R_OK) != 0) key = NULL; cert = su_sprintf(autohome, "%s/%s", path, "wss.crt"); if (access(cert, R_OK) != 0) cert = NULL; if ( !key ) key = su_sprintf(autohome, "%s/%s", path, "wss.pem"); if ( !cert ) cert = su_sprintf(autohome, "%s/%s", path, "wss.pem"); if (access(key, R_OK) != 0) key = NULL; if (access(cert, R_OK) != 0) cert = NULL; } init_ssl(); // OpenSSL_add_all_algorithms(); /* load & register cryptos */ // SSL_load_error_strings(); /* load all error messages */ wspri->ssl_method = SSLv23_server_method(); /* create server instance */ wspri->ssl_ctx = SSL_CTX_new((SSL_METHOD *)wspri->ssl_method); /* create context */ SSL_CTX_sess_set_remove_cb(wspri->ssl_ctx, NULL); wspri->ws_secure = 1; if ( !wspri->ssl_ctx ) goto done; /* set the local certificate from CertFile */ SSL_CTX_use_certificate_file(wspri->ssl_ctx, cert, SSL_FILETYPE_PEM); /* set the private key from KeyFile */ SSL_CTX_use_PrivateKey_file(wspri->ssl_ctx, key, SSL_FILETYPE_PEM); /* verify private key */ if ( !SSL_CTX_check_private_key(wspri->ssl_ctx) ) { goto done; } SSL_CTX_set_cipher_list(wspri->ssl_ctx, "HIGH:!DSS:!aNULL@STRENGTH"); ret = tport_ws_init_primary(pri, tpn, ai, tags, return_culprit); done: su_home_zap(autohome); return ret; }
static int test_auto(void) { BEGIN(); int i; su_home_t tmphome[SU_HOME_AUTO_SIZE(8000)]; char *b = NULL; su_home_stat_t hs[1]; TEST_1(!su_home_auto(tmphome, sizeof tmphome[0])); TEST_1(su_home_auto(tmphome, sizeof tmphome)); for (i = 0; i < 8192; i++) TEST_1(su_alloc(tmphome, 12)); TEST_VOID(su_home_deinit(tmphome)); TEST_1(su_home_auto(tmphome, sizeof tmphome)); su_home_init_stats(tmphome); for (i = 1; i < 8192; i++) { TEST_1(b = su_realloc(tmphome, b, i)); b[i - 1] = '\125'; } for (i = 1; i < 8192; i++) { TEST(b[i - 1], '\125'); } for (i = 1; i < 8192; i++) { TEST_1(b = su_realloc(tmphome, b, i)); b[i - 1] = '\125'; if ((i % 32) == 0) TEST_1(b = su_realloc(tmphome, b, 1)); } su_home_get_stats(tmphome, 0, hs, sizeof *hs); TEST64(hs->hs_allocs.hsa_preload + hs->hs_allocs.hsa_number, 8191 + 8191 + 8191 / 32); TEST64(hs->hs_frees.hsf_preload + hs->hs_frees.hsf_number, 8191 + 8191 + 8191 / 32 - 1); /* This test depends on macro SU_HOME_AUTO_SIZE() calculating offsetof(su_block_t, sub_nodes[7]) correctly with ((3 * sizeof (void *) + 4 * sizeof(unsigned) + 7 * (sizeof (long) + sizeof(void *)) + 7) */ TEST_1(hs->hs_frees.hsf_preload == hs->hs_allocs.hsa_preload); su_free(tmphome, b); for (i = 1; i < 8192; i++) TEST_1(b = su_alloc(tmphome, 1)); TEST_VOID(su_home_deinit(tmphome)); END(); }