Beispiel #1
0
/**
 * Handles an incoming REGSITER message from a client.
 */
void handle_register(struct pr_group_list_t *group, int hostidx,
                     const unsigned char *message, unsigned meslen,
                     uint32_t src)
{
    const struct register_h *reg;
    const unsigned char *enckey;
    struct pr_destinfo_t *dest;
    int dupmsg;

    reg = (const struct register_h *)message;
    enckey = (const unsigned char *)reg + sizeof(struct register_h);

    if (group->destcount == MAXPROXYDEST) {
        glog1(group, "Rejecting REGISTER from %08X: max destinations exceeded",
                     ntohl(src));
        send_downstream_abort(group, src, "Max destinations exceeded", 0);
        return;
    }
    if ((meslen < (reg->hlen * 4U)) || ((reg->hlen * 4U) <
            sizeof(struct register_h) + ntohs(reg->keyinfo_len))) {
        glog1(group, "Rejecting REGISTER from %08X: invalid message size",
                     ntohl(src));
        send_downstream_abort(group, src, "Invalid message size", 0);
        return;
    }

    if (hostidx == -1) {
        hostidx = add_client(src, group);
    }
    dest = &group->destinfo[hostidx];
    dupmsg = (dest->registered == 1);
    dest->registered = 1;
    dest->regtime.tv_sec = ntohl(reg->tstamp_sec);
    dest->regtime.tv_usec = ntohl(reg->tstamp_usec);

    if (dest->state != PR_CLIENT_REGISTERED) {
        if (group->keytype != KEY_NONE) {
            if (!handle_register_keys(reg, enckey, group, hostidx, src)) {
                return;
            }
        }
        if (!group->client_auth || dest->pubkey.key) {
            dest->state = PR_CLIENT_REGISTERED;
        }
    }

    glog2(group, "Received REGISTER%s from %s", dupmsg ? "+" : "", dest->name);

    if (dest->state == PR_CLIENT_REGISTERED) {
        check_pending(group, hostidx, message);
    }
}
Beispiel #2
0
/**
 * Check for any client that hasn't fully registered.
 * If the abort parameter is set, send an ABORT to the server and client.
 * Returns 1 if any aren't fully registered, 0 if all are registered.
 */
int check_unfinished_clients(int listidx, int abort)
{
    int hostidx, found;
    struct pr_destinfo_t *dest;

    if (group_list[listidx].keytype == KEY_NONE) {
        return 0;
    }

    found = 0;
    for (hostidx = 0; hostidx < group_list[listidx].destcount; hostidx++) {
        dest = &group_list[listidx].destinfo[hostidx];
        if ((group_list[listidx].group_id != 0) &&
                (dest->state != PR_CLIENT_READY)) {
            if (abort) {
                send_downstream_abort(listidx, dest->addr.s_addr,
                        "Client not fully registered at proxy");
                send_upstream_abort(listidx, dest->addr.s_addr,
                        "Client not fully registered at proxy");
            }
            found = 1;
        }
    }
    return found;
}
Beispiel #3
0
/**
 * Check for any client that hasn't fully registered.
 * If the abort parameter is set, send an ABORT to the server and client.
 * Returns 1 if any aren't fully registered, 0 if all are registered.
 */
int check_unfinished_clients(struct pr_group_list_t *group, int abort_session)
{
    int hostidx, found;
    struct pr_destinfo_t *dest;

    if (group->keytype == KEY_NONE) {
        return 0;
    }

    found = 0;
    for (hostidx = 0; hostidx < group->destcount; hostidx++) {
        dest = &group->destinfo[hostidx];
        if ((group->group_id != 0) &&
                (dest->state != PR_CLIENT_READY)) {
            if (abort_session) {
                send_downstream_abort(group, dest->id,
                        "Client not fully registered at proxy", 0);
                send_upstream_abort(group, dest->id,
                        "Client not fully registered at proxy");
            }
            found = 1;
        }
    }
    return found;
}
Beispiel #4
0
/**
 * Handles an ABORT message from a client or server
 * and forwards if necessary.
 */
