/* * Write one byte to an empty fifo, then try to read one byte and make sure * we don't get back EAGAIN. */ static void test_nonblocking_one_byte(void) { int reader_fd, ret, timedout, writer_fd; ssize_t len; u_char ch; makefifo("testfifo", __func__); if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) < 0) { warn("test_nonblocking: openfifo: testfifo"); cleanfifo2("testfifo", -1, -1); exit(-1); } if (set_nonblocking(reader_fd, __func__) < 0) { cleanfifo2("testfifo", reader_fd, writer_fd); exit(-1); } ch = 0xfe; ret = timed_write(writer_fd, &ch, sizeof(ch), &len, 5, &timedout, __func__); if (ret < 0) { warn("test_nonblocking_one_byte: timed_write"); cleanfifo2("testfifo", reader_fd, writer_fd); exit(-1); } if (len != sizeof(ch)) { warnx("test_nonblocking_one_byte: timed_write: tried to write " "%zu, wrote %zd", sizeof(ch), len); cleanfifo2("testfifo", reader_fd, writer_fd); exit(-1); } ch = 0xab; ret = timed_read(reader_fd, &ch, sizeof(ch), &len, 5, &timedout, __func__); if (ret < 0) { warn("test_nonblocking_one_byte: timed_read"); cleanfifo2("testfifo", reader_fd, writer_fd); exit(-1); } if (len != sizeof(ch)) { warnx("test_nonblocking_one_byte: timed_read: wanted %zu, read " "%zd", sizeof(ch), len); cleanfifo2("testfifo", reader_fd, writer_fd); exit(-1); } if (ch != 0xfe) { warnx("test_nonblocking_one_byte: timed_read: expected to read " "0x%02x, read 0x%02x", 0xfe, ch); cleanfifo2("testfifo", reader_fd, writer_fd); exit(-1); } cleanfifo2("testfifo", reader_fd, writer_fd); }
static ssize_t serialized_write(struct http_connection *c, const void *buf, size_t count) { tpool_inform_blocking(&tpool); mutex_lock(&c->writelock); tpool_inform_unblocked(&tpool); ssize_t ret = timed_write(c, buf, count); mutex_unlock(&c->writelock); return ret; }
/* * First of two test cases involving a 512K buffer: write the buffer into a * blocking file descriptor. We'd like to know it blocks, but the closest we * can get is to see if SIGALRM fired during the I/O resulting in a partial * write. */ static void test_blocking_partial_write(void) { int reader_fd, ret, timedout, writer_fd; u_char *buffer; ssize_t len; makefifo("testfifo", __func__); if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) < 0) { warn("test_blocking_partial_write: openfifo: testfifo"); cleanfifo2("testfifo", -1, -1); exit(-1); } if (set_blocking(writer_fd, __func__) < 0) { cleanfifo2("testfifo", reader_fd, writer_fd); exit(-1); } buffer = malloc(512*1024); if (buffer == NULL) { warn("test_blocking_partial_write: malloc"); cleanfifo2("testfifo", reader_fd, writer_fd); exit(-1); } bzero(buffer, 512*1024); ret = timed_write(writer_fd, buffer, 512*1024, &len, 5, &timedout, __func__); if (ret < 0) { warn("test_blocking_partial_write: timed_write"); free(buffer); cleanfifo2("testfifo", reader_fd, writer_fd); exit(-1); } if (!timedout) { warnx("test_blocking_partial_write: timed_write: blocking " "socket didn't time out"); free(buffer); cleanfifo2("testfifo", reader_fd, writer_fd); exit(-1); } free(buffer); if (drain_fd(reader_fd, __func__) < 0) { cleanfifo2("testfifo", reader_fd, writer_fd); exit(-1); } cleanfifo2("testfifo", reader_fd, writer_fd); }
static bool try_query(Message *msg, Message *answer, timeout_t *timeout) { int s = get_connection(timeout); if (s < 0) return false; if (timeout_happened(timeout)) { debug("try_query: get_connection() timed out\n"); return false; } if (!timed_write(s, msg, sizeof(Message), timeout)) { debug("try_query: failed to send the query to the leader\n"); return false; } if (!timed_read(s, answer, sizeof(Message), timeout)) { debug("try_query: failed to recv the answer from the leader\n"); return false; } return true; }
ssize_t tls_prng_egd_read(TLS_PRNG_SRC *egd, size_t len) { const char *myname = "tls_prng_egd_read"; unsigned char buffer[UCHAR_MAX]; ssize_t count; if (len <= 0) msg_panic("%s: bad length %ld", myname, (long) len); buffer[0] = 1; buffer[1] = (len > UCHAR_MAX ? UCHAR_MAX : len); if (timed_write(egd->fd, buffer, 2, egd->timeout, (void *) 0) != 2) { msg_info("cannot write to EGD server %s: %m", egd->name); return (-1); } if (timed_read(egd->fd, buffer, 1, egd->timeout, (void *) 0) != 1) { msg_info("cannot read from EGD server %s: %m", egd->name); return (-1); } count = buffer[0]; if (count > sizeof(buffer)) count = sizeof(buffer); if (count == 0) { msg_info("EGD server %s reports zero bytes available", egd->name); return (-1); } if (timed_read(egd->fd, buffer, count, egd->timeout, (void *) 0) != count) { msg_info("cannot read %ld bytes from EGD server %s: %m", (long) count, egd->name); return (-1); } if (msg_verbose) msg_info("%s: got %ld bytes from EGD server %s", myname, (long) count, egd->name); RAND_seed(buffer, count); return (count); }
/* * Write a 512K buffer to an empty fifo using a non-blocking file descriptor, * and make sure it doesn't block. */ static void test_nonblocking_partial_write(void) { int reader_fd, ret, timedout, writer_fd; u_char *buffer; ssize_t len; makefifo("testfifo", __func__); if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) { warn("test_blocking_partial_write: openfifo: testfifo"); cleanfifo2("testfifo", -1, -1); exit(-1); } if (set_nonblocking(writer_fd, __func__) < 0) { cleanfifo2("testfifo", reader_fd, writer_fd); exit(-1); } buffer = malloc(512*1024); if (buffer == NULL) { warn("test_blocking_partial_write: malloc"); cleanfifo2("testfifo", reader_fd, writer_fd); exit(-1); } bzero(buffer, 512*1024); ret = timed_write(writer_fd, buffer, 512*1024, &len, 5, &timedout, __func__); if (ret < 0) { warn("test_blocking_partial_write: timed_write"); free(buffer); cleanfifo2("testfifo", reader_fd, writer_fd); exit(-1); } if (timedout) { warnx("test_blocking_partial_write: timed_write: " "non-blocking socket timed out"); free(buffer); cleanfifo2("testfifo", reader_fd, writer_fd); exit(-1); } if (len == 0 || len >= 512*1024) { warnx("test_blocking_partial_write: timed_write: requested " "%d, sent %zd", 512*1024, len); free(buffer); cleanfifo2("testfifo", reader_fd, writer_fd); exit(-1); } free(buffer); if (drain_fd(reader_fd, __func__) < 0) { cleanfifo2("testfifo", reader_fd, writer_fd); exit(-1); } cleanfifo2("testfifo", reader_fd, writer_fd); }
/* Parse, a-la IPv6 */ int parse6(int fd, struct sockaddr_in6 *laddr, struct sockaddr_in6 *faddr) { char token[21], buf[BUFSIZ], *p; struct sockaddr_in6 laddr2, faddr2; struct passwd *pw; uid_t uid; int n; if (debug_flag && syslog_flag) syslog(LOG_DEBUG, "In function parse6(), from %s to %s", gethost6(faddr), gethost6(laddr)); faddr2 = *faddr; laddr2 = *laddr; lport = fport = 0; /* Read query from client */ if ((n = timed_read(fd, buf, sizeof(buf) - 1, IO_TIMEOUT)) <= 0) { if (syslog_flag) syslog(LOG_NOTICE, n ? "read from %s: %m" : "read from %s: EOF", gethost6(faddr)); if ((n = snprintf(buf, sizeof(buf), "%d , %d : ERROR : UNKNOWN-ERROR\r\n", lport, fport)) >= sizeof(buf) || n < 0) n = strlen(buf); if (timed_write(fd, buf, n, IO_TIMEOUT) != n && syslog_flag) { syslog(LOG_NOTICE, "write to %s: %m", gethost6(faddr)); return 1; } return 0; } buf[n] = '\0'; /* Pull out local and remote ports */ p = buf; while (isspace(*p)) p++; if ((p = strtok(p, " \t,"))) { lport = atoi(p); if ((p = strtok(NULL, " \t,"))) fport = atoi(p); } if (lport < 1 || lport > 65535 || fport < 1 || fport > 65535) { if (syslog_flag) syslog(LOG_NOTICE, "scanf: invalid-port(s): %d , %d from %s", lport, fport, gethost6(faddr)); if ((n = snprintf(buf, sizeof(buf), "%d , %d : ERROR : %s\r\n", lport, fport, unknown_flag ? "UNKNOWN-ERROR" : "INVALID-PORT")) >= sizeof(buf) || n < 0) n = strlen(buf); if (timed_write(fd, buf, n, IO_TIMEOUT) != n && syslog_flag) { syslog(LOG_NOTICE, "write to %s: %m", gethost6(faddr)); return 1; } return 0; } if (syslog_flag && verbose_flag) syslog(LOG_NOTICE, "request for (%d,%d) from %s", lport, fport, gethost6(faddr)); if (debug_flag && syslog_flag) syslog(LOG_DEBUG, " After fscanf(), before k_getuid6()"); /* * Next - get the specific TCP connection and return the * uid - user number. */ if (k_getuid6(&faddr2, htons(fport), laddr, htons(lport), &uid) == -1) { if (no_user_token_flag) { gentoken(token, sizeof token); syslog(LOG_NOTICE, "token %s == NO USER", token); if ((n = snprintf(buf, sizeof(buf), "%d , %d : USERID : %s%s%s :%s\r\n", lport, fport, opsys_name, charset_sep, charset_name, token)) >= sizeof(buf) || n < 0) n = strlen(buf); if (timed_write(fd, buf, n, IO_TIMEOUT) != n && syslog_flag) { syslog(LOG_NOTICE, "write to %s: %m", gethost6(faddr)); return 1; } return 0; } if (syslog_flag) syslog(LOG_DEBUG, "Returning: %d , %d : NO-USER", lport, fport); if ((n = snprintf(buf, sizeof(buf), "%d , %d : ERROR : %s\r\n", lport, fport, unknown_flag ? "UNKNOWN-ERROR" : "NO-USER")) >= sizeof(buf) || n < 0) n = strlen(buf); if (timed_write(fd, buf, n, IO_TIMEOUT) != n && syslog_flag) { syslog(LOG_NOTICE, "write to %s: %m", gethost6(faddr)); return 1; } return 0; } if (debug_flag && syslog_flag) syslog(LOG_DEBUG, " After k_getuid6(), before getpwuid()"); pw = getpwuid(uid); if (!pw) { if (syslog_flag) syslog(LOG_WARNING, "getpwuid() could not map uid (%u) to name", uid); if ((n = snprintf(buf, sizeof(buf), "%d , %d : USERID : %s%s%s :%u\r\n", lport, fport, opsys_name, charset_sep, charset_name, uid)) >= sizeof(buf) || n < 0) n = strlen(buf); if (timed_write(fd, buf, n, IO_TIMEOUT) != n && syslog_flag) { syslog(LOG_NOTICE, "write to %s: %m", gethost6(faddr)); return 1; } return 0; } if (syslog_flag) syslog(LOG_DEBUG, "Successful lookup: %d , %d : %s", lport, fport, pw->pw_name); if (noident_flag && check_noident(pw->pw_dir)) { if (syslog_flag && verbose_flag) syslog(LOG_NOTICE, "user %s requested HIDDEN-USER for host %s: %d, %d", pw->pw_name, gethost6(faddr), lport, fport); if ((n = snprintf(buf, sizeof(buf), "%d , %d : ERROR : HIDDEN-USER\r\n", lport, fport)) >= sizeof(buf) || n < 0) n = strlen(buf); if (timed_write(fd, buf, n, IO_TIMEOUT) != n && syslog_flag) { syslog(LOG_NOTICE, "write to %s: %m", gethost6(faddr)); return 1; } return 0; } if (userident_flag && getuserident(pw->pw_dir, token, sizeof token)) { syslog(LOG_NOTICE, "token \"%s\" == uid %u (%s)", token, uid, pw->pw_name); if ((n = snprintf(buf, sizeof(buf), "%d , %d : USERID : %s%s%s :%s\r\n", lport, fport, opsys_name, charset_sep, charset_name, token)) >= sizeof(buf) || n < 0) n = strlen(buf); if (timed_write(fd, buf, n, IO_TIMEOUT) != n && syslog_flag) { syslog(LOG_NOTICE, "write to %s: %m", gethost6(faddr)); return 1; } return 0; } if (token_flag) { gentoken(token, sizeof token); syslog(LOG_NOTICE, "token %s == uid %u (%s)", token, uid, pw->pw_name); if ((n = snprintf(buf, sizeof(buf), "%d , %d : USERID : %s%s%s :%s\r\n", lport, fport, opsys_name, charset_sep, charset_name, token)) >= sizeof(buf) || n < 0) n = strlen(buf); if (timed_write(fd, buf, n, IO_TIMEOUT) != n && syslog_flag) { syslog(LOG_NOTICE, "write to %s: %m", gethost6(faddr)); return 1; } return 0; } if (number_flag) { if ((n = snprintf(buf, sizeof(buf), "%d , %d : USERID : %s%s%s :%u\r\n", lport, fport, opsys_name, charset_sep, charset_name, uid)) >= sizeof(buf) || n < 0) n = strlen(buf); if (timed_write(fd, buf, n, IO_TIMEOUT) != n && syslog_flag) { syslog(LOG_NOTICE, "write to %s: %m", gethost6(faddr)); return 1; } return 0; } if ((n = snprintf(buf, sizeof(buf), "%d , %d : USERID : %s%s%s :%s\r\n", lport, fport, opsys_name, charset_sep, charset_name, pw->pw_name)) >= sizeof(buf) || n < 0) n = strlen(buf); if (timed_write(fd, buf, n, IO_TIMEOUT) != n && syslog_flag) { syslog(LOG_NOTICE, "write to %s: %m", gethost6(faddr)); return 1; } return 0; }
/* This is a wrapped version of the child web server thread */ static void __http_server(struct kqueue *q, struct http_connection *c, struct http_request *r) { struct stat statbuf; int j, file_fd, buflen; long i = 0, ret = 0; char *fstr; char *request_line; char *saveptr; char now[RFC1123_TIME_LEN + 1]; char mod[RFC1123_TIME_LEN + 1]; /* Try and extract a request from the connection. */ ret = extract_request(c, r); /* If there was an error, just destroy the connection, as there is * nothing more we can do with this connection anyway. */ if(ret < 0) { logger(LOG, "Connection reset by peer.", "", c->conn.id); maybe_destroy_connection(q, c); return; } /* If there was no error, but we weren't able to extract a request, finish up * if we are the last one to look at the connection. */ if(ret == 0) { maybe_destroy_connection(q, c); return; } /* Otherwise, just reenqueue the connection so another thread can grab the * next request and start processing it. */ if (!c->should_close) { if(c->burst_length) { c->burst_length--; enqueue_connection_head(q, c); } else { c->burst_length = MAX_BURST; enqueue_connection_tail(q, c); } } /* Attempt to intercept the request and do something special with it. */ struct intercept_buf ib; if (intercept_request(&ib, r)) { /* Send the necessary header info + a blank line */ logger(LOG, "INTERCEPT URL", &request_line[4], c->conn.id); setDateString(NULL, now); setDateString(NULL, mod); sprintf(r->buf, page_data[OK_HEADER], VERSION, now, ib.mime_type, ib.size, mod); serialized_write(c, r->buf, strlen(r->buf)); serialized_write(c, ib.buf, ib.size); free(ib.buf); maybe_destroy_connection(q, c); return; } /* If not intercepted, parse through the extracted request, grabbing only the * first line. */ request_line = strtok_r(r->buf, "\r\n", &saveptr); if (!request_line) { logger(LOG, "Unterminated request buffer.", "", c->conn.id); maybe_destroy_connection(q, c); return; } /* Make sure it's a GET operation */ if(strncmp(request_line, "GET ", 4) && strncmp(request_line, "get ", 4)) { logger(FORBIDDEN, "Only simple GET operation supported", request_line, c->socketfd); serialized_write(c, page_data[FORBIDDEN_PAGE], strlen(page_data[FORBIDDEN_PAGE])); maybe_destroy_connection(q, c); return; } logger(LOG, "Request", request_line, c->conn.id); /* Strip the version info from the request_line */ for(i=4; i<strlen(request_line); i++) { /* String is "GET URL?<query_data> HTTP_VERSION" */ if(request_line[i] == ' ') { request_line[i] = '\0'; break; } } /* Strip all query data from the request_line */ for(i=4; i<strlen(request_line); i++) { /* String is "GET URL?<query_data>" */ if(request_line[i] == '?') { request_line[i] = '\0'; break; } } /* Otherwise, check for illegal parent directory use .. */ for(j=4; j<i-1; j++) { if(request_line[j] == '.' && request_line[j+1] == '.') { logger(FORBIDDEN, "Parent directory (..) path names not supported", request_line, c->socketfd); serialized_write(c, page_data[FORBIDDEN_PAGE], strlen(page_data[FORBIDDEN_PAGE])); maybe_destroy_connection(q, c); return; } } /* Convert no filename to index file */ if(!strncmp(request_line, "GET /\0", 6) || !strncmp(request_line, "get /\0", 6)) strcpy(request_line, "GET /index.html"); /* Work out the file type and check we support it */ buflen=strlen(request_line); fstr = 0; for(i=0; extensions[i].ext != 0; i++) { int len = strlen(extensions[i].ext); if(!strncmp(&request_line[buflen-len], extensions[i].ext, len)) { fstr =extensions[i].filetype; break; } } if(fstr == 0) { logger(FORBIDDEN, "File extension type not supported", request_line, c->socketfd); serialized_write(c, page_data[FORBIDDEN_PAGE], strlen(page_data[FORBIDDEN_PAGE])); maybe_destroy_connection(q, c); return; } /* Open the file for reading */ if((file_fd = open(&request_line[5], O_RDONLY)) == -1) { logger(NOTFOUND, "Failed to open file", &request_line[5], c->socketfd); serialized_write(c, page_data[NOTFOUND_PAGE], strlen(page_data[NOTFOUND_PAGE])); maybe_destroy_connection(q, c); return; } /* Get the File Stats */ fstat(file_fd, &statbuf); /* Prepopulate the request buf with the beginning of the requested file */ ret = read(file_fd, r->buf, sizeof(r->buf)); if (ret < 0) { logger(ERROR, "Failed to read file", "...", 0); close(file_fd); maybe_destroy_connection(q, c); return; } /* Prepare the header info + a blank line */ setDateString(NULL, now); setDateString(&statbuf.st_mtime, mod); sprintf(r->rsp_header, page_data[OK_HEADER], VERSION, now, fstr, statbuf.st_size, mod); logger(LOG, "Header", r->rsp_header, c->conn.id); /* Start sending a response */ logger(LOG, "SEND", &request_line[5], c->conn.id); tpool_inform_blocking(&tpool); mutex_lock(&c->writelock); tpool_inform_unblocked(&tpool); timed_write(c, r->rsp_header, strlen(r->rsp_header)); /* Send the file itself in 8KB chunks - last block may be smaller */ do { if(timed_write(c, r->buf, ret) < 0) logger(LOG, "Write error on socket.", "", c->socketfd); } while((ret = read(file_fd, r->buf, sizeof(r->buf))) > 0); mutex_unlock(&c->writelock); close(file_fd); maybe_destroy_connection(q, c); }