/* Return true on usable data. */ static krb5_boolean service_tcp_read(krb5_context context, const krb5_data *realm, struct conn_state *conn, struct select_state *selstate) { ssize_t nread; int e = 0; struct incoming_message *in = &conn->in; if (in->bufsizebytes_read == 4) { /* Reading data. */ nread = SOCKET_READ(conn->fd, &in->buf[in->pos], in->n_left); if (nread <= 0) { e = nread ? SOCKET_ERRNO : ECONNRESET; TRACE_SENDTO_KDC_TCP_ERROR_RECV(context, &conn->addr, e); kill_conn(context, conn, selstate); return FALSE; } in->n_left -= nread; in->pos += nread; if (in->n_left <= 0) return TRUE; } else { /* Reading length. */ nread = SOCKET_READ(conn->fd, in->bufsizebytes + in->bufsizebytes_read, 4 - in->bufsizebytes_read); if (nread <= 0) { e = nread ? SOCKET_ERRNO : ECONNRESET; TRACE_SENDTO_KDC_TCP_ERROR_RECV_LEN(context, &conn->addr, e); kill_conn(context, conn, selstate); return FALSE; } in->bufsizebytes_read += nread; if (in->bufsizebytes_read == 4) { unsigned long len = load_32_be(in->bufsizebytes); /* Arbitrary 1M cap. */ if (len > 1 * 1024 * 1024) { kill_conn(context, conn, selstate); return FALSE; } in->bufsize = in->n_left = len; in->pos = 0; in->buf = malloc(len); if (in->buf == NULL) { kill_conn(context, conn, selstate); return FALSE; } } } return FALSE; }
/*---------------------------------------------------------------------------*/ static int readn( SOCKET fd, char *buf, int n ) { long nleft, nread; nleft = n; while( nleft > 0 ) { nread = SOCKET_READ( fd, buf, nleft ); if( nread < 0 ) { break; } else if( nread == 0 ) { break; } else { nleft -= nread; buf += nread; } } return (n - nleft); }
static int special_read(struct connstruct *cn, void *buf, size_t count) { int res; if (cn->is_ssl) { uint8_t *read_buf; if ((res = ssl_read(cn->ssl, &read_buf)) > SSL_OK) { memcpy(buf, read_buf, res > (int)count ? count : res); } } else { res = SOCKET_READ(cn->networkdesc, buf, count); } return res; }
// Read a line of input from the socket. // static int mod_email_sock_readline(SOCKET sock, UTF8 *buffer, int maxlen) { buffer[0] = '\0'; if (IS_INVALID_SOCKET(sock)) { return 0; } fd_set read_fds; FD_ZERO(&read_fds); FD_SET(sock, &read_fds); // Wait up to 1 second. // struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; // Check for data before giving up. // if (IS_SOCKET_ERROR(select(static_cast<int>(sock+1), &read_fds, NULL, NULL, &tv))) { return 0; } if (!FD_ISSET(sock, &read_fds)) { return 0; } bool done = false; bool possible_close = false; int pos = 0; while ( !done && pos < maxlen) { UTF8 getme[2]; int numread = SOCKET_READ(sock, (char *)&getme[0], 1, 0); if ( IS_SOCKET_ERROR(numread) || 0 == numread) { if (possible_close) { done = true; } else { FD_ZERO(&read_fds); FD_SET(sock, &read_fds); // Wait up to 1 second. // tv.tv_sec = 1; tv.tv_usec = 0; // Check for data before giving up. // if (IS_SOCKET_ERROR(select(static_cast<int>(sock+1), &read_fds, NULL, NULL, &tv))) { done = true; } if (FD_ISSET(sock, &read_fds)) { possible_close = true; } } } else { possible_close = false; if (getme[0] != '\n') { buffer[pos++] = getme[0]; } else { done = true; } } } buffer[pos] = '\0'; return pos; }
/* * Some browsers use a hybrid SSLv2 "client hello" */ int process_sslv23_client_hello(SSL *ssl) { uint8_t *buf = ssl->bm_data; int bytes_needed = ((buf[0] & 0x7f) << 8) + buf[1]; int version = (buf[3] << 4) + buf[4]; int ret = SSL_OK; /* we have already read 3 extra bytes so far */ int read_len = SOCKET_READ(ssl->client_fd, buf, bytes_needed-3); int cs_len = buf[1]; int id_len = buf[3]; int ch_len = buf[5]; int i, j, offset = 8; /* start at first cipher */ int random_offset = 0; DISPLAY_BYTES(ssl, "received %d bytes", buf, read_len, read_len); /* should be v3.1 (TLSv1) or better - we'll send in v3.1 mode anyway */ if (version < 0x31) { return SSL_ERROR_INVALID_VERSION; } add_packet(ssl, buf, read_len); /* connection has gone, so die */ if (bytes_needed < 0) { return SSL_ERROR_CONN_LOST; } /* now work out what cipher suite we are going to use */ for (j = 0; j < NUM_PROTOCOLS; j++) { for (i = 0; i < cs_len; i += 3) { if (ssl_prot_prefs[j] == buf[offset+i]) { ssl->cipher = ssl_prot_prefs[j]; goto server_hello; } } } /* ouch! protocol is not supported */ ret = SSL_ERROR_NO_CIPHER; goto error; server_hello: /* get the session id */ offset += cs_len - 2; /* we've gone 2 bytes past the end */ #ifndef CONFIG_SSL_SKELETON_MODE ssl->session = ssl_session_update(ssl->ssl_ctx->num_sessions, ssl->ssl_ctx->ssl_sessions, ssl, id_len ? &buf[offset] : NULL); #endif /* get the client random data */ offset += id_len; /* random can be anywhere between 16 and 32 bytes long - so it is padded * with 0's to the left */ if (ch_len == 0x10) { random_offset += 0x10; } memcpy(&ssl->dc->client_random[random_offset], &buf[offset], ch_len); ret = send_server_hello_sequence(ssl); error: return ret; }
static int service_tcp_fd(krb5_context context, struct conn_state *conn, struct select_state *selstate, int ssflags) { int e = 0; ssize_t nwritten, nread; if (!(ssflags & (SSF_READ|SSF_WRITE|SSF_EXCEPTION))) abort(); switch (conn->state) { SOCKET_WRITEV_TEMP tmp; case CONNECTING: if (ssflags & SSF_READ) { /* Bad -- the KDC shouldn't be sending to us first. */ e = EINVAL /* ?? */; kill_conn: TRACE_SENDTO_KDC_TCP_DISCONNECT(context, conn); kill_conn(conn, selstate, e); if (e == EINVAL) { closesocket(conn->fd); conn->fd = INVALID_SOCKET; } return e == 0; } if (ssflags & SSF_EXCEPTION) { handle_exception: e = get_so_error(conn->fd); if (e) dprint("socket error on exception fd: %m", e); else dprint("no socket error info available on exception fd"); goto kill_conn; } /* * Connect finished -- but did it succeed or fail? * UNIX sets can_write if failed. * Call getsockopt to see if error pending. * * (For most UNIX systems it works to just try writing the * first time and detect an error. But Bill Dodd at IBM * reports that some version of AIX, SIGPIPE can result.) */ e = get_so_error(conn->fd); if (e) { TRACE_SENDTO_KDC_TCP_ERROR_CONNECT(context, conn, e); dprint("socket error on write fd: %m", e); goto kill_conn; } conn->state = WRITING; goto try_writing; case WRITING: if (ssflags & SSF_READ) { e = E2BIG; /* Bad -- the KDC shouldn't be sending anything yet. */ goto kill_conn; } if (ssflags & SSF_EXCEPTION) goto handle_exception; try_writing: dprint("trying to writev %d (%d bytes) to fd %d\n", conn->x.out.sg_count, ((conn->x.out.sg_count == 2 ? SG_LEN(&conn->x.out.sgp[1]) : 0) + SG_LEN(&conn->x.out.sgp[0])), conn->fd); TRACE_SENDTO_KDC_TCP_SEND(context, conn); nwritten = SOCKET_WRITEV(conn->fd, conn->x.out.sgp, conn->x.out.sg_count, tmp); if (nwritten < 0) { e = SOCKET_ERRNO; TRACE_SENDTO_KDC_TCP_ERROR_SEND(context, conn, e); dprint("failed: %m\n", e); goto kill_conn; } dprint("wrote %d bytes\n", nwritten); while (nwritten) { sg_buf *sgp = conn->x.out.sgp; if ((size_t) nwritten < SG_LEN(sgp)) { SG_ADVANCE(sgp, (size_t) nwritten); nwritten = 0; } else { nwritten -= SG_LEN(sgp); conn->x.out.sgp++; conn->x.out.sg_count--; if (conn->x.out.sg_count == 0 && nwritten != 0) /* Wrote more than we wanted to? */ abort(); } } if (conn->x.out.sg_count == 0) { /* Done writing, switch to reading. */ /* Don't call shutdown at this point because * some implementations cannot deal with half-closed connections.*/ FD_CLR(conn->fd, &selstate->wfds); /* Q: How do we detect failures to send the remaining data to the remote side, since we're in non-blocking mode? Will we always get errors on the reading side? */ dprint("switching fd %d to READING\n", conn->fd); conn->state = READING; conn->x.in.bufsizebytes_read = 0; conn->x.in.bufsize = 0; conn->x.in.buf = 0; conn->x.in.pos = 0; conn->x.in.n_left = 0; } return 0; case READING: if (ssflags & SSF_EXCEPTION) { if (conn->x.in.buf) { free(conn->x.in.buf); conn->x.in.buf = 0; } goto handle_exception; } if (conn->x.in.bufsizebytes_read == 4) { /* Reading data. */ dprint("reading %d bytes of data from fd %d\n", (int) conn->x.in.n_left, conn->fd); nread = SOCKET_READ(conn->fd, conn->x.in.pos, conn->x.in.n_left); if (nread <= 0) { e = nread ? SOCKET_ERRNO : ECONNRESET; free(conn->x.in.buf); conn->x.in.buf = 0; TRACE_SENDTO_KDC_TCP_ERROR_RECV(context, conn, e); goto kill_conn; } conn->x.in.n_left -= nread; conn->x.in.pos += nread; if (conn->x.in.n_left <= 0) { /* We win! */ return 1; } } else { /* Reading length. */ nread = SOCKET_READ(conn->fd, conn->x.in.bufsizebytes + conn->x.in.bufsizebytes_read, 4 - conn->x.in.bufsizebytes_read); if (nread < 0) { TRACE_SENDTO_KDC_TCP_ERROR_RECV_LEN(context, conn, e); e = SOCKET_ERRNO; goto kill_conn; } conn->x.in.bufsizebytes_read += nread; if (conn->x.in.bufsizebytes_read == 4) { unsigned long len = load_32_be (conn->x.in.bufsizebytes); dprint("received length on fd %d is %d\n", conn->fd, (int)len); /* Arbitrary 1M cap. */ if (len > 1 * 1024 * 1024) { e = E2BIG; goto kill_conn; } conn->x.in.bufsize = conn->x.in.n_left = len; conn->x.in.buf = conn->x.in.pos = malloc(len); dprint("allocated %d byte buffer at %p\n", (int) len, conn->x.in.buf); if (conn->x.in.buf == 0) { /* allocation failure */ e = ENOMEM; goto kill_conn; } } } break; default: abort(); } return 0; }