void ne_lockstore_remove(ne_lock_store *store, struct ne_lock *lock) { struct lock_list *item; /* Find the lock */ for (item = store->locks; item != NULL; item = item->next) if (item->lock == lock) break; if (item) { /* XXX coverity #440269 */ if (item->prev != NULL) { item->prev->next = item->next; } else { store->locks = item->next; } if (item->next != NULL) { item->next->prev = item->prev; } ne_free(item); } }
static void parse_dav_header(const char *value, ne_server_capabilities *caps) { char *tokens = ne_strdup(value), *pnt = tokens; do { char *tok = ne_qtoken(&pnt, ',', "\"'"); if (!tok) break; tok = ne_shave(tok, " \r\t\n"); if (strcmp(tok, "1") == 0) { caps->dav_class1 = 1; } else if (strcmp(tok, "2") == 0) { caps->dav_class2 = 1; } else if (strcmp(tok, "<http://apache.org/dav/propset/fs/1>") == 0) { caps->dav_executable = 1; } } while (pnt != NULL); ne_free(tokens); }
ne_ssl_certificate *ne_ssl_cert_read(const char *filename) { int ret; gnutls_datum data; gnutls_x509_crt x5; if (read_to_datum(filename, &data)) return NULL; if (gnutls_x509_crt_init(&x5) != 0) return NULL; ret = gnutls_x509_crt_import(x5, &data, GNUTLS_X509_FMT_PEM); ne_free(data.data); if (ret < 0) { gnutls_x509_crt_deinit(x5); return NULL; } return populate_cert(ne_calloc(sizeof(struct ne_ssl_certificate_s)), x5); }
static int check_redir(struct redir_args *args, const char *expect) { ne_session *sess; const ne_uri *loc; char *unp; CALL(make_session(&sess, serve_redir, args)); ne_redirect_register(sess); CALL(process_redir(sess, args->path, &loc)); ONN("redirect location was NULL", loc == NULL); unp = ne_uri_unparse(loc); ONV(strcmp(unp, expect), ("redirected to `%s' not `%s'", unp, expect)); ne_free(unp); ne_session_destroy(sess); CALL(await_server()); return OK; }
void ne_session_destroy(ne_session *sess) { struct hook *hk; NE_DEBUG(NE_DBG_HTTP, "sess: Destroying session.\n"); /* Run the destroy hooks. */ for (hk = sess->destroy_sess_hooks; hk != NULL; hk = hk->next) { ne_destroy_sess_fn fn = (ne_destroy_sess_fn)hk->fn; fn(hk->userdata); } /* Close the connection; note that the notifier callback could * still be invoked here. */ if (sess->connected) { ne_close_connection(sess); } destroy_hooks(sess->create_req_hooks); destroy_hooks(sess->pre_send_hooks); destroy_hooks(sess->post_headers_hooks); destroy_hooks(sess->post_send_hooks); destroy_hooks(sess->destroy_req_hooks); destroy_hooks(sess->destroy_sess_hooks); destroy_hooks(sess->close_conn_hooks); destroy_hooks(sess->private); ne_free(sess->scheme); ne_free(sess->server.hostname); ne_free(sess->server.hostport); if (sess->server.address) ne_addr_destroy(sess->server.address); if (sess->proxy.address) ne_addr_destroy(sess->proxy.address); if (sess->proxy.hostname) ne_free(sess->proxy.hostname); if (sess->user_agent) ne_free(sess->user_agent); #ifdef NE_HAVE_SSL if (sess->ssl_context) ne_ssl_context_destroy(sess->ssl_context); if (sess->server_cert) ne_ssl_cert_free(sess->server_cert); if (sess->client_cert) ne_ssl_clicert_free(sess->client_cert); #endif ne_free(sess); }
static int qappend(void) { static const struct { const char *in; size_t inlen; const char *out; } ts[] = { { "", 0, "" }, { "a", 1, "a" }, { "b", 2, "b\\x00" }, { "alpha\0alpha", 11, "alpha\\x00alpha" }, { "a\tb", 3, "a\\x09b" }, { NULL } }; unsigned n; for (n = 0; ts[n].in; n++) { ne_buffer *buf = ne_buffer_create(); char *s; const unsigned char *in = (const unsigned char *)ts[n].in; ne_buffer_qappend(buf, in, ts[n].inlen); ONCMP(buf->data, ts[n].out); ONV(strlen(buf->data) + 1 != buf->used, ("bad buffer length for '%s': %" NE_FMT_SIZE_T, ts[n].out, buf->used)); s = ne_strnqdup(in, ts[n].inlen); ONCMP(s, ts[n].out); ne_free(s); ne_buffer_destroy(buf); } return OK; }
char *ne_path_unescape(const char *uri) { const char *pnt; char *ret, *retpos, buf[5] = { "0x00\0" }; retpos = ret = ne_malloc(strlen(uri) + 1); for (pnt = uri; *pnt != '\0'; pnt++) { if (*pnt == '%') { if (!isxdigit((unsigned char) pnt[1]) || !isxdigit((unsigned char) pnt[2])) { /* Invalid URI */ ne_free(ret); return NULL; } buf[2] = *++pnt; buf[3] = *++pnt; /* bit faster than memcpy */ *retpos++ = (char)strtol(buf, NULL, 16); } else { *retpos++ = *pnt; } } *retpos = '\0'; return ret; }
/* Custom function of type ne_accept_response. */ static int ra_neon_error_accepter(void *userdata, ne_request *req, const ne_status *st) { /* Before, this function was being run for *all* responses including the 401 auth challenge. In neon 0.24.x that was harmless. But in neon 0.25.0, trying to parse a 401 response as XML using ne_xml_parse_v aborts the response; so the auth hooks never got a chance. */ ne_content_type ctype; /* Only accept non-2xx responses with text/xml content-type */ if (st->klass != 2 && ne_get_content_type(req, &ctype) == 0) { int is_xml = (strcmp(ctype.type, "text") == 0 && strcmp(ctype.subtype, "xml") == 0); ne_free(ctype.value); return is_xml; } else return 0; }
static int copy_shallow(void) { char *csrc, *cdest, *res; csrc = ne_concat(i_path, "ccsrc/", NULL); cdest = ne_concat(i_path, "ccdest/", NULL); /* Set up the ccsrc collection with one member */ ONMREQ("MKCOL", csrc, ne_mkcol(i_session, csrc)); CALL(upload_foo("ccsrc/foo")); /* Clean up to make some fresh copies. */ ne_delete(i_session, cdest); /* Now copy with Depth 0 */ ONV(ne_copy(i_session, 0, NE_DEPTH_ZERO, csrc, cdest), ("collection COPY `%s' to `%s': %s", csrc, cdest, ne_get_error(i_session))); /* Remove the source, to be paranoid. */ if (ne_delete(i_session, csrc)) { t_warning("Could not delete csrc"); } /* Now make sure the child resource hasn't been copied along with * the collection. */ res = ne_concat(i_path, "foo", NULL); ne_delete(i_session, res); ONV(STATUS(404), ("DELETE on `%s' should fail with 404: got %d", res, GETSTATUS)); ne_free(res); if (ne_delete(i_session, cdest)) { t_warning("Could not clean up cdest"); } return OK; }
static void parse_dav_header(const char *value, unsigned int *caps) { char *tokens = ne_strdup(value), *pnt = tokens; *caps = 0; do { char *tok = ne_qtoken(&pnt, ',', "\"'"); unsigned n; if (!tok) break; tok = ne_shave(tok, " \r\t\n"); for (n = 0; n < sizeof(options_map)/sizeof(options_map[0]); n++) { if (strcmp(tok, options_map[n].name) == 0) { *caps |= options_map[n].cap; } } } while (pnt != NULL); ne_free(tokens); }
void ne_session_destroy(ne_session *sess) { struct hook *hk; NE_DEBUG(NE_DBG_HTTP, "ne_session_destroy called.\n"); /* Run the destroy hooks. */ for (hk = sess->destroy_sess_hooks; hk != NULL; hk = hk->next) { ne_destroy_sess_fn fn = (ne_destroy_sess_fn)hk->fn; fn(hk->userdata); } destroy_hooks(sess->create_req_hooks); destroy_hooks(sess->pre_send_hooks); destroy_hooks(sess->post_send_hooks); destroy_hooks(sess->destroy_req_hooks); destroy_hooks(sess->destroy_sess_hooks); destroy_hooks(sess->private); ne_free(sess->scheme); ne_free(sess->server.hostname); ne_free(sess->server.hostport); if (sess->server.address) ne_addr_destroy(sess->server.address); if (sess->proxy.address) ne_addr_destroy(sess->proxy.address); if (sess->proxy.hostname) ne_free(sess->proxy.hostname); if (sess->user_agent) ne_free(sess->user_agent); if (sess->connected) { ne_close_connection(sess); } #ifdef NE_HAVE_SSL if (sess->ssl_context) ne_ssl_context_destroy(sess->ssl_context); if (sess->server_cert) ne_ssl_cert_free(sess->server_cert); if (sess->client_cert) ne_ssl_clicert_free(sess->client_cert); #endif ne_free(sess); }
static int large_writev(void) { struct string str; ne_socket *sock; ssize_t n; struct ne_iovec vec[4]; str.data = ne_malloc(LARGE_SIZE); str.len = LARGE_SIZE; for (n = 0; n < LARGE_SIZE; n++) str.data[n] = 41 + n % 130; for (n = 0; n < 4; n++) { vec[n].base = str.data + n * LARGE_SIZE / 4; vec[n].len = LARGE_SIZE / 4; } CALL(begin(&sock, serve_expect, &str)); CALL(full_writev(sock, vec, 4)); ne_free(str.data); return finish(sock, 1); }
/* Duplicate a client certificate, which must be in the decrypted state. */ static ne_ssl_client_cert *dup_client_cert(const ne_ssl_client_cert *cc) { int ret; ne_ssl_client_cert *newcc = ne_calloc(sizeof *newcc); newcc->decrypted = 1; if (cc->keyless) { newcc->keyless = 1; #ifdef HAVE_GNUTLS_PRIVKEY_IMPORT_EXT newcc->sign_func = cc->sign_func; newcc->sign_ud = cc->sign_ud; #endif } else { ret = gnutls_x509_privkey_init(&newcc->pkey); if (ret != 0) goto dup_error; ret = gnutls_x509_privkey_cpy(newcc->pkey, cc->pkey); if (ret != 0) goto dup_error; } newcc->cert.subject = x509_crt_copy(cc->cert.subject); if (!newcc->cert.subject) goto dup_error; if (cc->friendly_name) newcc->friendly_name = ne_strdup(cc->friendly_name); populate_cert(&newcc->cert, newcc->cert.subject); return newcc; dup_error: if (newcc->pkey) gnutls_x509_privkey_deinit(newcc->pkey); if (newcc->cert.subject) gnutls_x509_crt_deinit(newcc->cert.subject); ne_free(newcc); return NULL; }
/* FIXME: Leaky as a bucket */ void open_connection(const char *url) { char *proxy_host = get_option(opt_proxy), *pnt; ne_server_capabilities caps; int ret, use_ssl = 0; ne_session *sess; if (session.connected) { close_connection(); } else { ne_uri_free(&session.uri); if (session.lastwp) { ne_free(session.lastwp); session.lastwp = NULL; } } /* Single argument: see whether we have a path or scheme */ if (strchr(url, '/') == NULL) { /* No path, no scheme -> just a hostname */ pnt = strchr(url, ':'); if (pnt != NULL) { *pnt++ = '\0'; session.uri.port = atoi(pnt); } else { session.uri.port = 80; } session.uri.host = ne_strdup(url); session.uri.scheme = ne_strdup("http"); } else { /* Parse the URL */ if (ne_uri_parse(url, &session.uri) || session.uri.host == NULL) { printf(_("Could not parse URL `%s'\n"), url); return; } if (session.uri.scheme == NULL) session.uri.scheme = ne_strdup("http"); if (!session.uri.port) session.uri.port = ne_uri_defaultport(session.uri.scheme); if (strcasecmp(session.uri.scheme, "https") == 0) { if (!ne_has_support(NE_FEATURE_SSL)) { printf(_("SSL is not enabled.\n")); return; } use_ssl = 1; } } session.sess = ne_session_create(session.uri.scheme, session.uri.host, session.uri.port); sess = session.sess; if (use_ssl && setup_ssl()) { return; } ne_lockstore_register(session.locks, sess); ne_redirect_register(sess); ne_set_notifier(sess, notifier, NULL); if (session.uri.path == NULL) { session.uri.path = ne_strdup("/"); } else { if (!ne_path_has_trailing_slash(session.uri.path)) { pnt = ne_concat(session.uri.path, "/", NULL); free(session.uri.path); session.uri.path = pnt; } } /* Get the proxy details */ if (proxy_host != NULL) { if (get_option(opt_proxy_port) != NULL) { proxy_port = atoi(get_option(opt_proxy_port)); } else { proxy_port = 8080; } proxy_hostname = proxy_host; } #ifdef ENABLE_NETRC { netrc_entry *found; found = search_netrc(netrc_list, session.uri.host); if (found != NULL) { if (found->account && found->password) { server_username = found->account; server_password = found->password; } } } #endif /* ENABLE_NETRC */ #ifdef NE_SESSFLAG_EXPECT100 ne_set_session_flag(session.sess, NE_SESSFLAG_EXPECT100, get_bool_option(opt_expect100)); #endif /* NE_SESSFLAG_EXPECT100 */ session.connected = 0; ne_set_useragent(session.sess, "cadaver/" PACKAGE_VERSION); ne_set_server_auth(session.sess, supply_creds_server, NULL); ne_set_proxy_auth(session.sess, supply_creds_proxy, NULL); if (proxy_host) { ne_session_proxy(session.sess, proxy_hostname, proxy_port); } ret = ne_options(session.sess, session.uri.path, &caps); switch (ret) { case NE_OK: session.connected = true; if (set_path(session.uri.path)) { close_connection(); } break; case NE_CONNECT: if (proxy_host) { printf(_("Could not connect to `%s' on port %d:\n%s\n"), proxy_hostname, proxy_port, ne_get_error(session.sess)); } else { printf(_("Could not connect to `%s' on port %d:\n%s\n"), session.uri.host, session.uri.port, ne_get_error(session.sess)); } break; case NE_LOOKUP: puts(ne_get_error(session.sess)); break; default: printf(_("Could not open collection:\n%s\n"), ne_get_error(session.sess)); break; } }
/* This function directly implements the "Remove Dot Segments" * algorithm described in RFC 3986 section 5.2.4. */ static char *remove_dot_segments(const char *path) { char *in, *inc, *out; inc = in = ne_strdup(path); out = ne_malloc(strlen(path) + 1); out[0] = '\0'; while (in[0]) { /* case 2.A: */ if (strncmp(in, "./", 2) == 0) { in += 2; } else if (strncmp(in, "../", 3) == 0) { in += 3; } /* case 2.B: */ else if (strncmp(in, "/./", 3) == 0) { in += 2; } else if (strcmp(in, "/.") == 0) { in[1] = '\0'; } /* case 2.C: */ else if (strncmp(in, "/../", 4) == 0 || strcmp(in, "/..") == 0) { char *p; /* Make the next character in the input buffer a "/": */ if (in[3] == '\0') { /* terminating "/.." case */ in += 2; in[0] = '/'; } else { /* "/../" prefix case */ in += 3; } /* Trim the last component from the output buffer, or * empty it. */ p = strrchr(out, '/'); if (p) { *p = '\0'; } else { out[0] = '\0'; } } /* case 2.D: */ else if (strcmp(in, ".") == 0 || strcmp(in, "..") == 0) { in[0] = '\0'; } /* case 2.E */ else { char *p; /* Search for the *second* "/" if the leading character is * already "/": */ p = strchr(in + (in[0] == '/'), '/'); /* Otherwise, copy the whole string */ if (p == NULL) p = strchr(in, '\0'); strncat(out, in, p - in); in = p; } } ne_free(inc); return out; }
void ne_md5_destroy_ctx(struct ne_md5_ctx *ctx) { ne_free(ctx); }
void ne_lock_destroy(struct ne_lock *lock) { ne_lock_free(lock); ne_free(lock); }
void ne_lockstore_destroy(ne_lock_store *store) { free_list(store->locks, 1); ne_free(store); }
/* This implemementation does not attempt to support IPv6 using * gethostbyname2 et al. */ ne_sock_addr *ne_addr_resolve(const char *hostname, int flags) { ne_sock_addr *addr = ne_calloc(sizeof *addr); #ifdef USE_GETADDRINFO struct addrinfo hints = {0}; char *pnt; hints.ai_socktype = SOCK_STREAM; if (hostname[0] == '[' && ((pnt = strchr(hostname, ']')) != NULL)) { char *hn = ne_strdup(hostname + 1); hn[pnt - hostname - 1] = '\0'; #ifdef AI_NUMERICHOST /* added in the RFC2553 API */ hints.ai_flags = AI_NUMERICHOST; #endif hints.ai_family = AF_INET6; addr->errnum = getaddrinfo(hn, NULL, &hints, &addr->result); ne_free(hn); } else { #ifdef USE_GAI_ADDRCONFIG /* added in the RFC3493 API */ hints.ai_flags = AI_ADDRCONFIG; hints.ai_family = AF_UNSPEC; addr->errnum = getaddrinfo(hostname, NULL, &hints, &addr->result); #else hints.ai_family = ipv6_disabled ? AF_INET : AF_UNSPEC; addr->errnum = getaddrinfo(hostname, NULL, &hints, &addr->result); #endif } #else /* Use gethostbyname() */ in_addr_t laddr; struct hostent *hp; struct hostent h; char buf[sizeof(struct in_addr) + sizeof(struct in_addr *)*2 + sizeof(char *)*8 + 384/*namebuffer*/ + 32/* margin */]; int errn; laddr = inet_addr(hostname); if (laddr == INADDR_NONE) { if (ne_find_cached_host(hostname, &laddr)) { addr->addrs = ne_malloc(sizeof *addr->addrs); addr->count = 1; memcpy(addr->addrs, &laddr, sizeof *addr->addrs); return addr; } gethostbyname_r(hostname, &h, buf, sizeof(buf), &hp, &errn); //hp = gethostbyname(hostname); if (hp == NULL) { #ifdef WIN32 addr->errnum = WSAGetLastError(); #else addr->errnum = h_errno; #endif if (!addr->errnum) { addr->errnum = NO_RECOVERY; } } else if (hp->h_length != sizeof(struct in_addr)) { /* fail gracefully if somebody set RES_USE_INET6 */ addr->errnum = NO_RECOVERY; } else { size_t n; /* count addresses */ for (n = 0; hp->h_addr_list[n] != NULL; n++) /* noop */; addr->count = n; addr->addrs = ne_malloc(n * sizeof *addr->addrs); if (n > 0) ne_add_cached_host(hostname, hp->h_addr_list[0]); for (n = 0; n < addr->count; n++) memcpy(&addr->addrs[n], hp->h_addr_list[n], hp->h_length); } } else { addr->addrs = ne_malloc(sizeof *addr->addrs); addr->count = 1; memcpy(addr->addrs, &laddr, sizeof *addr->addrs); } #endif return addr; }
/* Pass this the value of the 'Authentication-Info:' header field, if * one is received. * Returns: * 0 if it gives a valid authentication for the server * non-zero otherwise (don't believe the response in this case!). */ static int verify_digest_response(struct auth_request *req, auth_session *sess, const char *value) { char *hdr, *pnt, *key, *val; auth_qop qop = auth_qop_none; char *nextnonce = NULL, /* for the nextnonce= value */ *rspauth = NULL, /* for the rspauth= value */ *cnonce = NULL, /* for the cnonce= value */ *nc = NULL, /* for the nc= value */ *qop_value = NULL; unsigned int nonce_count; int okay; if (!req->will_handle) { /* Ignore it */ return 0; } if (sess->scheme != auth_scheme_digest) { NE_DEBUG(NE_DBG_HTTPAUTH, "Found Auth-Info header not in response " " to Digest credentials - dodgy.\n"); return -1; } pnt = hdr = ne_strdup(value); NE_DEBUG(NE_DBG_HTTPAUTH, "Auth-Info header: %s\n", value); while (tokenize(&pnt, &key, &val, NULL, 0) == 0) { val = ne_shave(val, "\""); NE_DEBUG(NE_DBG_HTTPAUTH, "Pair: [%s] = [%s]\n", key, val); if (strcasecmp(key, "qop") == 0) { qop_value = val; if (strcasecmp(val, "auth") == 0) { qop = auth_qop_auth; } else { qop = auth_qop_none; } } else if (strcasecmp(key, "nextnonce") == 0) { nextnonce = val; } else if (strcasecmp(key, "rspauth") == 0) { rspauth = val; } else if (strcasecmp(key, "cnonce") == 0) { cnonce = val; } else if (strcasecmp(key, "nc") == 0) { nc = val; if (sscanf(val, "%x", &nonce_count) != 1) { NE_DEBUG(NE_DBG_HTTPAUTH, "Couldn't find nonce count.\n"); } else { NE_DEBUG(NE_DBG_HTTPAUTH, "Got nonce_count: %u\n", nonce_count); } } } /* Presume the worst */ okay = -1; if ((qop != auth_qop_none) && (qop_value != NULL)) { if ((rspauth == NULL) || (cnonce == NULL) || (nc == NULL)) { NE_DEBUG(NE_DBG_HTTPAUTH, "Missing rspauth, cnonce or nc with qop.\n"); } else { /* Have got rspauth, cnonce and nc */ if (strcmp(cnonce, sess->cnonce) != 0) { NE_DEBUG(NE_DBG_HTTPAUTH, "Response cnonce doesn't match.\n"); } else if (nonce_count != sess->nonce_count) { NE_DEBUG(NE_DBG_HTTPAUTH, "Response nonce count doesn't match.\n"); } else { /* Calculate and check the response-digest value. * joe: IMO the spec is slightly ambiguous as to whether * we use the qop which WE sent, or the qop which THEY * sent... */ struct ne_md5_ctx a2; unsigned char a2_md5[16], rdig_md5[16]; char a2_md5_ascii[33], rdig_md5_ascii[33]; NE_DEBUG(NE_DBG_HTTPAUTH, "Calculating response-digest.\n"); /* First off, H(A2) again. */ ne_md5_init_ctx(&a2); ne_md5_process_bytes(":", 1, &a2); ne_md5_process_bytes(req->uri, strlen(req->uri), &a2); ne_md5_finish_ctx(&a2, a2_md5); ne_md5_to_ascii(a2_md5, a2_md5_ascii); /* We have the stored digest-so-far of * H(A1) ":" unq(nonce-value) * [ ":" nc-value ":" unq(cnonce-value) ] for qop * in sess->stored_rdig, to save digesting them again. * */ if (qop != auth_qop_none) { /* Add in qop-value */ NE_DEBUG(NE_DBG_HTTPAUTH, "Digesting qop-value [%s:].\n", qop_value); ne_md5_process_bytes(qop_value, strlen(qop_value), &sess->stored_rdig); ne_md5_process_bytes(":", 1, &sess->stored_rdig); } /* Digest ":" H(A2) */ ne_md5_process_bytes(a2_md5_ascii, 32, &sess->stored_rdig); /* All done */ ne_md5_finish_ctx(&sess->stored_rdig, rdig_md5); ne_md5_to_ascii(rdig_md5, rdig_md5_ascii); NE_DEBUG(NE_DBG_HTTPAUTH, "Calculated response-digest of: " "[%s]\n", rdig_md5_ascii); NE_DEBUG(NE_DBG_HTTPAUTH, "Given response-digest of: " "[%s]\n", rspauth); /* And... do they match? */ okay = (strcasecmp(rdig_md5_ascii, rspauth) == 0)?0:-1; NE_DEBUG(NE_DBG_HTTPAUTH, "Matched: %s\n", okay?"nope":"YES!"); } } } else { NE_DEBUG(NE_DBG_HTTPAUTH, "No qop directive, auth okay.\n"); okay = 0; } /* Check for a nextnonce */ if (nextnonce != NULL) { NE_DEBUG(NE_DBG_HTTPAUTH, "Found nextnonce of [%s].\n", nextnonce); if (sess->nonce != NULL) ne_free(sess->nonce); sess->nonce = ne_strdup(nextnonce); } ne_free(hdr); return okay; }
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 }
static int execute_command(const char *line) { const struct command *cmd; char **tokens; int n, argcount, ret = 0; tokens = parse_command(line, &argcount); if (argcount == 0) { free(tokens); return 0; } argcount--; cmd = get_command(tokens[0]); if (cmd == NULL) { printf(_("Unrecognised command. Type 'help' for a list of commands.\n")); } else if (argcount < cmd->min_args) { printf(_("The `%s' command requires %d argument%s"), tokens[0], cmd->min_args, cmd->min_args==1?"":"s"); if (cmd->short_help) { printf(_(":\n %s : %s\n"), cmd->call, cmd->short_help); } else { printf(".\n"); } } else if (argcount > cmd->max_args) { if (cmd->max_args) { printf(_("The `%s' command takes at most %d argument%s"), tokens[0], cmd->max_args, cmd->max_args==1?"":"s"); } else { printf(_("The `%s' command takes no arguments"), tokens[0]); } if (cmd->short_help) { printf(_(":\n" " %s : %s\n"), cmd->call, cmd->short_help); } else { printf(".\n"); } } else if (!session.connected && cmd->needs_connection) { printf(_("The `%s' command can only be used when connected to the server.\n" "Try running `open' first (see `help open' for more details).\n"), tokens[0]); } else if (cmd->id == cmd_quit) { ret = -1; } else { /* Cast away */ /* with a nod in the general direction of apache */ switch (cmd->max_args) { case 0: cmd->handler.take0(); break; case 1: /* tokens[1]==NULL if argcount==0 */ cmd->handler.take1(tokens[1]); break; case 2: if (argcount <=1) { cmd->handler.take2(tokens[1], NULL); } else { cmd->handler.take2(tokens[1], tokens[2]); } break; case 3: cmd->handler.take3(tokens[1], tokens[2], tokens[3]); break; case CMD_VARY: cmd->handler.takeV(argcount, (const char **) &tokens[1]); default: break; } } for (n = 0; n < argcount; n++) { ne_free(tokens[n]); } ne_free(tokens); return ret; }
/* Callback invoked when the SSL server requests a client certificate. */ static int provide_client_cert(gnutls_session session, const gnutls_datum *req_ca_rdn, int nreqs, const gnutls_pk_algorithm *sign_algos, int sign_algos_length, gnutls_retr_st *st) { ne_session *sess = gnutls_session_get_ptr(session); if (!sess) { return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; } NE_DEBUG(NE_DBG_SSL, "ssl: Client cert provider callback; %d CA names.\n", nreqs); if (!sess->client_cert && sess->ssl_provide_fn) { #ifdef HAVE_NEW_DN_API const ne_ssl_dname **dns; ne_ssl_dname *dnarray; unsigned dncount = 0; int n; dns = ne_malloc(nreqs * sizeof(ne_ssl_dname *)); dnarray = ne_calloc(nreqs * sizeof(ne_ssl_dname)); for (n = 0; n < nreqs; n++) { gnutls_x509_dn_t dn; if (gnutls_x509_dn_init(&dn) == 0) { dnarray[n].dn = dn; if (gnutls_x509_dn_import(dn, &req_ca_rdn[n]) == 0) { dns[dncount++] = &dnarray[n]; } else { gnutls_x509_dn_deinit(dn); } } } NE_DEBUG(NE_DBG_SSL, "ssl: Mapped %d CA names to %u DN objects.\n", nreqs, dncount); sess->ssl_provide_fn(sess->ssl_provide_ud, sess, dns, dncount); for (n = 0; n < nreqs; n++) { if (dnarray[n].dn) { gnutls_x509_dn_deinit(dnarray[n].dn); } } ne_free(dns); ne_free(dnarray); #else /* HAVE_NEW_DN_API */ /* Nothing to do here other than pretend no CA names were * given, and hope the caller can cope. */ sess->ssl_provide_fn(sess->ssl_provide_ud, sess, NULL, 0); #endif } if (sess->client_cert) { gnutls_certificate_type type = gnutls_certificate_type_get(session); if (type == GNUTLS_CRT_X509) { NE_DEBUG(NE_DBG_SSL, "Supplying client certificate.\n"); st->type = type; st->ncerts = 1; st->cert.x509 = &sess->client_cert->cert.subject; st->key.x509 = sess->client_cert->pkey; /* tell GNU TLS not to deallocate the certs. */ st->deinit_all = 0; } else { return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE; } } else { NE_DEBUG(NE_DBG_SSL, "No client certificate supplied.\n"); st->ncerts = 0; sess->ssl_cc_requested = 1; return 0; } return 0; }
/* Parses a PKCS#12 structure and loads the certificate, private key * and friendly name if possible. Returns zero on success, non-zero * on error. */ static int pkcs12_parse(gnutls_pkcs12 p12, gnutls_x509_privkey *pkey, gnutls_x509_crt *x5, char **friendly_name, const char *password) { gnutls_pkcs12_bag bag = NULL; int i, j, ret = 0; for (i = 0; ret == 0; ++i) { if (bag) gnutls_pkcs12_bag_deinit(bag); ret = gnutls_pkcs12_bag_init(&bag); if (ret < 0) continue; ret = gnutls_pkcs12_get_bag(p12, i, bag); if (ret < 0) continue; gnutls_pkcs12_bag_decrypt(bag, password); for (j = 0; ret == 0 && j < gnutls_pkcs12_bag_get_count(bag); ++j) { gnutls_pkcs12_bag_type type; gnutls_datum data; if (friendly_name && *friendly_name == NULL) { char *name = NULL; gnutls_pkcs12_bag_get_friendly_name(bag, j, &name); if (name) { if (name[0] == '.') name++; /* weird GnuTLS bug? */ *friendly_name = ne_strdup(name); } } type = gnutls_pkcs12_bag_get_type(bag, j); switch (type) { case GNUTLS_BAG_PKCS8_KEY: case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY: /* Ignore any but the first key encountered; really * need to match up keyids. */ if (*pkey) break; gnutls_x509_privkey_init(pkey); ret = gnutls_pkcs12_bag_get_data(bag, j, &data); if (ret < 0) continue; ret = gnutls_x509_privkey_import_pkcs8(*pkey, &data, GNUTLS_X509_FMT_DER, password, 0); if (ret < 0) continue; break; case GNUTLS_BAG_CERTIFICATE: /* Ignore any but the first cert encountered; again, * really need to match up keyids. */ if (*x5) break; ret = gnutls_x509_crt_init(x5); if (ret < 0) continue; ret = gnutls_pkcs12_bag_get_data(bag, j, &data); if (ret < 0) continue; ret = gnutls_x509_crt_import(*x5, &data, GNUTLS_X509_FMT_DER); if (ret < 0) continue; break; default: break; } } } /* Make sure last bag is freed */ if (bag) gnutls_pkcs12_bag_deinit(bag); /* Free in case of error */ if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { if (*x5) gnutls_x509_crt_deinit(*x5); if (*pkey) gnutls_x509_privkey_deinit(*pkey); if (friendly_name && *friendly_name) ne_free(*friendly_name); } if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) ret = 0; return ret; }
static int ah_post_send(ne_request *req, void *cookie, const ne_status *status) { auth_session *sess = cookie; struct auth_request *areq = ne_get_request_private(req, sess->spec->id); const char *auth_hdr, *auth_info_hdr; int ret = NE_OK; if (!areq) return NE_OK; auth_hdr = ne_get_response_header(req, sess->spec->resp_hdr); auth_info_hdr = ne_get_response_header(req, sess->spec->resp_info_hdr); if (sess->context == AUTH_CONNECT && status->code == 401 && !auth_hdr) { /* Some broken proxies issue a 401 as a proxy auth challenge * to a CONNECT request; handle this here. */ auth_hdr = ne_get_response_header(req, "WWW-Authenticate"); auth_info_hdr = NULL; } #ifdef HAVE_GSSAPI /* whatever happens: forget the GSSAPI token cached thus far */ if (sess->gssapi_token) { ne_free(sess->gssapi_token); sess->gssapi_token = NULL; } #endif NE_DEBUG(NE_DBG_HTTPAUTH, "ah_post_send (#%d), code is %d (want %d), %s is %s\n", sess->attempt, status->code, sess->spec->status_code, sess->spec->resp_hdr, auth_hdr ? auth_hdr : "(none)"); if (auth_info_hdr && sess->scheme == auth_scheme_digest) { if (verify_digest_response(areq, sess, auth_info_hdr)) { NE_DEBUG(NE_DBG_HTTPAUTH, "Response authentication invalid.\n"); ne_set_error(sess->sess, "%s", _(sess->spec->fail_msg)); ret = NE_ERROR; } } #ifdef HAVE_GSSAPI /* one must wonder... has Mr Brezak actually read RFC2617? */ else if (sess->scheme == auth_scheme_gssapi && (status->klass == 2 || status->klass == 3) && auth_hdr) { char *hdr = ne_strdup(auth_hdr); if (verify_negotiate_response(sess, hdr)) { NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Mutual auth failed.\n"); ret = NE_ERROR; } ne_free(hdr); } #endif /* HAVE_GSSAPI */ else if ((status->code == sess->spec->status_code || (status->code == 401 && sess->context == AUTH_CONNECT)) && auth_hdr) { /* note above: allow a 401 in response to a CONNECT request * from a proxy since some buggy proxies send that. */ NE_DEBUG(NE_DBG_HTTPAUTH, "Got challenge (code %d).\n", status->code); if (!auth_challenge(sess, auth_hdr)) { ret = NE_RETRY; } else { clean_session(sess); ret = sess->spec->fail_code; } } #ifdef HAVE_SSPI else if (sess->sspi_context) { ne_sspi_clear_context(sess->sspi_context); } #endif return ret; }
static void free_hostinfo(struct host_info *hi) { if (hi->hostname) ne_free(hi->hostname); if (hi->hostport) ne_free(hi->hostport); if (hi->address) ne_addr_destroy(hi->address); }
/* Continue a GSS-API Negotiate exchange, using input TOKEN if * non-NULL. Returns non-zero on error. */ static int continue_negotiate(auth_session *sess, const char *token) { unsigned int major, minor; gss_buffer_desc input = GSS_C_EMPTY_BUFFER; gss_buffer_desc output = GSS_C_EMPTY_BUFFER; unsigned char *bintoken = NULL; int ret; if (token) { input.length = ne_unbase64(token, &bintoken); if (input.length == 0) { NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Invalid input [%s].\n", token); return -1; } input.value = bintoken; NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Continuation token [%s]\n", token); } else if (sess->gssctx != GSS_C_NO_CONTEXT) { NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Reset incomplete context.\n"); gss_delete_sec_context(&minor, &sess->gssctx, GSS_C_NO_BUFFER); } major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, &sess->gssctx, sess->gssname, sess->gssmech, GSS_C_MUTUAL_FLAG, GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, &input, &sess->gssmech, &output, NULL, NULL); /* done with the input token. */ if (bintoken) ne_free(bintoken); if (GSS_ERROR(major)) { ne_buffer *err = ne_buffer_create(); int flag = 0; make_gss_error(err, &flag, major, GSS_C_GSS_CODE); make_gss_error(err, &flag, minor, GSS_C_MECH_CODE); NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Error: %s\n", err->data); ne_set_error(sess->sess, _("GSSAPI authentication error (%s)"), err->data); ne_buffer_destroy(err); return -1; } if (major == GSS_S_CONTINUE_NEEDED || major == GSS_S_COMPLETE) { NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: init_sec_context OK. (major=%d)\n", major); ret = 0; } else { NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Init failure %d.\n", major); ret = -1; } if (major != GSS_S_CONTINUE_NEEDED) { /* context no longer needed: destroy it */ gss_delete_sec_context(&minor, &sess->gssctx, GSS_C_NO_BUFFER); } if (output.length) { sess->gssapi_token = ne_base64(output.value, output.length); NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Output token: [%s]\n", sess->gssapi_token); gss_release_buffer(&minor, &output); } else { NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: No output token.\n"); } return ret; }
static void lk_destroy(ne_request *req, void *userdata) { struct lh_req_cookie *lrc = ne_get_request_private(req, HOOK_ID); free_list(lrc->submit, 0); ne_free(lrc); }
/* Passed the value of a "(Proxy,WWW)-Authenticate: " header field. * Returns 0 if valid challenge was accepted; non-zero if no valid * challenge was found. */ static int auth_challenge(auth_session *sess, const char *value) { char *pnt, *key, *val, *hdr, sep; struct auth_challenge *chall = NULL, *challenges = NULL; int success; pnt = hdr = ne_strdup(value); NE_DEBUG(NE_DBG_HTTPAUTH, "Got new auth challenge: %s\n", value); /* The header value may be made up of one or more challenges. We * split it down into attribute-value pairs, then search for * schemes in the pair keys. */ while (!tokenize(&pnt, &key, &val, &sep, 1)) { if (val == NULL) { auth_scheme scheme; if (strcasecmp(key, "basic") == 0) { scheme = auth_scheme_basic; } else if (strcasecmp(key, "digest") == 0) { scheme = auth_scheme_digest; } #ifdef HAVE_GSSAPI else if (strcasecmp(key, "negotiate") == 0) { scheme = auth_scheme_gssapi; } #else #ifdef HAVE_SSPI else if (strcasecmp(key, "negotiate") == 0) { scheme = auth_scheme_sspi_negotiate; } else if (strcasecmp(key, "ntlm") == 0) { scheme = auth_scheme_sspi_ntlm; } #endif #endif else { NE_DEBUG(NE_DBG_HTTPAUTH, "Ignoring challenge '%s'.\n", key); chall = NULL; continue; } NE_DEBUG(NE_DBG_HTTPAUTH, "New '%s' challenge.\n", key); chall = ne_calloc(sizeof *chall); chall->scheme = scheme; chall->next = challenges; challenges = chall; if (sep == ' ' && (scheme == auth_scheme_gssapi || scheme == auth_scheme_sspi_negotiate || scheme == auth_scheme_sspi_ntlm) ) { /* Cope with the fact that the unquoted base64 * paramater token doesn't match the 2617 auth-param * grammar: */ chall->opaque = ne_shave(ne_token(&pnt, ','), " \t"); NE_DEBUG(NE_DBG_HTTPAUTH, "auth: Negotiate parameter '%s'\n", chall->opaque); if (!pnt) break; /* stop parsing at end-of-string. */ } continue; } else if (chall == NULL) { /* Ignore pairs for an unknown challenge. */ NE_DEBUG(NE_DBG_HTTPAUTH, "Ignored pair: %s = %s\n", key, val); continue; } /* Strip quotes off value. */ val = ne_shave(val, "\"'"); NE_DEBUG(NE_DBG_HTTPAUTH, "Got pair: [%s] = [%s]\n", key, val); if (strcasecmp(key, "realm") == 0) { chall->realm = val; } else if (strcasecmp(key, "nonce") == 0) { chall->nonce = val; } else if (strcasecmp(key, "opaque") == 0) { chall->opaque = val; } else if (strcasecmp(key, "stale") == 0) { /* Truth value */ chall->stale = (strcasecmp(val, "true") == 0); } else if (strcasecmp(key, "algorithm") == 0) { if (strcasecmp(val, "md5") == 0) { chall->alg = auth_alg_md5; } else if (strcasecmp(val, "md5-sess") == 0) { chall->alg = auth_alg_md5_sess; } else { chall->alg = auth_alg_unknown; } } else if (strcasecmp(key, "qop") == 0) { /* iterate over each token in the value */ do { const char *tok = ne_shave(ne_token(&val, ','), " \t"); if (strcasecmp(tok, "auth") == 0) { chall->qop_auth = 1; } } while (val); chall->got_qop = chall->qop_auth; } } NE_DEBUG(NE_DBG_HTTPAUTH, "Finished parsing parameters.\n"); /* Did we find any challenges */ if (challenges == NULL) { ne_free(hdr); return -1; } success = 0; #ifdef HAVE_GSSAPI /* Ignore Negotiate challenges from origin servers which don't * come over SSL. */ if (sess->spec == &ah_proxy_class || sess->context != AUTH_ANY) { NE_DEBUG(NE_DBG_HTTPAUTH, "Looking for GSSAPI.\n"); /* Try a GSSAPI challenge */ for (chall = challenges; chall != NULL; chall = chall->next) { if (chall->scheme == auth_scheme_gssapi) { if (!gssapi_challenge(sess, chall)) { success = 1; break; } } } } #endif #ifdef HAVE_SSPI if (!success) { NE_DEBUG(NE_DBG_HTTPAUTH, "Looking for SSPI/Negotiate.\n"); for (chall = challenges; chall != NULL; chall = chall->next) { if (chall->scheme == auth_scheme_sspi_negotiate) { if (!sspi_challenge(sess, chall, 0)) { success = 1; break; } } } } if (!success) { NE_DEBUG(NE_DBG_HTTPAUTH, "Looking for SSPI/NTLM.\n"); for (chall = challenges; chall != NULL; chall = chall->next) { if (chall->scheme == auth_scheme_sspi_ntlm) { if (!sspi_challenge(sess, chall, 1)) { success = 1; break; } } } } #endif /* Try a digest challenge */ if (!success) { NE_DEBUG(NE_DBG_HTTPAUTH, "Looking for Digest challenges.\n"); for (chall = challenges; chall != NULL; chall = chall->next) { if (chall->scheme == auth_scheme_digest) { if (!digest_challenge(sess, chall)) { success = 1; break; } } } } if (!success) { NE_DEBUG(NE_DBG_HTTPAUTH, "No good Digest challenges, looking for Basic.\n"); for (chall = challenges; chall != NULL; chall = chall->next) { if (chall->scheme == auth_scheme_basic) { if (!basic_challenge(sess, chall)) { success = 1; break; } } } if (!success) { /* No good challenges - record this in the session state */ NE_DEBUG(NE_DBG_HTTPAUTH, "Did not understand any challenges.\n"); } } /* Remember whether we can now supply the auth details */ sess->can_handle = success; while (challenges != NULL) { chall = challenges->next; ne_free(challenges); challenges = chall; } ne_free(hdr); return !success; }
/* Check certificate identity. Returns zero if identity matches; 1 if * identity does not match, or <0 if the certificate had no identity. * If 'identity' is non-NULL, store the malloc-allocated identity in * *identity. */ static int check_identity(const char *hostname, X509 *cert, char **identity) { STACK_OF(GENERAL_NAME) *names; int match = 0, found = 0; names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (names) { int n; /* subjectAltName contains a sequence of GeneralNames */ for (n = 0; n < sk_GENERAL_NAME_num(names) && !match; n++) { GENERAL_NAME *nm = sk_GENERAL_NAME_value(names, n); /* handle dNSName and iPAddress name extensions only. */ if (nm->type == GEN_DNS) { char *name = dup_ia5string(nm->d.ia5); if (identity && !found) *identity = ne_strdup(name); match = match_hostname(name, hostname); ne_free(name); found = 1; } else if (nm->type == GEN_IPADD) { /* compare IP address with server IP address. */ ne_inet_addr *ia; if (nm->d.ip->length == 4) ia = ne_iaddr_make(ne_iaddr_ipv4, nm->d.ip->data); else if (nm->d.ip->length == 16) ia = ne_iaddr_make(ne_iaddr_ipv6, nm->d.ip->data); else ia = NULL; /* ne_iaddr_make returns NULL if address type is unsupported */ if (ia != NULL) { /* address type was supported. */ char buf[128]; match = strcmp(hostname, ne_iaddr_print(ia, buf, sizeof buf)) == 0; found = 1; ne_iaddr_free(ia); } else { NE_DEBUG(NE_DBG_SSL, "iPAddress name with unsupported " "address type (length %d), skipped.\n", nm->d.ip->length); } } /* TODO: handle uniformResourceIdentifier too */ } /* free the whole stack. */ sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); } /* Check against the commonName if no DNS alt. names were found, * as per RFC3280. */ if (!found) { X509_NAME *subj = X509_get_subject_name(cert); X509_NAME_ENTRY *entry; ne_buffer *cname = ne_buffer_ncreate(30); int idx = -1, lastidx; /* find the most specific commonName attribute. */ do { lastidx = idx; idx = X509_NAME_get_index_by_NID(subj, NID_commonName, lastidx); } while (idx >= 0); if (lastidx < 0) { /* no commonNmae attributes at all. */ ne_buffer_destroy(cname); return -1; } /* extract the string from the entry */ entry = X509_NAME_get_entry(subj, lastidx); if (append_dirstring(cname, X509_NAME_ENTRY_get_data(entry))) { ne_buffer_destroy(cname); return -1; } if (identity) *identity = ne_strdup(cname->data); match = match_hostname(cname->data, hostname); ne_buffer_destroy(cname); } NE_DEBUG(NE_DBG_SSL, "Identity match for '%s': %s\n", hostname, match ? "good" : "bad"); return match ? 0 : 1; }