Ejemplo n.º 1
0
static ServerConnectionState *CFTestD_NewConn(ConnectionInfo *info)
{
#if 1
    /* TODO: why do we do this ?  We fail if getsockname() fails, but
     * don't use the information it returned.  Was the intent to use
     * it to fill in conn->ipaddr ? */
    struct sockaddr_storage addr;
    socklen_t size = sizeof(addr);
    int sockfd     = ConnectionInfoSocket(info);
    int sockname   = getsockname(sockfd, (struct sockaddr *)&addr, &size);

    if (sockname == -1)
    {
        Log(LOG_LEVEL_ERR,
            "Could not obtain socket address. (getsockname: '%s')",
            GetErrorStr());
        return NULL;
    }
#endif

    ServerConnectionState *conn = xcalloc(1, sizeof(*conn));
    conn->ctx                   = NULL;
    conn->conn_info             = info;
    conn->encryption_type       = 'c';
    /* Only public files (chmod o+r) accessible to non-root */
    conn->uid = CF_UNKNOWN_OWNER; /* Careful, 0 is root! */
    /* conn->maproot is false: only public files (chmod o+r) are accessible */

    Log(LOG_LEVEL_DEBUG,
        "New connection (socket %d).",
        ConnectionInfoSocket(info));
    return conn;
}
Ejemplo n.º 2
0
Archivo: server.c Proyecto: tzz/core
static void SpawnConnection(EvalContext *ctx, char *ipaddr, ConnectionInfo *info)
{
    ServerConnectionState *conn = NULL;
    int ret;
    pthread_t tid;
    pthread_attr_t threadattrs;

    conn = NewConn(ctx, info);
    int sd_accepted = ConnectionInfoSocket(info);
    strlcpy(conn->ipaddr, ipaddr, CF_MAX_IP_LEN );

    Log(LOG_LEVEL_VERBOSE, "New connection...(from %s, sd %d)",
        conn->ipaddr, sd_accepted);
    Log(LOG_LEVEL_VERBOSE, "Spawning new thread...");

    ret = pthread_attr_init(&threadattrs);
    if (ret != 0)
    {
        Log(LOG_LEVEL_ERR,
            "SpawnConnection: Unable to initialize thread attributes (%s)",
            GetErrorStr());
        goto err2;
    }
    ret = pthread_attr_setdetachstate(&threadattrs, PTHREAD_CREATE_DETACHED);
    if (ret != 0)
    {
        Log(LOG_LEVEL_ERR,
            "SpawnConnection: Unable to set thread to detached state (%s).",
            GetErrorStr());
        goto err1;
    }
    ret = pthread_attr_setstacksize(&threadattrs, 1024 * 1024);
    if (ret != 0)
    {
        Log(LOG_LEVEL_WARNING,
            "SpawnConnection: Unable to set thread stack size (%s).",
            GetErrorStr());
        /* Continue with default thread stack size. */
    }

    ret = pthread_create(&tid, &threadattrs,
                         (void *(*)(void *)) HandleConnection, conn);
    if (ret != 0)
    {
        errno = ret;
        Log(LOG_LEVEL_ERR,
            "Unable to spawn worker thread. (pthread_create: %s)",
            GetErrorStr());
        goto err1;
    }

  err1:
    pthread_attr_destroy(&threadattrs);
  err2:
    if (ret != 0)
    {
        Log(LOG_LEVEL_WARNING, "Thread is being handled from main loop!");
        HandleConnection(conn);
    }
}
Ejemplo n.º 3
0
static void CFTestD_SpawnConnection(
    const char *ipaddr, ConnectionInfo *info, CFTestD_Config *config)
{
    ServerConnectionState *conn = CFTestD_NewConn(info);
    ConnectionInfoSocket(info);
    strlcpy(conn->ipaddr, ipaddr, CF_MAX_IP_LEN);

    Log(LOG_LEVEL_WARNING, "Connection is being handled from main loop!");
    CFTestD_HandleConnection(conn, config);
}
Ejemplo n.º 4
0
static void CFTestD_DeleteConn(ServerConnectionState *conn)
{
    int sd = ConnectionInfoSocket(conn->conn_info);
    if (sd != SOCKET_INVALID)
    {
        cf_closesocket(sd);
    }
    ConnectionInfoDestroy(&conn->conn_info);

    free(conn->session_key);
    free(conn);
}
Ejemplo n.º 5
0
/**
 * @param len is the number of bytes to send, or 0 if buffer is a
 *        '\0'-terminated string so strlen(buffer) can used.
 */
