unsigned int ne_uri_defaultport(const char *scheme) { /* RFC2616/3.2.3 says use case-insensitive comparisons here. */ if (ne_strcasecmp(scheme, "http") == 0) return 80; else if (ne_strcasecmp(scheme, "https") == 0) return 443; else return 0; }
/* Returns non-zero if given content-type is an XML media type, * following the RFC 3023 rules. */ static int media_type_is_xml(const ne_content_type *ctype) { size_t stlen; return (ne_strcasecmp(ctype->type, "text") == 0 && ne_strcasecmp(ctype->subtype, "xml") == 0) || (ne_strcasecmp(ctype->type, "application") == 0 && ne_strcasecmp(ctype->subtype, "xml") == 0) || ((stlen = strlen(ctype->subtype)) > 4 && ne_strcasecmp(ctype->subtype + stlen - 4, "+xml") == 0); }
int ne_get_content_type(ne_request *req, ne_content_type *ct) { const char *value; char *sep, *stype; value = ne_get_response_header(req, "Content-Type"); if (value == NULL || strchr(value, '/') == NULL) { return -1; } ct->value = ne_strdup(value); stype = strchr(ct->value, '/'); *stype++ = '\0'; ct->type = ct->value; ct->charset = NULL; sep = strchr(stype, ';'); if (sep) { char *tok; /* look for the charset parameter. TODO; probably better to * hand-carve a parser than use ne_token/strstr/shave here. */ *sep++ = '\0'; do { tok = ne_qtoken(&sep, ';', "\"\'"); if (tok) { tok = strstr(tok, "charset="); if (tok) ct->charset = ne_shave(tok+8, "\"\'"); } else { break; } } while (sep != NULL); } /* set subtype, losing any trailing whitespace */ ct->subtype = ne_shave(stype, " \t"); if (ct->charset == NULL && ne_strcasecmp(ct->type, "text") == 0) { /* 3280§3.1: text/xml without charset implies us-ascii. */ if (ne_strcasecmp(ct->subtype, "xml") == 0) ct->charset = "us-ascii"; /* 2616§3.7.1: subtypes of text/ default to charset ISO-8859-1. */ else ct->charset = "ISO-8859-1"; } return 0; }
/* This doesn't actually implement complete RFC 2818 logic; omits * "f*.example.com" support for simplicity. */ int ne__ssl_match_hostname(const char *cn, size_t cnlen, const char *hostname) { const char *dot; NE_DEBUG(NE_DBG_SSL, "ssl: Match common name '%s' against '%s'\n", cn, hostname); if (strncmp(cn, "*.", 2) == 0 && cnlen > 2 && (dot = strchr(hostname, '.')) != NULL) { ne_inet_addr *ia; /* Prevent wildcard CN matches against anything which can be * parsed as an IP address (i.e. a CN of "*.1.1.1" should not * be match 8.1.1.1). draft-saintandre-tls-server-id-check * will require some more significant changes to cert ID * verification which will probably obviate this check, but * this is a desirable policy tightening in the mean time. */ ia = ne_iaddr_parse(hostname, ne_iaddr_ipv4); if (ia == NULL) ia = ne_iaddr_parse(hostname, ne_iaddr_ipv6); if (ia) { NE_DEBUG(NE_DBG_SSL, "ssl: Denying wildcard match for numeric " "IP address.\n"); ne_iaddr_free(ia); return 0; } hostname = dot + 1; cn += 2; cnlen -= 2; } return cnlen == strlen(hostname) && !ne_strcasecmp(cn, hostname); }
static int parse_depth(const char *depth) { if (ne_strcasecmp(depth, "infinity") == 0) { return NE_DEPTH_INFINITE; } else if (isdigit(depth[0])) { return atoi(depth); } else { return -1; } }
/* Submit the given lock for the given URI */ static void submit_lock(struct lh_req_cookie *lrc, struct ne_lock *lock) { struct lock_list *item; /* Check for dups */ for (item = lrc->submit; item != NULL; item = item->next) { if (ne_strcasecmp(item->lock->token, lock->token) == 0) return; } insert_lock(&lrc->submit, lock); }
static int casecmp(void) { static const struct { const char *left, *right; int expect; } ts[] = { { "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0 }, { "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz", 0 }, { "foo", "bar", 1 }, { "!#:[@\377", "!#:[@\377", 0 }, { "bar", "foo", -1 }, { "foop", "foo", 1 }, { "foo", "foop", -1 }, { NULL, NULL, 0 } }; size_t n; for (n = 0; ts[n].left; n++) { int actual; actual = ne_strcasecmp(ts[n].left, ts[n].right); ONV(ts[n].expect == 0 && actual != 0, ("strcasecmp(%s, %s) gave %d, expected 0", ts[n].left, ts[n].right, actual)); ONV(ts[n].expect > 0 && actual <= 0, ("strcasecmp(%s, %s) gave %d, expected > 0", ts[n].left, ts[n].right, actual)); ONV(ts[n].expect < 0 && actual >= 0, ("strcasecmp(%s, %s) gave %d, expected < 0", ts[n].left, ts[n].right, actual)); } ONN("comparison of identical pointers did not give zero", ne_strcasecmp(ts[0].left, ts[0].left) != 0); return OK; }
static long parse_timeout(const char *timeout) { if (ne_strcasecmp(timeout, "infinite") == 0) { return NE_TIMEOUT_INFINITE; } else if (strncasecmp(timeout, "Second-", 7) == 0) { long to = strtol(timeout+7, NULL, 10); if (to == LONG_MIN || to == LONG_MAX) return NE_TIMEOUT_INVALID; return to; } else { return NE_TIMEOUT_INVALID; } }
/* Return non-zero if hostname from certificate (cn) matches hostname * used for session (hostname). (Wildcard matching is no longer * mandated by RFC3280, but certs are deployed which use wildcards) */ static int match_hostname(char *cn, const char *hostname) { const char *dot; NE_DEBUG(NE_DBG_SSL, "Match %s on %s...\n", cn, hostname); dot = strchr(hostname, '.'); if (dot == NULL) { char *pnt = strchr(cn, '.'); /* hostname is not fully-qualified; unqualify the cn. */ if (pnt != NULL) { *pnt = '\0'; } } else if (strncmp(cn, "*.", 2) == 0) { hostname = dot + 1; cn += 2; } return !ne_strcasecmp(cn, hostname); }
/* This doesn't actually implement complete RFC 2818 logic; omits * "f*.example.com" support for simplicity. */ int ne__ssl_match_hostname(char *cn, const char *hostname) { const char *dot; dot = strchr(hostname, '.'); if (dot == NULL) { char *pnt = strchr(cn, '.'); /* hostname is not fully-qualified; unqualify the cn. */ if (pnt != NULL) { *pnt = '\0'; } } else if (strncmp(cn, "*.", 2) == 0) { hostname = dot + 1; cn += 2; } return !ne_strcasecmp(cn, hostname); }
/* TODO: implement properly */ int ne_path_compare(const char *a, const char *b) { int ret = ne_strcasecmp(a, b); if (ret) { /* This logic says: "If the lengths of the two URIs differ by * exactly one, and the LONGER of the two URIs has a trailing * slash and the SHORTER one DOESN'T, then..." */ int traila = ne_path_has_trailing_slash(a), trailb = ne_path_has_trailing_slash(b), lena = strlen(a), lenb = strlen(b); if (traila != trailb && abs(lena - lenb) == 1 && ((traila && lena > lenb) || (trailb && lenb > lena))) { /* Compare them, ignoring the trailing slash on the longer * URI */ if (strncasecmp(a, b, lena < lenb ? lena : lenb) == 0) ret = 0; } } return ret; }
void ne_session_system_proxy(ne_session *sess, unsigned int flags) { #ifdef HAVE_LIBPROXY pxProxyFactory *pxf = px_proxy_factory_new(); struct host_info *hi, **lasthi; char *url, **proxies; ne_uri uri; unsigned n; free_proxies(sess); /* Create URI for session to pass off to libproxy */ memset(&uri, 0, sizeof uri); ne_fill_server_uri(sess, &uri); uri.path = "/"; /* make valid URI structure. */ url = ne_uri_unparse(&uri); uri.path = NULL; /* Get list of pseudo-URIs from libproxy: */ proxies = px_proxy_factory_get_proxies(pxf, url); for (n = 0, lasthi = &sess->proxies; proxies[n]; n++) { enum proxy_type ptype; ne_uri_free(&uri); NE_DEBUG(NE_DBG_HTTP, "sess: libproxy #%u=%s\n", n, proxies[n]); if (ne_uri_parse(proxies[n], &uri)) continue; if (!uri.scheme) continue; if (ne_strcasecmp(uri.scheme, "http") == 0) ptype = PROXY_HTTP; else if (ne_strcasecmp(uri.scheme, "socks") == 0) ptype = PROXY_SOCKS; else if (ne_strcasecmp(uri.scheme, "direct") == 0) ptype = PROXY_NONE; else continue; /* Hostname/port required for http/socks schemes. */ if (ptype != PROXY_NONE && !(uri.host && uri.port)) continue; /* Do nothing if libproxy returned only a single "direct://" * entry -- a single "direct" (noop) proxy is equivalent to * having none. */ if (n == 0 && proxies[1] == NULL && ptype == PROXY_NONE) break; NE_DEBUG(NE_DBG_HTTP, "sess: Got proxy %s://%s:%d\n", uri.scheme, uri.host ? uri.host : "(none)", uri.port); hi = *lasthi = ne_calloc(sizeof *hi); if (ptype == PROXY_NONE) { /* A "direct" URI requires an attempt to connect directly to * the origin server, so dup the server details. */ set_hostinfo(hi, ptype, sess->server.hostname, sess->server.port); } else { /* SOCKS/HTTP proxy. */ set_hostinfo(hi, ptype, uri.host, uri.port); if (ptype == PROXY_HTTP) sess->any_proxy_http = 1; else if (ptype == PROXY_SOCKS) sess->socks_ver = NE_SOCK_SOCKSV5; } lasthi = &hi->next; } /* Free up the proxies array: */ for (n = 0; proxies[n]; n++) free(proxies[n]); free(proxies[n]); ne_free(url); ne_uri_free(&uri); px_proxy_factory_free(pxf); #endif }
/* Callback which is passed blocks of the response body. */ static int gz_reader(void *ud, const char *buf, size_t len) { ne_decompress *ctx = ud; NE_DEBUG_WINSCP_CONTEXT(ctx->session); const char *zbuf; size_t count; const char *hdr; if (len == 0) { /* End of response: */ switch (ctx->state) { case NE_Z_BEFORE_DATA: hdr = ne_get_response_header(ctx->request, "Content-Encoding"); if (hdr && ne_strcasecmp(hdr, "gzip") == 0) { /* response was truncated: return error. */ break; } /* else, fall through */ case NE_Z_FINISHED: /* complete gzip response */ case NE_Z_PASSTHROUGH: /* complete uncompressed response */ return ctx->reader(ctx->userdata, buf, 0); default: /* invalid state: truncated response. */ break; } /* else: truncated response, fail. */ ne_set_error(ctx->session, "Compressed response was truncated"); return NE_ERROR; } switch (ctx->state) { case NE_Z_PASSTHROUGH: /* move along there. */ return ctx->reader(ctx->userdata, buf, len); case NE_Z_FINISHED: /* Could argue for tolerance, and ignoring trailing content; * but it could mean something more serious. */ if (len > 0) { ne_set_error(ctx->session, "Unexpected content received after compressed stream"); return NE_ERROR; } break; case NE_Z_BEFORE_DATA: /* work out whether this is a compressed response or not. */ hdr = ne_get_response_header(ctx->request, "Content-Encoding"); if (hdr && ne_strcasecmp(hdr, "gzip") == 0) { int ret; NE_DEBUG(NE_DBG_HTTP, "compress: got gzipped stream.\n"); /* inflateInit2() works here where inflateInit() doesn't. */ ret = inflateInit2(&ctx->zstr, -MAX_WBITS); if (ret != Z_OK) { set_zlib_error(ctx, _("Could not initialize zlib"), ret); return -1; } ctx->zstrinit = 1; } else { /* No Content-Encoding header: pass it on. TODO: we could * hack it and register the real callback now. But that * would require add_resp_body_rdr to have defined * ordering semantics etc etc */ ctx->state = NE_Z_PASSTHROUGH; return ctx->reader(ctx->userdata, buf, len); } ctx->state = NE_Z_IN_HEADER; /* FALLTHROUGH */ case NE_Z_IN_HEADER: /* copy as many bytes as possible into the buffer. */ if (len + ctx->hdrcount > 10) { count = 10 - ctx->hdrcount; } else { count = len; } memcpy(ctx->header + ctx->hdrcount, buf, count); ctx->hdrcount += count; /* have we got the full header yet? */ if (ctx->hdrcount != 10) { return 0; } buf += count; len -= count; switch (parse_header(ctx)) { case HDR_EXTENDED: if (len == 0) return 0; break; case HDR_ERROR: return NE_ERROR; case HDR_DONE: if (len > 0) { return do_inflate(ctx, buf, len); } break; } /* FALLTHROUGH */ case NE_Z_POST_HEADER: /* eating the filename string. */ zbuf = memchr(buf, '\0', len); if (zbuf == NULL) { /* not found it yet. */ return 0; } NE_DEBUG(NE_DBG_HTTP, "compresss: skipped %" NE_FMT_SIZE_T " header bytes.\n", zbuf - buf); /* found end of string. */ len -= (1 + zbuf - buf); buf = zbuf + 1; ctx->state = NE_Z_INFLATING; if (len == 0) { /* end of string was at end of buffer. */ return 0; } /* FALLTHROUGH */ case NE_Z_INFLATING: return do_inflate(ctx, buf, len); case NE_Z_AFTER_DATA: return process_footer(ctx, (unsigned char *)buf, len); } return 0; }