/*
* ----------------------------------------------------------------
* Night Light IRC Proxy - Ident Daemon - Connection Functions
* ----------------------------------------------------------------
* Copyright (C) 1997-2007 Jonas Kvinge <jonas@night-light.net>
* 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 (03.07.2007)
*
*/
#define IDENT_IO_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 0 /* ioctl(), etc */
#define NEED_SYS_FILIO_H 0 /* 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 0 /* Network database functions */
#define NEED_ARPA_NAMESER_H 0 /* Nameserver definitions */
#define NEED_GETUSERPW_HEADERS 0 /* Functions to retrive system passwords */
#define NEED_ARES 0 /* Functions needed for ares */
#define NEED_SSL 1 /* Needed for SSL support */
#include "includes.h"
#include "irc.h"
#include "ident_conn.h"
#include "conn.h"
/* VARIABLES - JONAS (03.07.2003) */
struct IdentConn_Struct *IdentConn_Head = NULL;
struct IdentConn_Struct *IdentConn_Tail = NULL;
unsigned long int G_IdentConns = 0;
extern char *Ident_Conf_DefaultUser;
extern struct Conn_Struct *Conn_Head;
/* IDENT_CONN_ADD FUNCTION - JONAS (03.07.2003) */
struct IdentConn_Struct *ident_conn_add(const char *const HostIPSPT, signed long int FD) {
struct IdentConn_Struct *IdentConnS = NULL;
struct IdentConn_Struct *IdentConn_NEW = NULL;
assert(HostIPSPT != NULL);
IdentConn_NEW = malloc(sizeof(struct IdentConn_Struct));
if (IdentConn_NEW == NULL) {
aerrno = AEMALLOC;
return(NULL);
}
memset(IdentConn_NEW, 0, sizeof(struct IdentConn_Struct));
ident_conn_initconnection(IdentConn_NEW);
IdentConn_NEW->HostIPS = strdup(HostIPSPT);
if (IdentConn_NEW->HostIPS == NULL) {
free(IdentConn_NEW->HostIPS);
free(IdentConn_NEW);
aerrno = AEMALLOC;
return(NULL);
}
IdentConn_NEW->FD = FD;
IdentConn_NEW->Time = NOW;
IdentConn_SetSocket(IdentConn_NEW);
if (IdentConn_Head == NULL) {
IdentConn_Head = IdentConn_NEW;
IdentConn_Tail = IdentConn_NEW;
}
else {
IdentConnS = IdentConn_Tail;
IdentConnS->Next = IdentConn_NEW;
IdentConn_NEW->Prev = IdentConnS;
IdentConn_Tail = IdentConn_NEW;
}
G_IdentConns++;
aerrno = AESUCCESS;
return(IdentConn_NEW);
}
/* IDENT_CONN_REM FUNCTION - JONAS (03.07.2003) */
void ident_conn_rem(struct IdentConn_Struct *IdentConnS) {
assert(IdentConnS != NULL);
if (IdentConnS->Prev == NULL) { IdentConn_Head = IdentConnS->Next; }
else { IdentConnS->Prev->Next = IdentConnS->Next; }
if (IdentConnS->Next == NULL) { IdentConn_Tail = IdentConnS->Prev; }
else { IdentConnS->Next->Prev = IdentConnS->Prev; }
FREE(IdentConnS->RecvBuffer);
FREE(IdentConnS->SendBuffer);
free(IdentConnS->HostIPS);
free(IdentConnS);
G_IdentConns--;
}
/* IDENT_CONN_INITCONNECTION FUNCTION - JONAS (03.07.2003) */
void ident_conn_initconnection(struct IdentConn_Struct *IdentConnS) {
assert(IdentConnS != NULL);
IdentConnS->Flags = 0;
IdentConnS->FD = FD_NONE;
memset(&IdentConnS->INAddr, 0, sizeof(IdentConnS->INAddr));
#if IPV6_SUPPORT
memset(&IdentConnS->INAddr6, 0, sizeof(IdentConnS->INAddr6));
#endif
FREE(IdentConnS->RecvBuffer);
FREE(IdentConnS->SendBuffer);
}
/* IDENT_CONN_DISCONNECT FUNCTION - JONAS (03.07.2003) */
void ident_conn_disconnect(struct IdentConn_Struct *IdentConnS) {
assert(IdentConnS != NULL);
if (IdentConn_IsSocket(IdentConnS)) {
close(IdentConnS->FD);
IdentConnS->FD = FD_NONE;
}
ident_conn_initconnection(IdentConnS);
}
/* IDENT_CONN_FDS FUNCTION - JONAS (03.07.2003) */
void ident_conn_fds(fd_set *ReadFDS, fd_set *WriteFDS, unsigned long int *FDS) {
struct IdentConn_Struct *IdentConnS = NULL;
struct IdentConn_Struct *IdentConnS_DEL = NULL;
time_t Duration = 0;
for (IdentConnS = IdentConn_Head ; IdentConnS != NULL ;) {
Duration = (NOW - IdentConnS->Time);
if (Duration >= IDENTCONN_TIMEOUT) { ident_conn_disconnect(IdentConnS); }
if (IdentConn_IsSocket(IdentConnS)) {
FD_SET(IdentConnS->FD, ReadFDS);
if (IdentConnS->SendBuffer != NULL) { FD_SET(IdentConnS->FD, WriteFDS); }
IdentConnS = IdentConnS->Next;
continue;
}
else {
IdentConnS_DEL = IdentConnS;
IdentConnS = IdentConnS->Next;
ident_conn_rem(IdentConnS_DEL);
continue;
}
}
}
/* IDENT_CONN_IO FUNCTION - JONAS (03.07.2003) */
void ident_conn_io(fd_set *ReadFDS, fd_set *WriteFDS, unsigned long int *FDS) {
struct IdentConn_Struct *IdentConnS = NULL;
assert(ReadFDS != NULL);
assert(WriteFDS != NULL);
for (IdentConnS = IdentConn_Head ; IdentConnS != NULL ; IdentConnS = IdentConnS->Next) {
assert(*FDS >= 0);
if (*FDS <= 0) { return; }
if (IdentConn_IsSocket(IdentConnS)) {
if (FD_ISSET(IdentConnS->FD, ReadFDS)) { *FDS = *FDS - 1; }
if (FD_ISSET(IdentConnS->FD, WriteFDS)) { *FDS = *FDS - 1; }
}
if (IdentConn_IsSocket(IdentConnS)) {
if (FD_ISSET(IdentConnS->FD, ReadFDS)) { ident_conn_recv(IdentConnS); }
}
if (IdentConn_IsSocket(IdentConnS)) {
if (FD_ISSET(IdentConnS->FD, WriteFDS)) { ident_conn_send(IdentConnS); }
}
}
}
/* IDENT_CONN_RECV FUNCTION - JONAS (03.07.2003) */
void ident_conn_recv(struct IdentConn_Struct *IdentConnS) {
signed long int Result = 0;
unsigned long int OldLen = 0;
unsigned long int NewLen = 0;
char RecvBuffer[RECVBUFFERLEN+1] = "";
char *RecvBufferPT = NULL;
assert(IdentConnS != NULL);
assert(IdentConn_IsSocket(IdentConnS));
assert(IdentConnS->FD != FD_NONE);
do {
memset(&RecvBuffer, 0, sizeof(RecvBuffer));
Result = recv(IdentConnS->FD, RecvBuffer, RECVBUFFERLEN, MSG_NOSIGNAL);
if (Result <= ERROR) {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR)) { break; }
ident_conn_disconnect(IdentConnS);
return;
}
if (Result == 0) {
if (IdentConnS->RecvBuffer != NULL) { ident_conn_parse(IdentConnS); }
ident_conn_disconnect(IdentConnS);
return;
}
if (IdentConnS->RecvBuffer == NULL) { OldLen = 0; }
else { OldLen = strlen(IdentConnS->RecvBuffer); }
NewLen = OldLen + Result + 1;
RecvBufferPT = realloc(IdentConnS->RecvBuffer, NewLen);
if (RecvBufferPT == NULL) {
ident_conn_disconnect(IdentConnS);
return;
}
IdentConnS->RecvBuffer = RecvBufferPT;
RecvBufferPT += OldLen;
strcpy(RecvBufferPT, RecvBuffer);
}
while (Result >= RECVBUFFERLEN);
ident_conn_parse(IdentConnS);
}
/* IDENT_CONN_SEND FUNCTION - JONAS (03.07.2003) */
void ident_conn_send(struct IdentConn_Struct *IdentConnS) {
char *SendBufferPT = NULL;
char SendBuffer[SENDBUFFERLEN+1] = "";
unsigned long int SendLen = 0;
unsigned long int SentLen = 0;
signed long int Result = 0;
assert(IdentConnS != NULL);
assert(IdentConn_IsSocket(IdentConnS));
assert(IdentConnS->FD != FD_NONE);
assert(IdentConnS->SendBuffer != NULL);
for (SendBufferPT = IdentConnS->SendBuffer ; *SendBufferPT != '\0' ; SendBufferPT += SentLen) {
SendLen = strlen(SendBufferPT);
if (SendLen > SENDBUFFERLEN) { SendLen = SENDBUFFERLEN; }
memset(&SendBuffer, 0, sizeof(SendBuffer));
strncpy(SendBuffer, SendBufferPT, SendLen);
Result = send(IdentConnS->FD, SendBuffer, SendLen, MSG_NOSIGNAL);
if (Result <= ERROR) {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR) || (errno == ENOMEM) || (errno == ENOBUFS)) {
/*
* EAGAIN/EWOULDBLOCK -- THE SOCKET IMPLEMENTATION CAN'T HANDLE MORE DATA.
* EINTR - INTERRUPTED BY A SIGNAL.
* ENOMEM - NO MEMORY LEFT.
* ENOBUFS - NO BUFFER SPACE AVAILABLE.
*
* COPY WHATS LEFT TO THE THE START OF THE SENDBUFFER, REALLOCATE THE MEMORY AND BAIL OUT - JONAS (01.12.1999)
*
*/
unsigned long int Len = 0;
Len = strlen(SendBufferPT) + 1;
memmove(IdentConnS->SendBuffer, SendBufferPT, Len);
SendBufferPT = realloc(IdentConnS->SendBuffer, Len);
assert(SendBufferPT != NULL);
IdentConnS->SendBuffer = SendBufferPT;
return;
}
ident_conn_disconnect(IdentConnS);
return;
}
SentLen = Result;
assert(SentLen == SendLen);
}
FREE(IdentConnS->SendBuffer);
ident_conn_disconnect(IdentConnS);
}
/* IDENT_CONN_ADDSEND FUNCTION - JONAS (03.07.2003) */
void ident_conn_addsend(struct IdentConn_Struct *IdentConnS, const char *const LinePT, ...) {
char Line[LINELEN+1] = "";
char LineCRLF[LINELEN+1] = "";
va_list Args = { 0 };
unsigned long int Len = 0;
unsigned long int OldLen = 0;
unsigned long int NewLen = 0;
char *SendBufferPT = NULL;
assert(IdentConnS != NULL);
assert(LinePT != NULL);
assert(IdentConn_IsSocket(IdentConnS));
va_start(Args, LinePT);
vsnprintf(Line, LINELEN+1, LinePT, Args);
va_end(Args);
snprintf(LineCRLF, LINELEN+1, "%s\r\n", Line);
Len = strlen(LineCRLF);
if (IdentConnS->SendBuffer == NULL) { OldLen = 0; }
else { OldLen = strlen(IdentConnS->SendBuffer); }
NewLen = OldLen + Len + 1;
SendBufferPT = realloc(IdentConnS->SendBuffer, NewLen);
if (SendBufferPT == NULL) { return; }
IdentConnS->SendBuffer = SendBufferPT;
SendBufferPT = SendBufferPT + OldLen;
strcpy(SendBufferPT, LineCRLF);
}
/* IDENT_CONN_PARSE FUNCTION - JONAS (03.07.2003) */
void ident_conn_parse(struct IdentConn_Struct *IdentConnS) {
char *BufferPT = NULL;
char *LinePT = NULL;
char *DumbPT = NULL;
unsigned long int Count = 0;
unsigned long int Len = 0;
char *TempPT = NULL;
assert(IdentConnS != NULL);
BufferPT = IdentConnS->RecvBuffer;
for (Count = 1 ; BufferPT != NULL ; Count++) {
DumbPT = strchr(BufferPT, '\n');
if (DumbPT == NULL) {
if (Count == 1) { return; }
if (BufferPT != NULL) {
Len = strlen(BufferPT) + 1;
memmove(IdentConnS->RecvBuffer, BufferPT, Len);
TempPT = realloc(IdentConnS->RecvBuffer, Len);
if (TempPT == NULL) {
ident_conn_disconnect(IdentConnS);
return;
}
IdentConnS->RecvBuffer = TempPT;
return;
}
FREE(IdentConnS->RecvBuffer);
return;
}
LinePT = strtok(BufferPT, "\n");
BufferPT = strtok(NULL, "\0");
if (LinePT == NULL) { continue; }
Len = strlen(LinePT);
if (LinePT[Len-1] == '\r') { LinePT[Len-1] = '\0'; }
ident_conn_parse_message(IdentConnS, LinePT);
if (IdentConnS->RecvBuffer == NULL) { return; }
}
FREE(IdentConnS->RecvBuffer);
}
/* IDENT_CONN_PARSE_MESSAGE FUNCTION - JONAS (03.07.2003) */
void ident_conn_parse_message(struct IdentConn_Struct *IdentConnS, char *MessagePT) {
char *Port1PT = NULL;
char *Port2PT = NULL;
char *TempPT = NULL;
unsigned long int Port1 = 0;
unsigned long int Port2 = 0;
struct Conn_Struct *ConnS = NULL;
assert(IdentConnS != NULL);
assert(MessagePT != NULL);
DEBUGPRINT(BITMASK_DEBUG_IDENT, "Ident query from %s: %s", IdentConnS->HostIPS, MessagePT);
while (MessagePT[0] == ' ') { ++MessagePT; }
if (MessagePT[0] == '\0') {
ident_conn_addsend(IdentConnS, "0 , 0 : ERROR : X-INVALID-REQUEST");
return;
}
Port1PT = MessagePT;
StrMovePastToken(MessagePT, ',');
if (MessagePT == NULL) {
ident_conn_addsend(IdentConnS, "0 , 0 : ERROR : X-INVALID-REQUEST");
return;
}
while (MessagePT[0] == ' ') { ++MessagePT; }
Port2PT = MessagePT;
while((TempPT = strchr(Port1PT, ' ')) != NULL) { *TempPT = '\0'; }
while((TempPT = strchr(Port2PT, ' ')) != NULL) { *TempPT = '\0'; }
Port1 = strtoul(Port1PT, NULL, 0);
Port2 = strtoul(Port2PT, NULL, 0);
for (ConnS = Conn_Head ; ConnS != NULL ; ConnS = ConnS->Next) {
if ((ConnS->PortH == Port1) && (ConnS->ServerPortH == Port2)) {
ident_conn_addsend(IdentConnS, "%ld , %ld : USERID : UNIX : %s", Port1, Port2, ConnS->User);
return;
}
}
if ((Ident_Conf_DefaultUser == NULL) || (strcmp(Ident_Conf_DefaultUser, "NO-USER") == FALSE)) {
ident_conn_addsend(IdentConnS, "%ld , %ld : ERROR : NO-USER", Port1, Port2);
return;
}
else {
ident_conn_addsend(IdentConnS, "%ld , %ld : USERID : UNIX : %s", Port1, Port2, Ident_Conf_DefaultUser);
return;
}
}
/* IDENT_CONN_CLOSEALL FUNCTION - JONAS (03.07.2003) */
unsigned short int ident_conn_closeall(void) {
struct IdentConn_Struct *IdentConnS = NULL;
struct IdentConn_Struct *IdentConnS_DEL = NULL;
for (IdentConnS = IdentConn_Head ; IdentConnS != NULL ;) {
if (IdentConn_IsSocket(IdentConnS)) { ident_conn_disconnect(IdentConnS); }
IdentConnS_DEL = IdentConnS;
IdentConnS = IdentConnS->Next;
free(IdentConnS_DEL);
}
return(0);
}
syntax highlighted by Code2HTML, v. 0.9.1