void handle_abort(int listidx, const struct sockaddr_in *src,
                  const unsigned char *packet)
{
    struct uftp_h *header;
    struct abort_h *abort;
    int upstream, hostidx, found, i;

    header = (struct uftp_h *)packet;
    abort = (struct abort_h *)(packet + sizeof(struct uftp_h));

    upstream = (!memcmp(src, &group_list[listidx].up_addr, sizeof(*src)));
    if (ntohs(header->blsize) != sizeof(struct abort_h)) {
        log(group_list[listidx].group_id, 0,
                "Rejecting ABORT from %s: invalid message size",
                upstream ? "server" : "client");
    }

    if (upstream) {
        for (i = 0, found = 0; (i < interface_count) && !found; i++) {
            if (abort->host == m_interface[i].addr.s_addr) {
                found = 1;
            }
        }

        if ((abort->host == 0) || found) {
            log(group_list[listidx].group_id, 0,
                    "Transfer aborted by server: %s", abort->message);
            if (proxy_type != RESPONSE_PROXY) {
                send_downstream_abort(listidx, 0, abort->message);
            }
            group_cleanup(listidx);
        } else {
            if (proxy_type != RESPONSE_PROXY) {
                send_downstream_abort(listidx, header->srcaddr, abort->message);
            }
        }
    } else {
        if ((hostidx = find_client(listidx, header->srcaddr)) != -1) {
            log(group_list[listidx].group_id, 0, "Transfer aborted by %s: %s",
                    group_list[listidx].destinfo[hostidx].name, abort->message);
        } else {
            log(group_list[listidx].group_id, 0, "Transfer aborted by %s: %s",
                    inet_ntoa(to_addr(header->srcaddr)), abort->message);
        }
        send_upstream_abort(listidx, header->srcaddr, abort->message);
    }
}
Beispiel #5
0
/**
 * Handles an ABORT message from a client or server
 * and forwards if necessary.
 */
void handle_abort(struct pr_group_list_t *group, const union sockaddr_u *src,
                  const unsigned char *message, unsigned meslen,
                  uint32_t src_id)
{
    const struct abort_h *abort_hdr;
    int upstream, hostidx, current;

    abort_hdr = (const struct abort_h *)message;

    upstream = (addr_equal(&group->up_addr, src));
    if (meslen < (abort_hdr->hlen * 4U) ||
            ((abort_hdr->hlen * 4U) < sizeof(struct abort_h))) {
        glog1(group, "Rejecting ABORT from %s: invalid message size",
                     upstream ? "server" : "client");
    }

    if (upstream) {
        if ((abort_hdr->host == 0) || abort_hdr->host == uid ) {
            glog1(group, "Transfer aborted by server: %s", abort_hdr->message);
            current = ((abort_hdr->flags & FLAG_CURRENT_FILE) != 0);
            if (proxy_type != RESPONSE_PROXY) {
                send_downstream_abort(group, 0, abort_hdr->message, current);
            }
            if (!current) {
                group_cleanup(group);
            }
        } else {
            if (proxy_type != RESPONSE_PROXY) {
                send_downstream_abort(group, abort_hdr->host,
                                      abort_hdr->message, 0);
            }
        }
    } else {
        if ((hostidx = find_client(group, src_id)) != -1) {
            glog1(group, "Transfer aborted by %s: %s",
                         group->destinfo[hostidx].name, abort_hdr->message);
        } else {
            glog1(group, "Transfer aborted by %08X: %s",
                         ntohl(src_id), abort_hdr->message);
        }
        send_upstream_abort(group, src_id, abort_hdr->message);
    }
}
Beispiel #6
0
/**
 * Handles an incoming KEYINFO_ACK message from a client
 */
void handle_keyinfo_ack(struct pr_group_list_t *group, int hostidx,
                        const unsigned char *message, unsigned meslen)
{
    const struct keyinfoack_h *keyinfoack;
    unsigned char *verifydata, *verify_hash, *verify_test;
    int verifylen, len, dupmsg;
    unsigned int hashlen;
    struct pr_destinfo_t *dest;

    keyinfoack = (const struct keyinfoack_h *)message;
    dest = &group->destinfo[hostidx];

    if ((meslen < (keyinfoack->hlen * 4U)) ||
            ((keyinfoack->hlen * 4U) < sizeof(struct keyinfoack_h))) {
        glog1(group, "Rejecting KEYINFO_ACK from %s: invalid message size",
                     dest->name);
        send_downstream_abort(group, dest->id, "Invalid message size", 0);
        return;
    }

    if (!(verifydata = build_verify_data(group, hostidx, &verifylen,1))) {
        glog1(group, "Rejecting KEYINFO_ACK from %s: "
                     "error exporting client public key", dest->name);
        return;
    }
    verify_hash = safe_calloc(group->hmaclen, 1);
    verify_test = safe_calloc(VERIFY_LEN + group->hmaclen, 1);
    hash(group->hashtype, verifydata, verifylen, verify_hash, &hashlen);
    PRF(group->hashtype, VERIFY_LEN, group->groupmaster,
            sizeof(group->groupmaster), "client finished",
            verify_hash, hashlen, verify_test, &len);
    if (memcmp(keyinfoack->verify_data, verify_test, VERIFY_LEN)) {
        glog1(group, "Rejecting KEYINFO_ACK from %s: verify data mismatch",
                     dest->name);
        free(verifydata);
        free(verify_hash);
        free(verify_test);
        return;
    }

    free(verifydata);
    free(verify_hash);
    free(verify_test);

    dupmsg = (dest->state == PR_CLIENT_READY);
    glog2(group, "Received KEYINFO_ACK%s from %s", dupmsg ? "+" : "",
                 dest->name);
    dest->state = PR_CLIENT_READY;
    if (!check_unfinished_clients(group, 0)) {
        group->phase = PR_PHASE_RECEIVING;
    }
}
Beispiel #7
0
/**
 * Handles an incoming CLIENT_KEY message from a client.
 */