int SendTransaction(const ConnectionInfo *conn_info,
                    const char *buffer, int len, char status)
{
    assert(status == CF_MORE || status == CF_DONE);

    char work[CF_BUFSIZE] = { 0 };
    int ret;

    if (len == 0)
    {
        len = strlen(buffer);
    }

    if (len > CF_BUFSIZE - CF_INBAND_OFFSET)
    {
        Log(LOG_LEVEL_ERR, "SendTransaction: len (%d) > %d - %d",
            len, CF_BUFSIZE, CF_INBAND_OFFSET);
        return -1;
    }

    snprintf(work, CF_INBAND_OFFSET, "%c %d", status, len);

    memcpy(work + CF_INBAND_OFFSET, buffer, len);

    Log(LOG_LEVEL_DEBUG, "SendTransaction header: %s", work);
    LogRaw(LOG_LEVEL_DEBUG, "SendTransaction data: ",
           work + CF_INBAND_OFFSET, len);

    switch(ConnectionInfoProtocolVersion(conn_info))
    {
    case CF_PROTOCOL_CLASSIC:
        ret = SendSocketStream(ConnectionInfoSocket(conn_info), work,
                               len + CF_INBAND_OFFSET);
        break;
    case CF_PROTOCOL_TLS:
        ret = TLSSend(ConnectionInfoSSL(conn_info), work, len + CF_INBAND_OFFSET);
        break;
    default:
        UnexpectedError("SendTransaction: ProtocolVersion %d!",
                        ConnectionInfoProtocolVersion(conn_info));
        ret = -1;
    }

    if (ret == -1)
        return -1;
    else
        return 0;
}
Ejemplo n.º 6
0
/**
 * @brief Set the connection type to CLASSIC or TLS.

 * It is performed by peeking into the TLS connection to read the first bytes,
 * and if it's a CAUTH protocol command use the old protocol loop, else use
 * the TLS protocol loop.
 * This must be the first thing we run on an accepted connection.
 *
 * @return -1 in case of error, 1 otherwise.
 */
int ServerTLSPeek(ConnectionInfo *conn_info)
{
    assert(SSLSERVERCONTEXT != NULL && PRIVKEY != NULL && PUBKEY != NULL);

    assert(ConnectionInfoProtocolVersion(conn_info) == CF_PROTOCOL_UNDEFINED);

    const int peek_size = CF_INBAND_OFFSET + sizeof("CAUTH");

    char buf[peek_size];
    ssize_t got = recv(ConnectionInfoSocket(conn_info), buf, sizeof(buf), MSG_PEEK);
    assert(got <= peek_size);
    if (got < 0)
    {
        assert(got == -1);
        Log(LOG_LEVEL_ERR, "TCP receive error: %s", GetErrorStr());
        return -1;
    }
    else if (got == 0)
    {
        Log(LOG_LEVEL_INFO,
            "Peer closed TCP connection without sending data!");
        return -1;
    }
    else if (got < peek_size)
    {
        Log(LOG_LEVEL_INFO,
            "Peer sent only %zd bytes! Considering the protocol as Classic",
            got);
        ConnectionInfoSetProtocolVersion(conn_info, CF_PROTOCOL_CLASSIC);
    }
    else if (memcmp(&buf[CF_INBAND_OFFSET], "CAUTH", strlen("CAUTH")) == 0)
    {
        Log(LOG_LEVEL_VERBOSE,
            "Peeked CAUTH in TCP stream, considering the protocol as Classic");
        ConnectionInfoSetProtocolVersion(conn_info, CF_PROTOCOL_CLASSIC);
    }
    else                                   /* got==peek_size && not "CAUTH" */
    {
        Log(LOG_LEVEL_VERBOSE,
            "Peeked nothing important in TCP stream, considering the protocol as TLS");
        ConnectionInfoSetProtocolVersion(conn_info, CF_PROTOCOL_TLS);
    }
    LogRaw(LOG_LEVEL_DEBUG, "Peeked data: ", buf, got);

    return 1;
}
Ejemplo n.º 7
0
Archivo: server.c Proyecto: lra/core
/**
 * @note This function is thread-safe. Do NOT wrap it with mutex!
 */
