/* * ---------------------------------------------------------------- * Night Light IRC Proxy - Ident Daemon - Listener Functions * ---------------------------------------------------------------- * Copyright (C) 1997-2007 Jonas Kvinge * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Last modified by: * Jonas Kvinge (25.11.2007) * */ #define IDENT_LISTEN_C #define NEED_SYS_TYPES_H 1 /* Extra types */ #define NEED_SYS_PARAM_H 1 /* Some systems need this */ #define NEED_LIMITS_H 0 /* Kernel limits */ #define NEED_STDARG_H 1 /* va_list, etc */ #define NEED_ERRNO_H 1 /* errno */ #define NEED_CTYPE_H 1 /* isdigit(), etc */ #define NEED_NETINET_IN_H 1 /* in_addr, sockaddr_in, etc */ #define NEED_ARPA_INET_H 1 /* inet_ntoa(), inet_aton(), etc */ #define NEED_STDIO_H 1 /* Standard C UNIX functions */ #define NEED_STDLIB_H 1 /* malloc(), exit(), atoi(), etc */ #define NEED_TIME_H 1 /* time(), etc */ #define NEED_SYSCTL_H 0 /* sysctl(), etc */ #define NEED_SYS_STAT_H 0 /* chmod(), mkdir(), etc */ #define NEED_SYS_UIO_H 0 /* iovec, etc */ #define NEED_FCNTL_H 1 /* open(), creat(), fcntl(), etc */ #define NEED_SYS_IOCTL_H 1 /* ioctl(), etc */ #define NEED_SYS_FILIO_H 1 /* Solaris need this for ioctl(), etc */ #define NEED_UNISTD_H 1 /* Unix standard functions */ #define NEED_STRING_H 1 /* C string functions */ #define NEED_SIGNAL_H 0 /* Signal functions */ #define NEED_SYS_SOCKET_H 1 /* Socket functions */ #define NEED_NETDB_H 1 /* Network database functions */ #define NEED_ARPA_NAMESER_H 0 /* Nameserver definitions */ #define NEED_GETUSERPW_HEADERS 0 /* Functions to retrive system passwords */ #define NEED_ARES 1 /* Functions needed for ares */ #define NEED_SSL 0 /* Needed for SSL support */ #include "includes.h" #include "ident_listen.h" #include "ident_conn.h" /* VARIABLES - JONAS (03.07.2003) */ struct IdentListen_Struct *IdentListen_Head = NULL; struct IdentListen_Struct *IdentListen_Tail = NULL; unsigned long int G_Ident_Listens = 0; #if ARES extern ares_channel Ares_Channel; #endif /* IDENT_LISTEN_ADD FUNCTION - JONAS (03.07.2003) */ struct IdentListen_Struct *ident_listen_add(const char *const HostPT, const unsigned long int Port) { struct IdentListen_Struct *IdentListenS = NULL; struct IdentListen_Struct *IdentListen_NEW = NULL; assert(HostPT != NULL); IdentListenS = ident_get(HostPT, Port); if (IdentListenS != NULL) { aerrno = AEEXISTS; return(IdentListenS); } IdentListen_NEW = malloc(sizeof(struct IdentListen_Struct)); if (IdentListen_NEW == NULL) { aerrno = AEMALLOC; return(NULL); } memset(IdentListen_NEW, 0, sizeof(struct IdentListen_Struct)); IdentListen_NEW->Host = strdup(HostPT); if (IdentListen_NEW->Host == NULL) { free(IdentListen_NEW); aerrno = AEMALLOC; return(NULL); } IdentListen_NEW->PortH = Port; IdentListen_NEW->PortN = htons(Port); if (IdentListen_Head == NULL) { IdentListen_Head = IdentListen_NEW; IdentListen_Tail = IdentListen_NEW; } else { IdentListenS = IdentListen_Tail; IdentListenS->Next = IdentListen_NEW; IdentListen_NEW->Prev = IdentListenS; IdentListen_Tail = IdentListen_NEW; } G_Ident_Listens++; aerrno = AESUCCESS; return(IdentListen_NEW); } /* IDENT_LISTEN_REM FUNCTION - JONAS (03.07.2003) */ void ident_listen_rem(struct IdentListen_Struct *IdentListenS) { assert(IdentListenS != NULL); if (IdentListenS->Prev == NULL) { IdentListen_Head = IdentListenS->Next; } else { IdentListenS->Prev->Next = IdentListenS->Next; } if (IdentListenS->Next == NULL) { IdentListen_Tail = IdentListenS->Prev; } else { IdentListenS->Next->Prev = IdentListenS->Prev; } ident_listen_init(IdentListenS); free(IdentListenS->Host); free(IdentListenS); G_Ident_Listens--; } /* IDENT_LISTEN_INIT FUNCTION - JONAS (03.07.2003) */ void ident_listen_init(struct IdentListen_Struct *IdentListenS) { assert(IdentListenS != NULL); IdentListenS->Flags = 0; FREE(IdentListenS->HostIPS); memset(&IdentListenS->INAddr, 0, sizeof(IdentListenS->INAddr)); #if IPV6_SUPPORT memset(&IdentListenS->INAddr6, 0, sizeof(IdentListenS->INAddr6)); #endif IdentListenS->PortH = 0; IdentListenS->PortN = 0; IdentListenS->FD = FD_NONE; } /* IDENT_LISTEN_GET - JONAS (03.07.2003) */ struct IdentListen_Struct *ident_get(const char *const HostPT, const unsigned long int Port) { struct IdentListen_Struct *IdentListenS = NULL; assert(HostPT != NULL); for (IdentListenS = IdentListen_Head ; IdentListenS != NULL ; IdentListenS = IdentListenS->Next) { if ((strcasecmp(IdentListenS->Host, HostPT) == FALSE) && (IdentListenS->PortH == Port)) { aerrno = AESUCCESS; return(IdentListenS); } } aerrno = AENOMATCH; return(NULL); } /* IDENT_LISTEN_START - JONAS (03.07.2003) */ void ident_listen_start(struct IdentListen_Struct *IdentListenS) { signed long int Result = 0; signed long int BindResult = 0; struct sockaddr_in SockAddr = { 0 }; #if IPV6_SUPPORT struct sockaddr_in6 SockAddr6 = { 0 }; #endif #if !ARES struct hostent *HostEnt = NULL; #endif unsigned long int Flags = 0; assert(IdentListenS != NULL); IdentListenS->Time = NOW; IdentListenS->Tries++; if (!IdentListen_IsResolved(IdentListenS)) { if (IdentListenS->Host[0] == '*') { #if IPV6_SUPPORT if (IdentListen_IsIPv6(IdentListenS)) { memset(&IdentListenS->INAddr6, 0, sizeof(IdentListenS->INAddr6)); IdentListenS->INAddr6 = in6addr_any; } else { #endif /* IPV6_SUPPORT */ memset(&IdentListenS->INAddr, 0, sizeof(IdentListenS->INAddr)); IdentListenS->INAddr.s_addr = INADDR_ANY; #if IPV6_SUPPORT } #endif /* IPV6_SUPPORT */ IdentListen_SetResolved(IdentListenS); } else { memset(&IdentListenS->INAddr, 0, sizeof(IdentListenS->INAddr)); Result = inet_aton(IdentListenS->Host, &IdentListenS->INAddr); if (Result <= 0) { IdentListen_SetResolving(IdentListenS); #if ARES #if IPV6_SUPPORT if (IdentListen_IsIPv6(IdentListenS)) { ares_gethostbyname(Ares_Channel, IdentListenS->Host, AF_INET6, (ares_host_callback) ident_listen_hosttoip, IdentListenS); return; } else { #endif /* IPV6_SUPPORT */ ares_gethostbyname(Ares_Channel, IdentListenS->Host, AF_INET, (ares_host_callback) ident_listen_hosttoip, IdentListenS); #if IPV6_SUPPORT } #endif /* IPV6_SUPPORT */ return; #else /* ARES */ #if IPV6_SUPPORT if (IdentListen_IsIPv6(IdentListenS)) { HostEnt = gethostbyname2(IdentListenS->Host, AF_INET6); } else { HostEnt = gethostbyname2(IdentListenS->Host, AF_INET); } #else /* IPV6_SUPPORT */ HostEnt = gethostbyname(IdentListenS->Host); #endif /* IPV6_SUPPORT */ ident_listen_hosttoip(IdentListenS, errno, HostEnt); if (!Listen_IsResolved(IdentListenS)) { return; } #endif /* ARES */ } else { IdentListen_SetResolved(IdentListenS); IdentListenS->HostIPS = strrealloc(IdentListenS->HostIPS, IdentListenS->Host); if (aerrno != AESUCCESS) { ident_listen_init(IdentListenS); return; } } } } /* CREATE SOCKET */ #if IPV6_SUPPORT if (IdentListen_IsIPv6(IdentListenS)) { Result = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); } else { #endif /* IPV6_SUPPORT */ Result = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); #if IPV6_SUPPORT } #endif /* IPV6_SUPPORT */ if (Result <= ERROR) { sysprint(BITMASK_MAIN, "Ident daemon %s(%s):%ld: Unable to create socket: [%d] %s", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno)); ident_listen_stop(IdentListenS); return; } IdentListenS->FD = Result; IdentListen_SetSocket(IdentListenS); /* SET SOCKET IN NON-BLOCKING MODE */ #if defined(NBLOCK_SYSV) Flags = 1; Result = ioctl(IdentListenS->FD, FIONBIO, &Flags); if (Result <= ERROR) { sysprint(BITMASK_MAIN, "Ident daemon %s(%s):%ld: Unable to set socket in non-blocking mode using ioctl(): [%d] %s", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno)); ident_listen_stop(IdentListenS); return; } #else Result = fcntl(IdentListenS->FD, F_GETFL, &Flags); if (Result <= ERROR) { sysprint(BITMASK_MAIN, "Ident daemon %s(%s):%ld: Unable to get socket flags using fcntl(): [%d] %s", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno)); ident_listen_stop(IdentListenS); return; } #if defined(NBLOCK_BSD) Flags |= O_NDELAY; #elif defined(NBLOCK_POSIX) Flags |= O_NONBLOCK; #else #warning "This system does not support non-blocking sockets?" Flags |= O_NONBLOCK; #endif Result = fcntl(IdentListenS->FD, F_SETFL, Flags); if (Result <= ERROR) { sysprint(BITMASK_MAIN, "Ident daemon %s(%s):%ld: Unable to set socket in non-blocking mode using fcntl(): [%d] %s", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno)); ident_listen_stop(IdentListenS); return; } #endif if (IDENTLISTEN_SOCKKEEPALIVE == TRUE) { unsigned long int OPT = 1; Result = setsockopt(IdentListenS->FD, SOL_SOCKET, SO_KEEPALIVE, &OPT, sizeof(OPT)); if (Result <= ERROR) { sysprint(BITMASK_MAIN, "Ident daemon %s(%s):%ld: Unable to set Keep Alive option for socket: [%d] %s", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno)); ident_listen_stop(IdentListenS); return; } } if (IDENTLISTEN_SOCKREUSEADDR == TRUE) { unsigned long int OPT = 1; Result = setsockopt(IdentListenS->FD, SOL_SOCKET, SO_REUSEADDR, &OPT, sizeof(OPT)); if (Result <= ERROR) { sysprint(BITMASK_MAIN, "Ident daemon %s(%s):%ld: Unable to set Reuse Address option for socket: [%d] %s", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno)); ident_listen_stop(IdentListenS); return; } } /* BIND */ #if !WIN32 if (IdentListenS->PortH < 1024) { sysseteuid(0); } #endif #if IPV6_SUPPORT if (IdentListen_IsIPv6(IdentListenS)) { memset(&SockAddr6, 0, sizeof(SockAddr6)); SockAddr6.sin6_family = AF_INET6; SockAddr6.sin6_addr = IdentListenS->INAddr6; SockAddr6.sin6_port = IdentListenS->PortN; BindResult = bind(IdentListenS->FD, (struct sockaddr *) &SockAddr6, sizeof(SockAddr6)); } else { #endif /* IPV6_SUPPORT */ memset(&SockAddr, 0, sizeof(SockAddr)); SockAddr.sin_family = AF_INET; SockAddr.sin_addr = IdentListenS->INAddr; SockAddr.sin_port = IdentListenS->PortN; BindResult = bind(IdentListenS->FD, (struct sockaddr *) &SockAddr, sizeof(SockAddr)); #if IPV6_SUPPORT } #endif /* IPV6_SUPPORT */ #if !WIN32 if (IdentListenS->PortH < 1024) { sysseteuidnormal(); } #endif if (BindResult <= ERROR) { sysprint(BITMASK_MAIN, "Ident daemon %s(%s):%ld: Unable to bind socket to address: [%d] %s", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno)); ident_listen_stop(IdentListenS); return; } /* IDENT */ Result = listen(IdentListenS->FD, SOMAXCONN); if (Result <= ERROR) { sysprint(BITMASK_MAIN, "Ident daemon %s(%s):%ld: Unable to listen on address: [%d] %s", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno)); ident_listen_stop(IdentListenS); return; } else { DEBUGPRINT(BITMASK_DEBUG_IDENT, "Ident daemon %s(%s):%ld started.", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH); IdentListen_SetListening(IdentListenS); return; } } /* IDENT_LISTEN_HOSTTOIP FUNCTION - JONAS (03.07.2003) */ #if HAVE_CARES_CALLBACK_TIMEOUTS void ident_listen_hosttoip(void *ArgPT, unsigned short int ErrNo, int Timeouts, struct hostent *HostEnt) { #else void ident_listen_hosttoip(void *ArgPT, unsigned short int ErrNo, struct hostent *HostEnt) { #endif struct IdentListen_Struct *IdentListenS = ArgPT; const char *HostIPPT = NULL; #if IPV6_SUPPORT char Host[INET6_ADDRSTRLEN+1] = ""; #endif assert(IdentListenS != NULL); if ((HostEnt == NULL) || (HostEnt->h_length < 1)) { sysprint(BITMASK_MAIN, "Ident daemon %s:%ld: Unable to resolve host %s to IP-address: [%d] %s", IdentListenS->Host, IdentListenS->PortH, IdentListenS->Host, ErrNo, res_strerror(ErrNo)); ident_listen_init(IdentListenS); return; } #if IPV6_SUPPORT if (IdentListen_IsIPv6(IdentListenS)) { memset(&IdentListenS->INAddr6, 0, sizeof(IdentListenS->INAddr6)); memcpy(&IdentListenS->INAddr6, HostEnt->h_addr, HostEnt->h_length); HostIPPT = inet_ntop(AF_INET6, &IdentListenS->INAddr6, Host, INET6_ADDRSTRLEN); if (HostIPPT == NULL) { sysprint(BITMASK_MAIN, "Ident daemon %s:%ld: inet_ntop() failed: [%d] %s", IdentListenS->Host, IdentListenS->PortH, errno, strerror(errno)); ident_listen_init(IdentListenS); return; } } else { memset(&IdentListenS->INAddr, 0, sizeof(IdentListenS->INAddr)); memcpy(&IdentListenS->INAddr, HostEnt->h_addr, HostEnt->h_length); HostIPPT = inet_ntop(AF_INET, &IdentListenS->INAddr, Host, INET6_ADDRSTRLEN); if (HostIPPT == NULL) { sysprint(BITMASK_MAIN, "Ident daemon %s:%ld: inet_ntop() failed: [%d] %s", IdentListenS->Host, IdentListenS->PortH, errno, strerror(errno)); ident_listen_init(IdentListenS); return; } } #else /* IPV6_SUPPORT */ memset(&IdentListenS->INAddr, 0, sizeof(IdentListenS->INAddr)); memcpy(&IdentListenS->INAddr, HostEnt->h_addr, HostEnt->h_length); HostIPPT = inet_ntoa(IdentListenS->INAddr); if (HostIPPT == NULL) { sysprint(BITMASK_MAIN, "Ident daemon %s:%ld: inet_ntoa() failed: [%d] %s", IdentListenS->Host, IdentListenS->PortH, errno, strerror(errno)); ident_listen_init(IdentListenS); return; } #endif IdentListenS->HostIPS = strrealloc(IdentListenS->HostIPS, HostIPPT); IdentListen_ClearResolving(IdentListenS); IdentListen_SetResolved(IdentListenS); #if ARES ident_listen_start(IdentListenS); #endif /* ARES */ } /* IDENT_LISTEN_STOP - JONAS (03.07.2003) */ void ident_listen_stop(struct IdentListen_Struct *IdentListenS) { assert(IdentListenS != NULL); if (IdentListen_IsResolving(IdentListenS)) { #if HAVE_ARES_CANCELQUERY ares_cancelquery(Ares_Channel, IdentListenS); #endif return; } if (IdentListen_IsListening(IdentListenS)) { DEBUGPRINT(BITMASK_DEBUG_IDENT, "Ident daemon %s(%s):%ld stopped.", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH); } if (IdentListen_IsSocket(IdentListenS)) { close(IdentListenS->FD); IdentListenS->FD = FD_NONE; } ident_listen_init(IdentListenS); } /* IDENT_LISTEN_FDS - JONAS (03.07.2003) */ void ident_listen_fds(fd_set *ReadFDS, fd_set *WriteFDS, unsigned long int *FDS) { struct IdentListen_Struct *IdentListenS = NULL; for (IdentListenS = IdentListen_Head ; IdentListenS != NULL ;) { if (IdentListen_IsRemove(IdentListenS)) { struct IdentListen_Struct *IdentListenS_DEL = NULL; if (IdentListen_IsResolving(IdentListenS)) { continue; } ident_listen_stop(IdentListenS); IdentListenS_DEL = IdentListenS; IdentListenS = IdentListenS->Next; ident_listen_rem(IdentListenS_DEL); continue; } if (IdentListen_IsListening(IdentListenS)) { FD_SET(IdentListenS->FD, ReadFDS); } else { if (!IdentListen_IsResolving(IdentListenS)) { unsigned long int Duration = (NOW - IdentListenS->Time); if (Duration >= IDENTLISTEN_INTERVAL) { ident_listen_start(IdentListenS); } } } IdentListenS = IdentListenS->Next; } } /* IDENT_LISTEN_IO - JONAS (03.07.2003) */ void ident_listen_io(fd_set *ReadFDS, fd_set *WriteFDS, unsigned long int *FDS) { struct IdentListen_Struct *IdentListenS = NULL; struct IdentConn_Struct *IdentConnS = NULL; signed long int Result = 0; unsigned long int FD = 0; struct in_addr INAddr; struct sockaddr_in SockAddr = { 0 }; accept_addrlen_type SockAddrLen = sizeof(SockAddr); #if IPV6_SUPPORT struct in6_addr INAddr6; struct sockaddr_in6 SockAddr6 = { 0 }; accept_addrlen_type SockAddrLen6 = sizeof(SockAddr6); #endif char Host[INET6_ADDRSTRLEN+1] = ""; const char *HostIPPT = NULL; unsigned long int PortH; unsigned long int PortN; unsigned short int Count = 0; for (IdentListenS = IdentListen_Head ; IdentListenS != NULL ; IdentListenS = IdentListenS->Next) { assert(*FDS >= 0); if (*FDS <= 0) { return; } if (!IdentListen_IsListening(IdentListenS)) { continue; } if (!FD_ISSET(IdentListenS->FD, ReadFDS)) { continue; } *FDS = *FDS - 1; for (Count = 0 ;; ++Count) { #if IPV6_SUPPORT if (IdentListen_IsIPv6(IdentListenS)) { Result = accept(IdentListenS->FD, (struct sockaddr *) &SockAddr6, &SockAddrLen6); } else { #endif /* IPV6_SUPPORT */ Result = accept(IdentListenS->FD, (struct sockaddr *) &SockAddr, &SockAddrLen); #if IPV6_SUPPORT } #endif /* IPV6_SUPPORT */ if (Result <= ERROR) { if (Count == 0) { sysprint(BITMASK_MAIN, "Ident daemon %s(%s):%ld: Unable to accept new incoming connection: [%d] %s", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno)); } break; } FD = Result; #if IPV6_SUPPORT if (IdentListen_IsIPv6(IdentListenS)) { memset(&INAddr6, 0, sizeof(INAddr6)); INAddr6 = SockAddr6.sin6_addr; PortN = SockAddr6.sin6_port; } else { #endif /* IPV6_SUPPORT */ memset(&INAddr, 0, sizeof(INAddr)); INAddr = SockAddr.sin_addr; PortN = SockAddr.sin_port; #if IPV6_SUPPORT } #endif /* IPV6_SUPPORT */ #if IPV6_SUPPORT if (IdentListen_IsIPv6(IdentListenS)) { HostIPPT = inet_ntop(AF_INET6, &INAddr6, Host, INET6_ADDRSTRLEN); if (HostIPPT == NULL) { close(FD); sysprint(BITMASK_ERROR, "Ident daemon %s(%s):%ld: Failed inet_ntop() for incoming client: %d [%s].", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno)); continue; } } else { HostIPPT = inet_ntop(AF_INET, &INAddr, Host, INET6_ADDRSTRLEN); if (HostIPPT == NULL) { close(FD); sysprint(BITMASK_ERROR, "Ident daemon %s(%s):%ld: Failed inet_ntop() for incoming client: %d [%s].", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno)); continue; } } #else HostIPPT = inet_ntoa(INAddr); if (HostIPPT == NULL) { close(FD); sysprint(BITMASK_ERROR, "Ident daemon %s(%s):%ld: Failed inet_ntoa() for incoming client: %d [%s].", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno)); continue; } #endif IdentConnS = ident_conn_add(HostIPPT, FD); if (IdentConnS == NULL) { close(FD); continue; } IdentConnS->PortH = PortH; IdentConnS->PortN = PortN; #if IPV6_SUPPORT if (IdentListen_IsIPv6(IdentListenS)) { IdentConnS->INAddr6 = INAddr6; } else { #endif IdentConnS->INAddr = INAddr; #if IPV6_SUPPORT } #endif DEBUGPRINT(BITMASK_DEBUG_IDENT, "Ident daemon %s(%s):%ld: Successfully accepted new incoming connection from \"%s\".", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, HostIPPT); } } } /* IDENT_LISTEN_CLOSEALL FUNCTION - JONAS (03.07.2003) */ unsigned short int ident_listen_closeall(const char *const MessagePT, ...) { struct IdentListen_Struct *IdentListenS = NULL; struct IdentListen_Struct *IdentListenS_DEL = NULL; unsigned short int Count = 0; for (IdentListenS = IdentListen_Head ; IdentListenS != NULL ;) { if (IdentListen_IsResolving(IdentListenS)) { #if HAVE_ARES_CANCELQUERY ares_cancelquery(Ares_Channel, IdentListenS); #endif ++Count; IdentListen_SetRemove(IdentListenS); continue; } ident_listen_stop(IdentListenS); IdentListenS_DEL = IdentListenS; IdentListenS = IdentListenS->Next; ident_listen_rem(IdentListenS_DEL); } return(Count); }