Exemple #1
0
/* Set conn->state to READING when done; otherwise, call a cm_set_. */
static krb5_boolean
service_https_write(krb5_context context, const krb5_data *realm,
                    struct conn_state *conn, struct select_state *selstate)
{
    k5_tls_status st;

    /* If this is our first time in here, set up the SSL context. */
    if (conn->http.tls == NULL && !setup_tls(context, realm, conn, selstate)) {
        kill_conn(context, conn, selstate);
        return FALSE;
    }

    /* Try to transmit our request to the server. */
    st = context->tls->write(context, conn->http.tls, SG_BUF(conn->out.sgp),
                             SG_LEN(conn->out.sgbuf));
    if (st == DONE) {
        TRACE_SENDTO_KDC_HTTPS_SEND(context, &conn->addr);
        cm_read(selstate, conn->fd);
        conn->state = READING;
    } else if (st == WANT_READ) {
        cm_read(selstate, conn->fd);
    } else if (st == WANT_WRITE) {
        cm_write(selstate, conn->fd);
    } else if (st == ERROR_TLS) {
        TRACE_SENDTO_KDC_HTTPS_ERROR_SEND(context, &conn->addr);
        kill_conn(context, conn, selstate);
    }

    return FALSE;
}
Exemple #2
0
/* 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;
}
Exemple #3
0
/* Perform next step in sending.  Return true on usable data. */
static krb5_boolean
service_dispatch(krb5_context context, const krb5_data *realm,
                 struct conn_state *conn, struct select_state *selstate,
                 int ssflags)
{
    /* Check for a socket exception. */
    if (ssflags & SSF_EXCEPTION) {
        kill_conn(context, conn, selstate);
        return FALSE;
    }

    switch (conn->state) {
    case CONNECTING:
        assert(conn->service_connect != NULL);
        return conn->service_connect(context, realm, conn, selstate);
    case WRITING:
        assert(conn->service_write != NULL);
        return conn->service_write(context, realm, conn, selstate);
    case READING:
        assert(conn->service_read != NULL);
        return conn->service_read(context, realm, conn, selstate);
    default:
        abort();
    }
}
Exemple #4
0
/* Sets conn->state to READING when done. */
static krb5_boolean
service_tcp_write(krb5_context context, const krb5_data *realm,
                  struct conn_state *conn, struct select_state *selstate)
{
    ssize_t nwritten;
    SOCKET_WRITEV_TEMP tmp;

    TRACE_SENDTO_KDC_TCP_SEND(context, &conn->addr);
    nwritten = SOCKET_WRITEV(conn->fd, conn->out.sgp, conn->out.sg_count, tmp);
    if (nwritten < 0) {
        TRACE_SENDTO_KDC_TCP_ERROR_SEND(context, &conn->addr, SOCKET_ERRNO);
        kill_conn(context, conn, selstate);
        return FALSE;
    }
    while (nwritten) {
        sg_buf *sgp = conn->out.sgp;
        if ((size_t)nwritten < SG_LEN(sgp)) {
            SG_ADVANCE(sgp, (size_t)nwritten);
            nwritten = 0;
        } else {
            nwritten -= SG_LEN(sgp);
            conn->out.sgp++;
            conn->out.sg_count--;
        }
    }
    if (conn->out.sg_count == 0) {
        /* Done writing, switch to reading. */
        cm_read(selstate, conn->fd);
        conn->state = READING;
    }
    return FALSE;
}
Exemple #5
0
static bool_t Detach_m(
        FlowMan_cl      *self,
        FlowMan_Flow  flow     /* IN */,
        FlowMan_ConnID  cid     /* IN */ )
{
    flowman_st UNUSED *st = self->st;
    flow_t	*f = (flow_t *)flow;
    conn_t	*c = (conn_t *)cid;

    /* blow "c" from connection list */
    if (!DEL_LIST(f->conns, c))
    {
	printf("FlowMan$Detach: unknown CID %p\n", c);
	return False;
    }

    kill_conn(f, c); /* does implicit free() of c */

    /* was this the last connection? */
    if (!f->conns)
    {
	/* garbage collect the TX filter */
	Netif$SetTxFilter(f->intf->card->netif, f->txhdl, NULL);
	PF$Dispose(f->txpf);
	f->txpf = NULL;
	/* but not the RX stuff, cos this flow might get re-used */
    }

    return True;
}
Exemple #6
0
/* Return true on finished data.  Call a cm_read/write function and return
 * false if the TLS layer needs it.  Kill the connection on error. */
static krb5_boolean
https_read_bytes(krb5_context context, struct conn_state *conn,
                 struct select_state *selstate)
{
    size_t bufsize, nread;
    k5_tls_status st;
    char *tmp;
    struct incoming_message *in = &conn->in;