static void DeleteConn(ServerConnectionState *conn)
{
    cf_closesocket(ConnectionInfoSocket(conn->conn_info));
    ConnectionInfoDestroy(&conn->conn_info);
    free(conn->session_key);

    if (conn->ipaddr != NULL)
    {
        if (ThreadLock(cft_count))
        {
            DeleteItemMatching(&SV.connectionlist, conn->ipaddr);
            ThreadUnlock(cft_count);
        }
    }

    *conn = (ServerConnectionState) {0};
    free(conn);
}
Ejemplo n.º 8
0
/**
 * We directly initiate a TLS handshake with the server. If the server is old
 * version (does not speak TLS) the connection will be denied.
 * @note the socket file descriptor in #conn_info must be connected and *not*
 *       non-blocking
 * @return -1 in case of error
 */
int TLSTry(ConnectionInfo *conn_info)
{
    /* SSL Context might not be initialised up to now due to lack of keys, as
     * they might be generated as part of the policy (e.g. failsafe.cf). */
    if (!TLSClientInitialize())
    {
        return -1;
    }
    assert(SSLCLIENTCONTEXT != NULL && PRIVKEY != NULL && PUBKEY != NULL);

    ConnectionInfoSetSSL(conn_info, SSL_new(SSLCLIENTCONTEXT));
    SSL *ssl = ConnectionInfoSSL(conn_info);
    if (ssl == NULL)
    {
        Log(LOG_LEVEL_ERR, "SSL_new: %s",
            ERR_reason_error_string(ERR_get_error()));
        return -1;
    }

    /* Pass conn_info inside the ssl struct for TLSVerifyCallback(). */
    SSL_set_ex_data(ssl, CONNECTIONINFO_SSL_IDX, conn_info);

    /* Initiate the TLS handshake over the already open TCP socket. */
    SSL_set_fd(ssl, ConnectionInfoSocket(conn_info));

    int ret = SSL_connect(ssl);
    if (ret <= 0)
    {
        TLSLogError(ssl, LOG_LEVEL_ERR,
                    "Failed to establish TLS connection", ret);
        return -1;
    }

    Log(LOG_LEVEL_VERBOSE, "TLS cipher negotiated: %s, %s",
        SSL_get_cipher_name(ssl),
        SSL_get_cipher_version(ssl));
    Log(LOG_LEVEL_VERBOSE, "TLS session established, checking trust...");

    return 0;
}
Ejemplo n.º 9
0
Archivo: server.c Proyecto: tzz/core
static void *HandleConnection(ServerConnectionState *conn)
{
    int ret;
    char output[CF_BUFSIZE];

    /* Set logging prefix to be the IP address for all of thread's lifetime. */

    /* Should be valid for all lifetime of the thread. Just make sure that
     * after calling DeleteConn(), you exit right away. */
    LoggingPrivContext log_ctx = {
        .log_hook = LogHook,
        .param = conn->ipaddr
    };

    LoggingPrivSetContext(&log_ctx);

    if (!ThreadLock(cft_server_children))
    {
        DeleteConn(conn);
        return NULL;
    }

    ACTIVE_THREADS++;

    if (ACTIVE_THREADS >= CFD_MAXPROCESSES)
    {
        ACTIVE_THREADS--;

        if (TRIES++ > MAXTRIES) /* When to say we're hung / apoptosis threshold */
        {
            Log(LOG_LEVEL_ERR, "Server seems to be paralyzed. DOS attack? Committing apoptosis...");
            FatalError(conn->ctx, "Terminating");
        }

        if (!ThreadUnlock(cft_server_children))
        {
        }

        Log(LOG_LEVEL_ERR, "Too many threads (>=%d) -- increase server maxconnections?", CFD_MAXPROCESSES);
        snprintf(output, CF_BUFSIZE, "BAD: Server is currently too busy -- increase maxconnections or splaytime?");
        SendTransaction(conn->conn_info, output, 0, CF_DONE);
        DeleteConn(conn);
        return NULL;
    }
    else
    {
        ThreadUnlock(cft_server_children);
    }

    TRIES = 0;                  /* As long as there is activity, we're not stuck */

    DisableSendDelays(ConnectionInfoSocket(conn->conn_info));

    struct timeval tv = {
        .tv_sec = CONNTIMEOUT * 20,
    };
    SetReceiveTimeout(ConnectionInfoSocket(conn->conn_info), &tv);

    if (ConnectionInfoConnectionStatus(conn->conn_info) != CF_CONNECTION_ESTABLISHED)
    {
        /* Decide the protocol used. */
        ret = ServerTLSPeek(conn->conn_info);
        if (ret == -1)
        {
            DeleteConn(conn);
            return NULL;
        }
    }

    switch (ConnectionInfoProtocolVersion(conn->conn_info))
    {

    case CF_PROTOCOL_CLASSIC:
    {
        while (BusyWithClassicConnection(conn->ctx, conn))
        {
        }
        break;
    }

    case CF_PROTOCOL_TLS:
    {
        ret = ServerTLSSessionEstablish(conn);
        if (ret == -1)
        {
            DeleteConn(conn);
            return NULL;
        }

        while (BusyWithNewProtocol(conn->ctx, conn))
        {
        }
        break;
    }

    default:
        UnexpectedError("HandleConnection: ProtocolVersion %d!",
                        ConnectionInfoProtocolVersion(conn->conn_info));
    }

    Log(LOG_LEVEL_INFO, "Connection closed, terminating thread",
        conn->ipaddr);

    if (!ThreadLock(cft_server_children))
    {
        DeleteConn(conn);
        return NULL;
    }

    ACTIVE_THREADS--;

    if (!ThreadUnlock(cft_server_children))
    {
    }

    DeleteConn(conn);
    return NULL;
}


