These patches are written by Dark@Igor for Dutch Mountains, in December 1995. They are freely redistributable. diff -u src.orig/comm.c src.ident/comm.c --- src.orig/comm.c Fri Dec 15 16:23:26 1995 +++ src.ident/comm.c Wed Jan 3 22:41:48 1996 @@ -272,6 +272,8 @@ DESCRIPTOR_DATA * descriptor_free; /* Free list for descriptors */ DESCRIPTOR_DATA * descriptor_list; /* All open descriptors */ DESCRIPTOR_DATA * d_next; /* Next descriptor in loop */ +IDENT_DATA * ident_free; /* Free list for ident structs */ +IDENT_DATA * ident_list; /* Ident query structs in use */ FILE * fpReserve; /* Reserved filehandle */ FILE * fpReserveBug; /* Reserved filehandle for bugs */ bool god; /* All new chars are gods! */ @@ -302,6 +304,9 @@ void new_descriptor args( ( int control ) ); bool read_from_descriptor args( ( DESCRIPTOR_DATA *d ) ); bool write_to_descriptor args( ( int desc, char *txt, int length ) ); +void free_ident args( ( IDENT_DATA *id ) ); +IDENT_DATA * new_ident args( ( DESCRIPTOR_DATA *desc ) ); +void parse_ident args( ( IDENT_DATA *id ) ); #endif @@ -440,7 +445,7 @@ int x = 1; int fd; - if ( ( fd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) + if ( ( fd = socket( PF_INET, SOCK_STREAM, 0 ) ) < 0 ) { perror( "Init_socket: socket" ); exit( 1 ); @@ -761,6 +766,7 @@ fd_set out_set; fd_set exc_set; DESCRIPTOR_DATA *d; + IDENT_DATA *id, *id_next; int maxdesc, tmp; #if defined(MALLOC_DEBUG) @@ -780,9 +786,17 @@ { maxdesc = UMAX( maxdesc, d->descriptor ); FD_SET( d->descriptor, &in_set ); - FD_SET( d->descriptor, &out_set ); FD_SET( d->descriptor, &exc_set ); } + for ( id = ident_list; id != NULL; id = id->next ) + { + maxdesc = UMAX( maxdesc, id->descriptor ); + if (id->connected) + FD_SET( id->descriptor, &in_set ); + else + FD_SET( id->descriptor, &out_set ); + } + if ( select( maxdesc+1, &in_set, &out_set, &exc_set, &null_time ) < 0 ) { @@ -807,7 +821,6 @@ if ( FD_ISSET( d->descriptor, &exc_set ) ) { FD_CLR( d->descriptor, &in_set ); - FD_CLR( d->descriptor, &out_set ); if ( d->character ) save_char_obj( d->character, TRUE ); d->outtop = 0; @@ -825,6 +838,73 @@ } + /* + * Process ident queries. + */ + for ( id = ident_list; id != NULL; id = id_next ) + { + long size; + char * p; + struct sockaddr sa; + int salen = sizeof(sa); + + id_next = id->next; + if ( !id->connected && FD_ISSET( id->descriptor, &out_set ) ) + { + if ( getpeername( id->descriptor, &sa, &salen ) < 0 ) + free_ident ( id ); + else + { + char querybuf[20]; + sprintf( querybuf, "%d,%d\r\n", + id->remoteport, id->localport ); + write( id->descriptor, querybuf, strlen(querybuf) ); + id->connected = TRUE; + id->timeout = current_time + IDENT_TIMEOUT; + } + } + else if ( FD_ISSET( id->descriptor, &in_set ) ) + { + size = read( id->descriptor, id->reply_text + id->reply_pos, + IDENT_BUFFER - id->reply_pos ); + if (size < 0) + free_ident( id ); + else + { + bool complete = FALSE; + + id->reply_pos += size; + if ( id->reply_pos == IDENT_BUFFER ) + { + complete = TRUE; + id->reply_text[IDENT_BUFFER-2] = '\r'; + id->reply_text[IDENT_BUFFER-1] = '\n'; + } + else + { + for ( p = id->reply_text + id->reply_pos - 2; + p >= id->reply_text; p-- ) + { + if ( *p == '\r' && *(p+1) == '\n' ) + { + complete = TRUE; + break; + } + } + } + if ( complete ) + { + parse_ident( id ); + free_ident( id ); + } + } + } + else if ( current_time > id->timeout ) + { + free_ident( id ); + } + } + /* * Process input. */ @@ -841,7 +921,6 @@ d->original->timer = 0; if ( !read_from_descriptor( d ) ) { - FD_CLR( d->descriptor, &out_set ); if ( d->character != NULL ) save_char_obj( d->character, TRUE ); d->outtop = 0; @@ -1007,6 +1086,8 @@ free_string( d->host ); free_mem( d->outbuf, d->outsize ); + if ( d->ident ) + free_ident ( d->ident ); for ( iHistory = 0; iHistory < MAX_HISTORY; iHistory++ ) free_string( GET_HISTORY(d, iHistory) ); d->next = descriptor_free; @@ -1038,6 +1119,185 @@ /* END */ #if defined(unix) +void free_ident( IDENT_DATA *id ) +{ + if ( id->descriptor > 0 ) + close( id->descriptor ); + id->desc->ident = NULL; + + if ( ident_list == id ) + ident_list = ident_list->next; + else + { + IDENT_DATA *idp; + + for ( idp = ident_list; idp; idp = idp->next ) + { + if ( idp->next == id ) + { + idp->next = id->next; + break; + } + } + } + + id->next = ident_free; + ident_free = id; +} + +IDENT_DATA *new_ident( DESCRIPTOR_DATA *desc ) +{ + IDENT_DATA *id; + static IDENT_DATA id_zero; + sh_int d; + int localport, remoteport; + struct sockaddr_in sin; + size_t len = sizeof(sin); + + if ( getsockname( desc->descriptor, (struct sockaddr *) &sin, &len ) < 0 + || len < sizeof(sin) ) + return NULL; + localport = ntohs( sin.sin_port ); + + /* This will also leave sin.sin_addr useful for connect() below. */ + if ( getpeername( desc->descriptor, (struct sockaddr *) &sin, &len ) < 0 + || len < sizeof(sin) ) + return NULL; + remoteport = ntohs( sin.sin_port ); + + if ( (d = socket( PF_INET, SOCK_STREAM, 0 )) < 0 ) + { + perror("Ident socket: socket"); + return NULL; + } + +#if !defined(FNDELAY) +#define FNDELAY O_NDELAY +#endif + + if ( fcntl ( d, F_SETFL, FNDELAY ) == -1 ) + { + perror( "Ident socket: fcntl: FNDELAY" ); + close( d ); + return NULL; + } + + /* sin.sin_addr was set by getpeername() above. */ + sin.sin_family = AF_INET; + sin.sin_port = htons(113); + if ( connect( d, (struct sockaddr *) &sin, len ) < 0 + && errno != EINPROGRESS && errno != EAGAIN ) + { + close ( d ); + return NULL; + } + + if ( ident_free == NULL ) + { + id = alloc_perm( sizeof(*id) ); + } + else + { + id = ident_free; + ident_free = ident_free->next; + } + + *id = id_zero; + id->desc = desc; + id->descriptor = d; + id->connected = FALSE; + id->timeout = current_time + IDENT_TIMEOUT; + id->remoteport = remoteport; + id->localport = localport; + id->next = ident_list; + ident_list = id; + + return id; +} + +void parse_ident( IDENT_DATA *id ) +{ + char *p; + int remoteport, localport; + char replytype[40]; + char foo; + int tmp; + char *ident; + char *hostid; + static char tokenchars[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "-, .!@#$%^&*()_=+.,<>/?\"'~`{}[];"; + + if ( !(p = strstr( id->reply_text, "\r\n")) ) + return; + *p = 0; + + /* + * The extra argument "foo" is used because sscanf doesn't count + * a bare %n. + */ + if ( sscanf( id->reply_text, "%d , %d : %39s : %n%c", + &remoteport, &localport, replytype, &tmp, &foo ) < 4 + || remoteport != id->remoteport + || localport != id->localport ) + return; + + p = id->reply_text + tmp; + + if ( strcmp( replytype, "ERROR" ) == 0 ) + { + tmp = strspn( p, tokenchars ); + if ( p[tmp] ) + return; + + if ( p[0] == 'X' ) + ident = p + 1; + else if ( strcmp( p, "NO-USER" ) == 0 ) + ident = "<nobody>"; + else if ( strcmp( p, "HIDDEN-USER" ) == 0 ) + ident = "<hidden>"; + else + ident = "<error>"; + } + else if ( strcmp( replytype, "USERID" ) == 0 ) + { + /* Skip straight to the userid field */ + p = strchr( p, ':' ); + if ( p == NULL ) + return; + p++; + /* + * The RFC says not to ignore leading whitespace here. + * Unfortunately, some servers get it wrong because of + * the example on line 109 of RFC1413. + */ + ident = p + strspn( p, " \t" ); + for ( p = ident; *p; p++ ) + { + if ( !isprint( *p ) ) + *p = '?'; + } + } + else return; + + if ( id->desc->host ) + { + hostid = alloc_mem( strlen( ident ) + strlen( id->desc->host ) + 2 ); + sprintf( hostid, "%s@%s", ident, id->desc->host ); + free_string( id->desc->host ); + } + else + { + hostid = alloc_mem( strlen( ident ) + 6 ); + sprintf( hostid, "%s@NULL", ident ); + } + id->desc->host = hostid; +} +#endif + + +#if defined(unix) void new_descriptor( int control ) { static DESCRIPTOR_DATA d_zero; @@ -1065,12 +1325,6 @@ #define FNDELAY O_NDELAY #endif - if ( fcntl( control, F_SETFL, FNDELAY ) == -1 ) - { - perror( "New_descriptor: fcntl: FNDELAY" ); - return; - } - if ( fcntl( desc, F_SETFL, FNDELAY ) == -1 ) { perror( "New_descriptor: fcntl: FNDELAY" ); @@ -1134,6 +1388,8 @@ dnew->host = str_dup( from ? from->h_name : buf ); } + + dnew->ident = new_ident( dnew ); /* * Swiftest: I added the following to ban sites. I don't diff -u src.orig/merc.h src.ident/merc.h --- src.orig/merc.h Tue Dec 12 17:12:05 1995 +++ src.ident/merc.h Thu Dec 28 02:30:36 1995 @@ -82,6 +82,7 @@ typedef struct extra_descr_data EXTRA_DESCR_DATA; typedef struct trap_data TRAP_DATA; typedef struct help_data HELP_DATA; +typedef struct ident_data IDENT_DATA; typedef struct mob_index_data MOB_INDEX_DATA; typedef struct name_ban_data NAME_BAN_DATA; typedef struct note_data NOTE_DATA; @@ -259,6 +260,7 @@ DESCRIPTOR_DATA * snoop_by; CHAR_DATA * character; CHAR_DATA * original; + IDENT_DATA * ident; char * host; sh_int descriptor; sh_int connected; @@ -277,7 +279,24 @@ int showstr_len; }; +#define IDENT_TIMEOUT 120 /* 2 minutes */ +#define IDENT_BUFFER 1024 +/* + * Data for Ident (RFC1413) queries. + */ +struct ident_data +{ + IDENT_DATA * next; + DESCRIPTOR_DATA * desc; + sh_int descriptor; + bool connected; + time_t timeout; + sh_int localport; + sh_int remoteport; + sh_int reply_pos; + char reply_text [IDENT_BUFFER]; +}; /* * Attribute bonus structures.