    for (;;) {
        if (in->buf == NULL || in->bufsize - in->pos < 1024) {
            bufsize = in->bufsize ? in->bufsize * 2 : 8192;
            if (bufsize > 1024 * 1024) {
                kill_conn(context, conn, selstate);
                return FALSE;
            }
            tmp = realloc(in->buf, bufsize);
            if (tmp == NULL) {
                kill_conn(context, conn, selstate);
                return FALSE;
            }
            in->buf = tmp;
            in->bufsize = bufsize;
        }

        st = context->tls->read(context, conn->http.tls, &in->buf[in->pos],
                                in->bufsize - in->pos - 1, &nread);
        if (st != DATA_READ)
            break;

        in->pos += nread;
        in->buf[in->pos] = '\0';
    }

    if (st == DONE)
        return TRUE;

    if (st == WANT_READ) {
        cm_read(selstate, conn->fd);
    } else if (st == WANT_WRITE) {
        cm_write(selstate, conn->fd);
    } else if (st == ERROR_TLS) {
        TRACE_SENDTO_KDC_HTTPS_ERROR_RECV(context, &conn->addr);
        kill_conn(context, conn, selstate);
    }
    return FALSE;
}
Exemple #7
0
/* Process events on a UDP socket.  Return true if we get a reply. */
static krb5_boolean
service_udp_read(krb5_context context, const krb5_data *realm,
                 struct conn_state *conn, struct select_state *selstate)
{
    int nread;

    nread = recv(conn->fd, conn->in.buf, conn->in.bufsize, 0);
    if (nread < 0) {
        TRACE_SENDTO_KDC_UDP_ERROR_RECV(context, &conn->addr, SOCKET_ERRNO);
        kill_conn(context, conn, selstate);
        return FALSE;
    }
    conn->in.pos = nread;
    return TRUE;
}
Exemple #8
0
void	watchdog (userT *user)
{
	if ( 
	     ( 
		(time(NULL) - user->time > MAX_IDLE) &&
	       	(user->time) 
	     ) ||
	     (
		(user->errors >= MAX_ERRORS)
	     ) 
	   )	
	{
		kill_conn (user);
		return ;
	}
}		
Exemple #9
0
/* Return true on readable, valid KKDCPP data. */
static krb5_boolean
service_https_read(krb5_context context, const krb5_data *realm,
                   struct conn_state *conn, struct select_state *selstate)
{
    krb5_kkdcp_message *pm = NULL;
    krb5_data buf;
    const char *rep;
    struct incoming_message *in = &conn->in;

    /* Read data through the encryption layer. */
    if (!https_read_bytes(context, conn, selstate))
        return FALSE;

    /* Find the beginning of the response body. */
    rep = strstr(in->buf, "\r\n\r\n");
    if (rep == NULL)
        goto kill_conn;
    rep += 4;

    /* Decode the response. */
    buf = make_data((char *)rep, in->pos - (rep - in->buf));
    if (decode_krb5_kkdcp_message(&buf, &pm) != 0)
        goto kill_conn;

    /* Check and discard the message length at the front of the kerb_message
     * field after decoding.  If it's wrong or missing, something broke. */
    if (pm->kerb_message.length < 4 ||
        load_32_be(pm->kerb_message.data) != pm->kerb_message.length - 4) {
        goto kill_conn;
    }

    /* Replace all of the content that we read back with just the message. */
    memcpy(in->buf, pm->kerb_message.data + 4, pm->kerb_message.length - 4);
    in->pos = pm->kerb_message.length - 4;
    k5_free_kkdcp_message(context, pm);

    return TRUE;

kill_conn:
    TRACE_SENDTO_KDC_HTTPS_ERROR(context, in->buf);
    k5_free_kkdcp_message(context, pm);
    kill_conn(context, conn, selstate);
    return FALSE;
}
static int
service_udp_fd(krb5_context context, struct conn_state *conn,
               struct select_state *selstate, int ssflags)
{
    int nread;

    if (!(ssflags & (SSF_READ|SSF_EXCEPTION)))
        abort();
    if (conn->state != READING)
        abort();

    nread = recv(conn->fd, conn->x.in.buf, conn->x.in.bufsize, 0);
    if (nread < 0) {
        TRACE_SENDTO_KDC_UDP_ERROR_RECV(context, conn, SOCKET_ERRNO);
        kill_conn(conn, selstate, SOCKET_ERRNO);
        return 0;
    }
    conn->x.in.pos = conn->x.in.buf + nread;
    return 1;
}
Exemple #11
0
/* Initialize TCP transport. */
static krb5_boolean
service_tcp_connect(krb5_context context, const krb5_data *realm,
                    struct conn_state *conn, struct select_state *selstate)
{
    /* Check whether the connection succeeded. */
    int e = get_so_error(conn->fd);

    if (e) {
        TRACE_SENDTO_KDC_TCP_ERROR_CONNECT(context, &conn->addr, e);
        kill_conn(context, conn, selstate);
        return FALSE;
    }

    conn->state = WRITING;

    /* Record this connection's timeout for service_fds. */
    if (get_curtime_ms(&conn->endtime) == 0)
        conn->endtime += 10000;

    return conn->service_write(context, realm, conn, selstate);
}
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;
}