void process_event(mspool *nsp, gh_list *evlist, msevent *nse, int ev) { int match_r = 0, match_w = 0; #if HAVE_OPENSSL int desire_r = 0, desire_w = 0; #endif if (nsp->tracelevel > 7) nsock_trace(nsp, "Processing event %lu", nse->id); if (!nse->event_done) { switch(nse->type) { case NSE_TYPE_CONNECT: case NSE_TYPE_CONNECT_SSL: if (ev != EV_NONE) handle_connect_result(nsp, nse, NSE_STATUS_SUCCESS); if (!nse->event_done && nse->timeout.tv_sec && !TIMEVAL_AFTER(nse->timeout, nsock_tod)) handle_connect_result(nsp, nse, NSE_STATUS_TIMEOUT); break; case NSE_TYPE_READ: match_r = ev & EV_READ; match_w = ev & EV_WRITE; #if HAVE_OPENSSL desire_r = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ; desire_w = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE; if (nse->iod->ssl && ((desire_r && match_r) || (desire_w && match_w))) handle_read_result(nsp, nse, NSE_STATUS_SUCCESS); else #endif if (!nse->iod->ssl && match_r) handle_read_result(nsp, nse, NSE_STATUS_SUCCESS); if (!nse->event_done && nse->timeout.tv_sec && !TIMEVAL_AFTER(nse->timeout, nsock_tod)) handle_read_result(nsp, nse, NSE_STATUS_TIMEOUT); break; case NSE_TYPE_WRITE: match_r = ev & EV_READ; match_w = ev & EV_WRITE; #if HAVE_OPENSSL desire_r = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ; desire_w = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE; if (nse->iod->ssl && ((desire_r && match_r) || (desire_w && match_w))) handle_write_result(nsp, nse, NSE_STATUS_SUCCESS); else #endif if (!nse->iod->ssl && match_w) handle_write_result(nsp, nse, NSE_STATUS_SUCCESS); if (!nse->event_done && nse->timeout.tv_sec && !TIMEVAL_AFTER(nse->timeout, nsock_tod)) handle_write_result(nsp, nse, NSE_STATUS_TIMEOUT); break; case NSE_TYPE_TIMER: if (nse->timeout.tv_sec && !TIMEVAL_AFTER(nse->timeout, nsock_tod)) handle_timer_result(nsp, nse, NSE_STATUS_SUCCESS); break; #if HAVE_PCAP case NSE_TYPE_PCAP_READ:{ if (nsp->tracelevel > 5) nsock_trace(nsp, "PCAP iterating %lu", nse->id); if (ev & EV_READ) { /* buffer empty? check it! */ if (FILESPACE_LENGTH(&(nse->iobuf)) == 0) do_actual_pcap_read(nse); } /* if already received smth */ if (FILESPACE_LENGTH(&(nse->iobuf)) > 0) handle_pcap_read_result(nsp, nse, NSE_STATUS_SUCCESS); if (!nse->event_done && nse->timeout.tv_sec && !TIMEVAL_AFTER(nse->timeout, nsock_tod)) handle_pcap_read_result(nsp, nse, NSE_STATUS_TIMEOUT); #if PCAP_BSD_SELECT_HACK /* If event occurred, and we're in BSD_HACK mode, then this event was added * to two queues. read_event and pcap_read_event * Of course we should destroy it only once. * I assume we're now in read_event, so just unlink this event from * pcap_read_event */ if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0 && nse->event_done && evlist == &nsp->read_events) { /* event is done, list is read_events and we're in BSD_HACK mode. * So unlink event from pcap_read_events */ update_first_events(nse); gh_list_remove(&nsp->pcap_read_events, nse); if (nsp->tracelevel > 8) nsock_trace(nsp, "PCAP NSE #%lu: Removing event from PCAP_READ_EVENTS", nse->id); } if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0 && nse->event_done && evlist == &nsp->pcap_read_events) { update_first_events(nse); gh_list_remove(&nsp->read_events, nse); if (nsp->tracelevel > 8) nsock_trace(nsp, "PCAP NSE #%lu: Removing event from READ_EVENTS", nse->id); } #endif break; } #endif default: fatal("Event has unknown type (%d)", nse->type); break; /* unreached */ } } if (nse->event_done) { /* Security sanity check: don't return a functional SSL iod without setting an SSL data structure. */ if (nse->type == NSE_TYPE_CONNECT_SSL && nse->status == NSE_STATUS_SUCCESS) assert(nse->iod->ssl != NULL); if (nsp->tracelevel > 8) nsock_trace(nsp, "NSE #%lu: Sending event", nse->id); /* WooHoo! The event is ready to be sent */ msevent_dispatch_and_delete(nsp, nse, 1); } else { /* Is this event the next-to-timeout? */ if (nse->timeout.tv_sec != 0) { if (nsp->next_ev.tv_sec == 0) nsp->next_ev = nse->timeout; else if (TIMEVAL_AFTER(nsp->next_ev, nse->timeout)) nsp->next_ev = nse->timeout; } } }
int msevent_timedout(msevent *nse) { if (nse->event_done) return 0; return (nse->timeout.tv_sec && !TIMEVAL_AFTER(nse->timeout, nsock_tod)); }
/* Adds an event to the appropriate nsp event list, handles housekeeping such as * adjusting the descriptor select/poll lists, registering the timeout value, * etc. */ void nsp_add_event(mspool *nsp, msevent *nse) { if (nsp->tracelevel > 5) nsock_trace(nsp, "NSE #%lu: Adding event", nse->id); /* First lets do the event-type independent stuff, starting with timeouts */ if (nse->event_done) { nsp->next_ev = nsock_tod; } else { if (nse->timeout.tv_sec != 0) { if (nsp->next_ev.tv_sec == 0) nsp->next_ev = nse->timeout; else if (TIMEVAL_AFTER(nsp->next_ev, nse->timeout)) nsp->next_ev = nse->timeout; } } nsp->events_pending++; /* Now we do the event type specific actions */ switch(nse->type) { case NSE_TYPE_CONNECT: case NSE_TYPE_CONNECT_SSL: if (!nse->event_done) { assert(nse->iod->sd >= 0); socket_count_read_inc(nse->iod); socket_count_write_inc(nse->iod); update_events(nse->iod, nsp, EV_READ|EV_WRITE|EV_EXCEPT, EV_NONE); } iod_add_event(nse->iod, nse); break; case NSE_TYPE_READ: if (!nse->event_done) { assert(nse->iod->sd >= 0); socket_count_read_inc(nse->iod); update_events(nse->iod, nsp, EV_READ, EV_NONE); #if HAVE_OPENSSL if (nse->iod->ssl) nse->sslinfo.ssl_desire = SSL_ERROR_WANT_READ; #endif } iod_add_event(nse->iod, nse); break; case NSE_TYPE_WRITE: if (!nse->event_done) { assert(nse->iod->sd >= 0); socket_count_write_inc(nse->iod); update_events(nse->iod, nsp, EV_WRITE, EV_NONE); #if HAVE_OPENSSL if (nse->iod->ssl) nse->sslinfo.ssl_desire = SSL_ERROR_WANT_WRITE; #endif } iod_add_event(nse->iod, nse); break; case NSE_TYPE_TIMER: gh_list_append(&nsp->timer_events, nse); break; #if HAVE_PCAP case NSE_TYPE_PCAP_READ: { mspcap *mp = (mspcap *)nse->iod->pcap; assert(mp); if (mp->pcap_desc >= 0) { /* pcap descriptor present */ if (!nse->event_done) { socket_count_readpcap_inc(nse->iod); update_events(nse->iod, nsp, EV_READ, EV_NONE); } if (nsp->tracelevel > 8) nsock_trace(nsp, "PCAP NSE #%lu: Adding event to READ_EVENTS", nse->id); #if PCAP_BSD_SELECT_HACK /* when using BSD hack we must do pcap_next() after select(). * Let's insert this pcap to bot queues, to selectable and nonselectable. * This will result in doing pcap_next_ex() just before select() */ if (nsp->tracelevel > 8) nsock_trace(nsp, "PCAP NSE #%lu: Adding event to PCAP_READ_EVENTS", nse->id); #endif } else { /* pcap isn't selectable. Add it to pcap-specific queue. */ if (nsp->tracelevel > 8) nsock_trace(nsp, "PCAP NSE #%lu: Adding event to PCAP_READ_EVENTS", nse->id); } iod_add_event(nse->iod, nse); break; } #endif default: assert(0); break; /* unreached */ } }
/* userpass is a user:pass string (the argument to --proxy-auth). value is the value of the Proxy-Authorization header field. Returns 0 on authentication failure and nonzero on success. *stale is set to 1 if HTTP Digest credentials are valid but out of date. */ static int check_auth(const struct http_request *request, const struct http_credentials *credentials, int *stale) { if (o.proxy_auth == NULL) return 1; *stale = 0; if (credentials->scheme == AUTH_BASIC) { char *expected; int cmp; if (credentials->u.basic == NULL) return 0; /* We don't decode the received password, we encode the expected password and compare the encoded strings. */ expected = b64enc((unsigned char *) o.proxy_auth, strlen(o.proxy_auth)); cmp = strcmp(expected, credentials->u.basic); free(expected); return cmp == 0; } #if HAVE_HTTP_DIGEST else if (credentials->scheme == AUTH_DIGEST) { char *username, *password; char *proxy_auth; struct timeval nonce_tv, now; int nonce_age; int ret; /* Split up the proxy auth argument. */ proxy_auth = Strdup(o.proxy_auth); username = strtok(proxy_auth, ":"); password = strtok(NULL, ":"); if (password == NULL) { free(proxy_auth); return 0; } ret = http_digest_check_credentials(username, "Ncat", password, request->method, credentials); free(proxy_auth); if (!ret) return 0; /* The nonce checks out as one we issued and it matches what we expect given the credentials. Now check if it's too old. */ if (credentials->u.digest.nonce == NULL || http_digest_nonce_time(credentials->u.digest.nonce, &nonce_tv) == -1) return 0; gettimeofday(&now, NULL); if (TIMEVAL_AFTER(nonce_tv, now)) return 0; nonce_age = TIMEVAL_SEC_SUBTRACT(now, nonce_tv); if (nonce_age > HTTP_DIGEST_NONCE_EXPIRY) { if (o.verbose) loguser("Nonce is %d seconds old; rejecting.\n", nonce_age); *stale = 1; return 0; } /* To prevent replays, here we should additionally check against a list of recently used nonces, where "recently used nonce" is one that has been used to successfully authenticate within the last HTTP_DIGEST_NONCE_EXPIRY seconds. (Older than that and we don't need to keep it in the list, because the expiry test above will catch it. This isn't supported because the fork-and-process architecture of the proxy server makes it hard for us to change state in the parent process from here in the child. */ return 1; } #endif else { return 0; } }