void handle_clientkey(struct pr_group_list_t *group, int hostidx,
                      const unsigned char *message, unsigned meslen,
                      uint32_t src)
{
    const struct client_key_h *clientkey;
    const unsigned char *keyblob, *verify;
    struct pr_destinfo_t *dest;
    int dupmsg;

    clientkey = (const struct client_key_h *)message;
    keyblob = (const unsigned char *)clientkey + sizeof(struct client_key_h);
    verify = keyblob + ntohs(clientkey->bloblen);

    if (group->destcount == MAXPROXYDEST) {
        glog1(group, "Rejecting CLIENT_KEY from %08X: "
                     "max destinations exceeded", ntohl(src));
        send_downstream_abort(group, src, "Max destinations exceeded", 0);
        return;
    }
    if ((meslen < (clientkey->hlen * 4U)) ||
            ((clientkey->hlen * 4U) < sizeof(struct client_key_h) +
                ntohs(clientkey->bloblen) + ntohs(clientkey->siglen))) {
        glog1(group, "Rejecting CLIENT_KEY from %08X: invalid message size",
                     ntohl(src));
        send_downstream_abort(group, src, "Invalid message size", 0);
        return;
    }
    if ((((group->keyextype == KEYEX_RSA) ||
                    (group->keyextype == KEYEX_ECDH_RSA)) &&
                (keyblob[0] != KEYBLOB_RSA)) ||
            ((group->keyextype == KEYEX_ECDH_ECDSA) &&
             (keyblob[0] != KEYBLOB_EC))) {
        glog1(group, "Rejecting CLIENT_KEY from %08X: invalid keyblob type",
                     ntohl(src));
        send_downstream_abort(group, src, "Invalid keyblob type", 0);
        return;
    }


    if (hostidx == -1) {
        hostidx = add_client(src, group);
    }
    dest = &group->destinfo[hostidx];
    dupmsg = (dest->pubkey.key != 0);

    if (!dest->verified) {
        if (keyblob[0] == KEYBLOB_RSA) {
            if (!import_RSA_key(&dest->pubkey.rsa, keyblob,
                                ntohs(clientkey->bloblen))) {
                glog1(group, "Failed to load client public key");
                send_downstream_abort(group, src,
                                      "Failed to load client public key", 0);
                return;
            }
            dest->pubkeylen = RSA_keylen(dest->pubkey.rsa);
        } else {
            if (!import_EC_key(&dest->pubkey.ec, keyblob,
                               ntohs(clientkey->bloblen), 0)) {
                glog1(group, "Failed to load client public key");
                send_downstream_abort(group, src,
                                      "Failed to load client public key", 0);
                return;
            }
            dest->pubkeylen = ECDSA_siglen(dest->pubkey.ec);
        }
        if (!verify_fingerprint(client_fp, client_fp_count, keyblob,
                                ntohs(clientkey->bloblen), group, src)) {
            glog1(group, "Failed to verify client key fingerprint");
            send_downstream_abort(group, src, 
                                  "Failed to verify client key fingerprint", 0);
            return;
        }
        dest->verified = 1;
    }

    memcpy(dest->verifydata, verify, ntohs(clientkey->siglen));
    dest->verifylen = ntohs(clientkey->siglen);
    if (dest->registered) {
        if (!verify_client_key(group, hostidx)) {
            return;
        }
        dest->state = PR_CLIENT_REGISTERED;
    }

    glog2(group,"Received CLIENT_KEY%s from %s", dupmsg ? "+" : "", dest->name);

    if (dest->state == PR_CLIENT_REGISTERED) {
        // Pass in a dummy REGISTER message to check_pending, since
        // CLIENT_KEY is basically an extension of REGISTER.
        struct register_h reg;
        reg.func = REGISTER;
        check_pending(group, hostidx, (unsigned char *)&reg);
    }
}