/***************************************************************/
/* Toolkit/Class: conn                                         */
/***************************************************************/

static ServerConnectionState *NewConn(EvalContext *ctx, ConnectionInfo *info)
{
    ServerConnectionState *conn = NULL;
    struct sockaddr_storage addr;
    socklen_t size = sizeof(addr);

    if (getsockname(ConnectionInfoSocket(info), (struct sockaddr *)&addr, &size) == -1)
    {
        Log(LOG_LEVEL_ERR, "Could not obtain socket address. (getsockname: '%s')", GetErrorStr());
        return NULL;
    }

    conn = xcalloc(1, sizeof(*conn));
    conn->ctx = ctx;
    conn->conn_info = info;
    conn->id_verified = false;
    conn->rsa_auth = false;
    conn->hostname[0] = '\0';
    conn->ipaddr[0] = '\0';
    conn->username[0] = '\0';
    conn->session_key = NULL;
    conn->encryption_type = 'c';
    conn->maproot = false;      /* Only public files (chmod o+r) accessible */

    Log(LOG_LEVEL_DEBUG, "New socket %d", ConnectionInfoSocket(info));

    return conn;
}

/***************************************************************/

static void DeleteConn(ServerConnectionState *conn)
{
    cf_closesocket(ConnectionInfoSocket(conn->conn_info));
    ConnectionInfoDestroy(&conn->conn_info);
    free(conn->session_key);
    if (conn->ipaddr != NULL)
    {
        if (!ThreadLock(cft_count))
        {
            return;
        }

        DeleteItemMatching(&SV.connectionlist, MapAddress(conn->ipaddr));

        if (!ThreadUnlock(cft_count))
        {
            return;
        }
    }

    *conn = (ServerConnectionState) {0};
    free(conn);
}
Ejemplo n.º 10
0
Archivo: server.c Proyecto: tzz/core
void ServerEntryPoint(EvalContext *ctx, char *ipaddr, ConnectionInfo *info)
{
    char intime[64];
    time_t now;

    Log(LOG_LEVEL_VERBOSE,
        "Obtained IP address of '%s' on socket %d from accept",
        ipaddr, ConnectionInfoSocket(info));

    if ((SV.nonattackerlist) && (!IsMatchItemIn(SV.nonattackerlist, MapAddress(ipaddr))))
    {
        Log(LOG_LEVEL_ERR, "Not allowing connection from non-authorized IP '%s'", ipaddr);
        cf_closesocket(ConnectionInfoSocket(info));
        ConnectionInfoDestroy(&info);
        return;
    }

    if (IsMatchItemIn(SV.attackerlist, MapAddress(ipaddr)))
    {
        Log(LOG_LEVEL_ERR, "Denying connection from non-authorized IP '%s'", ipaddr);
        cf_closesocket(ConnectionInfoSocket(info));
        ConnectionInfoDestroy(&info);
        return;
    }

    if ((now = time((time_t *) NULL)) == -1)
       {
       now = 0;
       }

    PurgeOldConnections(&SV.connectionlist, now);

    if (!IsMatchItemIn(SV.multiconnlist, MapAddress(ipaddr)))
    {
        if (!ThreadLock(cft_count))
        {
            return;
        }

        if (IsItemIn(SV.connectionlist, MapAddress(ipaddr)))
        {
            ThreadUnlock(cft_count);
            Log(LOG_LEVEL_ERR, "Denying repeated connection from '%s'", ipaddr);
            cf_closesocket(ConnectionInfoSocket(info));
            ConnectionInfoDestroy(&info);
            return;
        }

        ThreadUnlock(cft_count);
    }

    if (SV.logconns)
    {
        Log(LOG_LEVEL_INFO, "Accepting connection from %s", ipaddr);
    }
    else
    {
        Log(LOG_LEVEL_INFO, "Accepting connection from %s", ipaddr);
    }

    snprintf(intime, 63, "%d", (int) now);

    if (!ThreadLock(cft_count))
    {
        cf_closesocket(ConnectionInfoSocket(info));
        ConnectionInfoDestroy(&info);
        return;
    }

    PrependItem(&SV.connectionlist, MapAddress(ipaddr), intime);

    if (!ThreadUnlock(cft_count))
    {
        cf_closesocket(ConnectionInfoSocket(info));
        ConnectionInfoDestroy(&info);
        return;
    }

    SpawnConnection(ctx, ipaddr, info);

}
Ejemplo n.º 11
0
/**
 * @brief Accept a TLS connection and authenticate and identify.
 * @note Various fields in #conn are set, like username and keyhash.
 */
