/***************************************** this file was submitted a very long time ago to me by Cid i had completely forgotten that id.c had some bugs in it that had to be dealt with before the mud would correctly compile. well better late then never. -Kjodo *******************************************/ #if defined( macintosh ) #include <types.h> #else #include <sys/types.h> #include <sys/time.h> #endif #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <fcntl.h> #include <netdb.h> #include <signal.h> #include <netinet/in.h> #include <sys/socket.h> #include <arpa/telnet.h> #include <errno.h> #include "merc.h" #define AUTH_UNSENT 0 #define AUTH_SENT 1 #define AUTH_RETRY 2 struct auth_data { struct auth_data *next; struct auth_data *prev; DESCRIPTOR_DATA *d; int auth_fd; char abuf[MAX_INPUT_LENGTH]; int auth_inc; int auth_state; int atimes; }; struct auth_data *first_auth; struct auth_data *last_auth; struct auth_data *auth_free; void send_auth( struct auth_data *auth ); void read_auth( struct auth_data *auth ); int read( int fd, char *buf, int nbyte ); int write( int fd, char *buf, int nbyte ); int close( int fd ); #define LINK(link, first, last, next, prev)\ do {\ if ( (first) == NULL )\ (first) = (link);\ else\ (last)->next = (link);\ (link)->next = NULL;\ (link)->prev = (last);\ (last) = (link);\ } while(0) #define UNLINK( link, first, last, next, prev ) \ do {\ if ( !(link)->next )\ (last) = (link)->prev;\ else\ (link)->next->prev = (link)->prev;\ if ( !(link)->prev )\ (first) = (link)->next;\ else\ (link)->prev->next = (link)->next;\ } while(0) #define GET_FREE(point, freelist) \ do { \ if ( freelist != NULL ) \ { \ point = freelist; \ freelist = freelist->next; \ } \ else \ point = alloc_perm(sizeof(*point)); \ memset(point, 0, sizeof(*point)); \ } while(0) #define PUT_FREE(point, freelist) \ do { \ point->next = freelist; \ freelist = point; \ } while(0) #define RLSTRIP(str) \ do { \ int pst; \ while ( isspace(*(str)) ) \ (str)++; \ for ( pst = strlen(str)-1; pst >= 0 && isspace((str)[pst]); pst-- ) \ (str)[pst] = '\0'; \ } while(0) bool start_auth( DESCRIPTOR_DATA *d ) { struct sockaddr_in sock; int tlen; struct auth_data *auth; int desc; desc = socket(AF_INET, SOCK_STREAM, 0); /* if ( desc < 0 && errno == EAGAIN ) { bug( "Can't allocate fd for authorization check on %s.", (int)d->host ); free_string(d->user); d->user = str_dup("(no auth_fd)"); return FALSE; } */ if ( fcntl(desc, F_SETFL, O_NDELAY) == -1 ) { perror("Nonblock"); close(desc); free_string(d->user); d->user = str_dup("(nonblock)"); return FALSE; } tlen = sizeof(sock); getpeername(d->descriptor, (struct sockaddr *)&sock, &tlen); sock.sin_port = htons(113); sock.sin_family = AF_INET; /* if ( connect(desc, (struct sockaddr *)&sock, sizeof(sock)) == -1 && errno != EINPROGRESS ) { bug( "Identd denied for %s.", (int)d->host ); close(desc); free_string(d->user); d->user = str_dup("(no verify)"); return FALSE; } if ( errno == ECONNREFUSED ) { close(desc); free_string(d->user); d->user = str_dup("(no identd)"); return FALSE; } */ for ( auth = first_auth; auth; auth = auth->next ) if ( auth->d == d ) break; if ( !auth ) { GET_FREE(auth, auth_free); auth->d = d; auth->atimes = 70; LINK(auth, first_auth, last_auth, next, prev); } auth->auth_fd = desc; auth->abuf[0] = '\0'; auth->auth_state = AUTH_UNSENT; auth->auth_inc = 0; return TRUE; } #define END_AUTH(auth, username) \ do { \ free_string(auth->d->user); \ auth->d->user = str_dup(username); \ close(auth->auth_fd); \ UNLINK(auth, first_auth, last_auth, next, prev); \ PUT_FREE(auth, auth_free); \ return; \ } while(0) #define RESET_AUTH(auth) \ do { \ close(auth->auth_fd); \ auth->auth_fd = -1; \ auth->auth_state = AUTH_RETRY; \ return; \ } while(0) void send_auth( struct auth_data *auth ) { struct sockaddr_in us, them; char authbuf[32]; int ulen, tlen, z; tlen = ulen = sizeof(us); if ( --auth->atimes == 0 ) END_AUTH(auth, "(auth failed)"); if ( getsockname(auth->d->descriptor, (struct sockaddr *)&us, &ulen) || getpeername(auth->d->descriptor, (struct sockaddr *)&them, &tlen) ) { bug( "auth getsockname/getpeername error", 0 ); RESET_AUTH(auth); } sprintf(authbuf, "%u , %u\r\n", ntohs(them.sin_port), ntohs(us.sin_port)); z = write(auth->auth_fd, authbuf, strlen(authbuf)); /* if ( errno == ECONNREFUSED ) END_AUTH(auth, "(no identd)"); */ if ( z != strlen(authbuf) ) { if ( auth->atimes == 1 ) { /* sprintf(log_buf, "auth request, broken pipe [%d/%d]", z, errno); */ log_string(log_buf, CHANNEL_CODER, -1); } RESET_AUTH(auth); } auth->auth_state = AUTH_SENT; return; } char *my_onearg( char **str, char cEnd ) { char *arg; /* char cEnd = ' ';*/ while ( isspace(**str) ) (*str)++; /* if ( **str == ':' ) { cEnd = **str; (*str)++; }*/ arg = *str; while ( **str != '\0' ) { if ( (cEnd == ' ' ? isspace(**str) : **str == cEnd) ) { **str = '\0'; (*str)++; while ( isspace(**str) ) (*str)++; break; } (*str)++; } RLSTRIP(arg); return arg; } /*char one_char(char **str) { char letter; while ( isspace(**str) ) (*str)++; letter = **str; (*str)++; while ( isspace(**str) ) (*str)++; return letter; }*/ void read_auth( struct auth_data *auth ) { int len; char ruser[20], system[20]; char *s; extern int port; *system = *ruser = '\0'; if ( (len = read(auth->auth_fd, auth->abuf+auth->auth_inc, sizeof(auth->abuf)-1-auth->auth_inc)) > 0 ) { auth->auth_inc += len; auth->abuf[auth->auth_inc] = '\0'; } if ( len > 0 && auth->auth_inc != sizeof(auth->abuf)-1 ) { s = auth->abuf; RLSTRIP(s); bug(s,0); if ( !*s ) END_AUTH(auth, "(blank auth)"); if ( !atoi(my_onearg(&s, ',')) || atoi(my_onearg(&s, ':')) != port ) END_AUTH(auth, "(invalid identd)"); my_onearg(&s, ':'); strncpy(system, my_onearg(&s, ':'), sizeof(system)-1); if ( !str_cmp(system, "OTHER") ) END_AUTH(auth, "(invalid system)"); strncpy(ruser, my_onearg(&s, ' '), sizeof(ruser)-1); if ( !*ruser ) END_AUTH(auth, "(no username)"); sprintf(log_buf, "auth reply ok, incoming user: [%s]", ruser); log_string(log_buf, CHANNEL_CODER, -1); } else if ( len != 0 ) { if ( !index(auth->abuf, '\n') && !index(auth->abuf, '\r') ) return; sprintf(log_buf, "bad auth reply: %s", auth->abuf); log_string(log_buf, CHANNEL_CODER, -1); strcpy(ruser, "(no auth)"); } END_AUTH(auth, ruser); } #undef END_AUTH void auth_maxdesc( int *maxdesc, fd_set *in_set, fd_set *out_set, fd_set *exc_set ) { struct auth_data *auth; for ( auth = first_auth; auth; auth = auth->next ) { if ( auth->auth_state == AUTH_RETRY ) continue; *maxdesc = UMAX(*maxdesc, auth->auth_fd); FD_SET(auth->auth_fd, in_set ); FD_SET(auth->auth_fd, out_set); FD_SET(auth->auth_fd, exc_set); } return; } void auth_update( fd_set *in_set, fd_set *out_set, fd_set *exc_set ) { struct auth_data *auth; struct auth_data *a_next; for ( auth = first_auth; auth; auth = a_next ) { a_next = auth->next; /* if ( FD_ISSET(auth->auth_fd, exc_set) ) { FD_CLR(auth->auth_fd, in_set ); FD_CLR(auth->auth_fd, out_set); close(auth->auth_fd); free_string(auth->d->user); auth->d->user = str_dup("(fd exception)"); UNLINK(auth, first_auth, last_auth, next, prev); PUT_FREE(auth, auth_free); continue; }*/ switch(auth->auth_state) { case AUTH_UNSENT: if ( FD_ISSET(auth->auth_fd, out_set) ) send_auth(auth); break; case AUTH_SENT: if ( FD_ISSET(auth->auth_fd, in_set ) ) read_auth(auth); break; case AUTH_RETRY: if ( !start_auth(auth->d) ) { UNLINK(auth, first_auth, last_auth, next, prev); PUT_FREE(auth, auth_free); continue; } break; } } return; } void auth_check( DESCRIPTOR_DATA *d ) { struct auth_data *auth; for ( auth = first_auth; auth; auth = auth->next ) if ( auth->d == d ) { if ( auth->auth_state != AUTH_RETRY ) close(auth->auth_fd); UNLINK(auth, first_auth, last_auth, next, prev); PUT_FREE(auth, auth_free); break; } return; }