CMom::~CMom(){ int iTemp = 0; if (pList){ if (iType == MASTER){ char *szTemp; DWORD dCount; DEBUG_DUMP("CMom::~CMom: Entering Critical Section gCS") szTemp = "\n\n====================================\nCMom::~CMom: WE ARE DELETING CMom! OH MY GOD! NO!!! DON'T DO IT!!!\n\n\n"; WriteConsole(ghDebug, szTemp, strlen(szTemp), &dCount, 0); EnterCriticalSection(&gCS); #ifdef _DEBUG DebugConnection("CMom Mother structure destroying.\n", 0); #endif }else{ /* DELETE THIS BLOCK: If this is not a MASTER then it is a DAUGHTER and a Daughter is only controlled by one thread so we should not need a CS since a thread can not preempt itself. EnterCriticalSection(&gCSMom); */ #ifdef _DEBUG DebugConnection("CMom Daughter structure destroying.\n", 0); #endif } while(iTemp < iNumOfEntries){ if(pList[iTemp]){ switch(iType){ case MASTER: delete (CMom *) pList[iTemp]; pItems[iTemp] = FREE_ITEM; pList[iTemp] = 0; break; case DAUGHTER: // Next line will be used once ODBC_TYPE is an // object class // delete (ODBC_TYPE *) pList[iTemp]; // In the meantime... #ifdef _DEBUG DebugConnection("CMom daughter deleting connetion...", 0); #endif DeleteConn(((ODBC_TYPE *)pList[iTemp])->conn); break; } } iTemp++; } delete [] pList; if (iType == MASTER){ DeleteCriticalSection(&gCSMom); LeaveCriticalSection(&gCS); DEBUG_DUMP("CMom::~CMom: Left Critical Section gCS ") }else{
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); }
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; }