int ServerTLSSessionEstablish(ServerConnectionState *conn)
{
    int ret;

    if (ConnectionInfoConnectionStatus(conn->conn_info) != CF_CONNECTION_ESTABLISHED)
    {
        assert(ConnectionInfoSSL(conn->conn_info) == NULL);
        SSL *ssl = SSL_new(SSLSERVERCONTEXT);
        if (ssl == NULL)
        {
            Log(LOG_LEVEL_ERR, "SSL_new: %s",
                TLSErrorString(ERR_get_error()));
            return -1;
        }
        ConnectionInfoSetSSL(conn->conn_info, ssl);

        /* Pass conn_info inside the ssl struct for TLSVerifyCallback(). */
        SSL_set_ex_data(ssl, CONNECTIONINFO_SSL_IDX, conn->conn_info);

        /* Now we are letting OpenSSL take over the open socket. */
        SSL_set_fd(ssl, ConnectionInfoSocket(conn->conn_info));

        ret = SSL_accept(ssl);
        if (ret <= 0)
        {
            TLSLogError(ssl, LOG_LEVEL_ERR,
                        "Failed to accept TLS connection", ret);
            return -1;
        }

        Log(LOG_LEVEL_VERBOSE, "TLS cipher negotiated: %s, %s",
            SSL_get_cipher_name(ssl),
            SSL_get_cipher_version(ssl));
        Log(LOG_LEVEL_VERBOSE, "TLS session established, checking trust...");

        /* Send/Receive "CFE_v%d" version string, agree on version, receive
           identity (username) of peer. */
        char username[sizeof(conn->username)] = "";
        bool b = ServerIdentificationDialog(conn->conn_info,
                                            username, sizeof(username));
        if (b != true)
        {
            return -1;
        }

        /* We *now* (maybe a bit late) verify the key that the client sent us in
         * the TLS handshake, since we need the username to do so. TODO in the
         * future store keys irrelevant of username, so that we can match them
         * before IDENTIFY. */
        ret = TLSVerifyPeer(conn->conn_info, conn->ipaddr, username);
        if (ret == -1)                                      /* error */
        {
            return -1;
        }

        if (ret == 1)                                    /* trusted key */
        {
            Log(LOG_LEVEL_VERBOSE,
                "%s: Client is TRUSTED, public key MATCHES stored one.",
                KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
        }

        if (ret == 0)                                  /* untrusted key */
        {
            if ((SV.trustkeylist != NULL) &&
                (IsMatchItemIn(SV.trustkeylist, conn->ipaddr)))
            {
                Log(LOG_LEVEL_VERBOSE,
                    "Peer was found in \"trustkeysfrom\" list");
                Log(LOG_LEVEL_NOTICE, "Trusting new key: %s",
                    KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));

                SavePublicKey(username, KeyPrintableHash(conn->conn_info->remote_key),
                              KeyRSA(ConnectionInfoKey(conn->conn_info)));
            }
            else
            {
                Log(LOG_LEVEL_NOTICE,
                    "TRUST FAILED, peer presented an untrusted key, dropping connection!");
                Log(LOG_LEVEL_VERBOSE,
                    "Add peer to \"trustkeysfrom\" if you really want to start trusting this new key.");
                return -1;
            }
        }

        /* All checks succeeded, set conn->uid (conn->sid for Windows)
         * according to the received USERNAME identity. */
        SetConnIdentity(conn, username);

        /* No CAUTH, SAUTH in non-classic protocol. */
        conn->user_data_set = 1;
        conn->rsa_auth = 1;

        LastSaw1(conn->ipaddr, KeyPrintableHash(ConnectionInfoKey(conn->conn_info)),
                 LAST_SEEN_ROLE_ACCEPT);

        ServerSendWelcome(conn);
    }
    return 1;
}
Ejemplo n.º 12
0
/**
 *  @return 0 in case of socket closed, -1 in case of other error, or
 *          >0 the number of bytes read.
 */
int ReceiveTransaction(const ConnectionInfo *conn_info, char *buffer, int *more)
{
    char proto[CF_INBAND_OFFSET + 1] = { 0 };
    char status = 'x';
    unsigned int len = 0;
    int ret;

    /* Get control channel. */
    switch(ConnectionInfoProtocolVersion(conn_info))
    {
    case CF_PROTOCOL_CLASSIC:
        ret = RecvSocketStream(ConnectionInfoSocket(conn_info), proto, CF_INBAND_OFFSET);
        break;
    case CF_PROTOCOL_TLS:
        ret = TLSRecv(ConnectionInfoSSL(conn_info), proto, CF_INBAND_OFFSET);
        break;
    default:
        UnexpectedError("ReceiveTransaction: ProtocolVersion %d!",
                        ConnectionInfoProtocolVersion(conn_info));
        ret = -1;
    }
    if (ret == -1 || ret == 0)
        return ret;

    LogRaw(LOG_LEVEL_DEBUG, "ReceiveTransaction header: ", proto, ret);

    ret = sscanf(proto, "%c %u", &status, &len);
    if (ret != 2)
    {
        Log(LOG_LEVEL_ERR,
            "ReceiveTransaction: Bad packet -- bogus header: %s", proto);
        return -1;
    }
    if (len > CF_BUFSIZE - CF_INBAND_OFFSET)
    {
        Log(LOG_LEVEL_ERR,
            "ReceiveTransaction: Bad packet -- too long (len=%d)", len);
        return -1;
    }
    if (status != CF_MORE && status != CF_DONE)
    {
        Log(LOG_LEVEL_ERR,
            "ReceiveTransaction: Bad packet -- bogus header (more='%c')",
            status);
        return -1;
    }

    if (more != NULL)
    {
        switch (status)
        {
        case CF_MORE:
                *more = true;
                break;
        case CF_DONE:
                *more = false;
                break;
        default:
            ProgrammingError("Unreachable, "
                             "bogus headers have already been checked!");
        }
    }

    /* Get data. */
    switch(ConnectionInfoProtocolVersion(conn_info))
    {
    case CF_PROTOCOL_CLASSIC:
        ret = RecvSocketStream(ConnectionInfoSocket(conn_info), buffer, len);
        break;
    case CF_PROTOCOL_TLS:
        ret = TLSRecv(ConnectionInfoSSL(conn_info), buffer, len);
        break;
    default:
        UnexpectedError("ReceiveTransaction: ProtocolVersion %d!",
                        ConnectionInfoProtocolVersion(conn_info));
        ret = -1;
    }

    LogRaw(LOG_LEVEL_DEBUG, "ReceiveTransaction data: ", buffer, ret);

    return ret;
}
Ejemplo n.º 13
0
Archivo: server.c Proyecto: lra/core
void ServerEntryPoint(EvalContext *ctx, const char *ipaddr, ConnectionInfo *info)
{
    time_t now;

    Log(LOG_LEVEL_VERBOSE,
        "Obtained IP address of '%s' on socket %d from accept",
        ipaddr, ConnectionInfoSocket(info));

    /* TODO change nonattackerlist, attackerlist and especially connectionlist
     *      to binary searched lists, or remove them from the main thread! */
    if ((SV.nonattackerlist) && (!IsMatchItemIn(SV.nonattackerlist, ipaddr)))
    {
        Log(LOG_LEVEL_ERR,
            "Remote host '%s' not in allowconnects, denying connection",
            ipaddr);
        cf_closesocket(ConnectionInfoSocket(info));
        ConnectionInfoDestroy(&info);
        return;
    }

    if (IsMatchItemIn(SV.attackerlist, ipaddr))
    {
        Log(LOG_LEVEL_ERR,
            "Remote host '%s' is in denyconnects, denying connection",
            ipaddr);
        cf_closesocket(ConnectionInfoSocket(info));
        ConnectionInfoDestroy(&info);
        return;
    }

    if ((now = time(NULL)) == -1)
    {
       now = 0;
    }

    PurgeOldConnections(&SV.connectionlist, now);

    if (!IsMatchItemIn(SV.multiconnlist, ipaddr))
    {
        if (!ThreadLock(cft_count))
        {
            cf_closesocket(ConnectionInfoSocket(info));
            ConnectionInfoDestroy(&info);
            return;
        }

        if (IsItemIn(SV.connectionlist, ipaddr))
        {
            ThreadUnlock(cft_count);
            Log(LOG_LEVEL_ERR,
                "Remote host '%s' is not in allowallconnects, denying second simultaneous connection",
                ipaddr);
            cf_closesocket(ConnectionInfoSocket(info));
            ConnectionInfoDestroy(&info);
            return;
        }

        ThreadUnlock(cft_count);
    }

    char intime[PRINTSIZE(now)];
    snprintf(intime, sizeof(intime), "%jd", (intmax_t) now);

    if (!ThreadLock(cft_count))
    {
        cf_closesocket(ConnectionInfoSocket(info));
        ConnectionInfoDestroy(&info);
        return;
    }

    PrependItem(&SV.connectionlist, ipaddr, intime);
    ThreadUnlock(cft_count);

    SpawnConnection(ctx, ipaddr, info);
}
Ejemplo n.º 14
0
Archivo: server.c Proyecto: lra/core
static void *HandleConnection(void *c)
{
    ServerConnectionState *conn = c;
    int ret;

    /* Set logging prefix to be the IP address for all of thread's lifetime. */

    /* This stack-allocated struct should be valid for all the lifetime of the
     * thread. Just make sure that after calling DeleteConn() (which frees
     * ipaddr), you exit the thread right away. */
    LoggingPrivContext log_ctx = {
        .log_hook = LogHook,
        .param = conn->ipaddr
    };
    LoggingPrivSetContext(&log_ctx);

    Log(LOG_LEVEL_INFO, "Accepting connection");

    /* We test if number of active threads is greater than max, if so we deny
       connection, if it happened too many times within a short timeframe then we
       kill ourself.TODO this test should be done *before* spawning the thread. */
    ret = ThreadLock(cft_server_children);
    if (!ret)
    {
        Log(LOG_LEVEL_ERR, "Unable to thread-lock, closing connection!");
        goto ret2;
    }
    else if (ACTIVE_THREADS > CFD_MAXPROCESSES)
    {
        if (TRIES > MAXTRIES)
        {
            /* This happens when no thread was freed while we had to drop 5
             * (or maxconnections/3) consecutive connections, because none of
             * the existing threads finished. */
            Log(LOG_LEVEL_CRIT,
                "Server seems to be paralyzed. DOS attack? "
                "Committing apoptosis...");
            ThreadUnlock(cft_server_children);
            FatalError(conn->ctx, "Terminating");
        }

        TRIES++;
        Log(LOG_LEVEL_ERR,
            "Too many threads (%d > %d), dropping connection! "
            "Increase server maxconnections?",
            ACTIVE_THREADS, CFD_MAXPROCESSES);

        ThreadUnlock(cft_server_children);
        goto ret2;
    }

    ACTIVE_THREADS++;
    TRIES = 0;
    ThreadUnlock(cft_server_children);

    DisableSendDelays(ConnectionInfoSocket(conn->conn_info));

    /* 20 times the connect() timeout should be enough to avoid MD5
     * computation timeouts on big files on old slow Solaris 8 machines. */
    SetReceiveTimeout(ConnectionInfoSocket(conn->conn_info),
                      CONNTIMEOUT * 20 * 1000);

    if (ConnectionInfoConnectionStatus(conn->conn_info) != CF_CONNECTION_ESTABLISHED)
    {
        /* Decide the protocol used. */
        ret = ServerTLSPeek(conn->conn_info);
        if (ret == -1)
        {
            goto ret1;
        }
    }

    ProtocolVersion protocol_version = ConnectionInfoProtocolVersion(conn->conn_info);
    if (protocol_version == CF_PROTOCOL_LATEST)
    {
        ret = ServerTLSSessionEstablish(conn);
        if (ret == -1)
        {
            goto ret1;
        }
    }
    else if (protocol_version < CF_PROTOCOL_LATEST &&
             protocol_version > CF_PROTOCOL_UNDEFINED)
    {
        /* This connection is legacy protocol. Do we allow it? */
        if (SV.allowlegacyconnects != NULL &&           /* By default we do */
            !IsMatchItemIn(SV.allowlegacyconnects, conn->ipaddr))
        {
            Log(LOG_LEVEL_INFO,
                "Connection is not using latest protocol, denying");
            goto ret1;
        }
    }
    else
    {
        UnexpectedError("HandleConnection: ProtocolVersion %d!",
                        ConnectionInfoProtocolVersion(conn->conn_info));
        goto ret1;
    }


    /* =========================  MAIN LOOPS  ========================= */
    if (protocol_version >= CF_PROTOCOL_TLS)
    {
        /* New protocol does DNS reverse look up of the connected
         * IP address, to check hostname access_rules. */
        if (NEED_REVERSE_LOOKUP)
        {
            ret = getnameinfo((const struct sockaddr *) &conn->conn_info->ss,
                              conn->conn_info->ss_len,
                              conn->revdns, sizeof(conn->revdns),
                              NULL, 0, NI_NAMEREQD);
            if (ret != 0)
            {
                Log(LOG_LEVEL_INFO,
                    "Reverse lookup failed (getnameinfo: %s)!",
                    gai_strerror(ret));
            }
            else
            {
                Log(LOG_LEVEL_INFO,
                    "Hostname (reverse looked up): %s",
                    conn->revdns);
            }
        }

        while (BusyWithNewProtocol(conn->ctx, conn))
        {
        }
    }
    else if (protocol_version == CF_PROTOCOL_CLASSIC)
    {
        while (BusyWithClassicConnection(conn->ctx, conn))
        {
        }
    }
    /* ============================================================ */


    Log(LOG_LEVEL_INFO, "Connection closed, terminating thread");

  ret1:
    ThreadLock(cft_server_children);
    ACTIVE_THREADS--;
    ThreadUnlock(cft_server_children);

  ret2:
    DeleteConn(conn);
    return NULL;
}


/***************************************************************/
/* Toolkit/Class: conn                                         */
/***************************************************************/

static ServerConnectionState *NewConn(EvalContext *ctx, ConnectionInfo *info)
{
    ServerConnectionState *conn = NULL;
    struct sockaddr_storage addr;
    socklen_t size = sizeof(addr);

    if (getsockname(ConnectionInfoSocket(info), (struct sockaddr *)&addr, &size) == -1)
    {
        Log(LOG_LEVEL_ERR, "Could not obtain socket address. (getsockname: '%s')", GetErrorStr());
        return NULL;
    }

    conn = xcalloc(1, sizeof(*conn));
    conn->ctx = ctx;
    conn->conn_info = info;
    conn->user_data_set = false;
    conn->rsa_auth = false;
    conn->hostname[0] = '\0';
    conn->ipaddr[0] = '\0';
    conn->username[0] = '\0';
    conn->session_key = NULL;
    conn->encryption_type = 'c';
    conn->maproot = false;      /* Only public files (chmod o+r) accessible */
    conn->revdns[0] = '\0';

    Log(LOG_LEVEL_DEBUG, "New socket %d", ConnectionInfoSocket(info));

    return conn;
}