// mostly borrowed from freebie code
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "emlen.h"
#ifdef WINDOWS
void start_auth (struct descriptor_data *d) {return;}
void read_auth (struct descriptor_data *d) {return;}
void send_auth (struct descriptor_data *d) {return;}
#else
#include "mush.h"
#include <sys/types.h>
#include <ctype.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <arpa/telnet.h>
#include <errno.h>
#include <netdb.h>
void nonblock (int s);
void start_auth (struct descriptor_data *d);
void read_auth (struct descriptor_data *d);
void send_auth (struct descriptor_data *d);
void
start_auth (struct descriptor_data *d)
{
struct sockaddr_in sock;
int err; /* error & result stuffs */
int tlen;
/*if ( !str_prefix( "130.63.236", d->host )
|| !str_prefix( "130.63", d->host ) )
{
free_string(d->user);
d->user = str_dup( "(ncsa format)" );
return;
} */
d->auth_fd = socket (AF_INET, SOCK_STREAM, 0);
err = errno;
if (d->auth_fd < 0 && err == EAGAIN)
bug ("Can't allocate fd for authorization check", 0);
nonblock (d->auth_fd);
/* Clone incoming host address */
tlen = sizeof (sock);
getpeername (d->descriptor, (struct sockaddr *) &sock, &tlen);
sock.sin_port = htons (113);
sock.sin_family = AF_INET;
if ((connect (d->auth_fd, (struct sockaddr *) &sock, sizeof (sock)) == -1)
&& (errno != EINPROGRESS))
{
/* Identd Denied */
close (d->auth_fd);
free_string (d->username);
d->username = str_dup ("no_inetd");
d->auth_fd = -1;
d->auth_state = 0;
d->atimes = 500;
return;
}
if (errno == ECONNREFUSED)
{
close (d->auth_fd);
d->auth_fd = -1;
free_string (d->username);
d->username = str_dup ("no_inetd");
d->auth_state = 0;
d->atimes = 500;
return;
}
d->auth_state |= (WRITE_AUTH | AUTH); /* Successful, but not sent */
return;
}
/* send_auth */
void
send_auth (struct descriptor_data *d)
{
struct sockaddr_in us, them;
char authbuf[32];
int ulen, tlen, z;
tlen = ulen = sizeof (us);
if (getsockname (d->descriptor, (struct sockaddr *) &us, &ulen)
|| getpeername (d->descriptor, (struct sockaddr *) &them, &tlen))
{
bug ("auth getsockname error", 0);
goto authsenderr;
}
/* compose request */
sprintf (authbuf, "%u , %u\r\n",
(unsigned int) ntohs (them.sin_port),
(unsigned int) ntohs (us.sin_port));
/*
sprintf( log_buf, "sending [%u , %u] to auth port %d:113",
(unsigned int)ntohs(them.sin_port),
(unsigned int)ntohs(us.sin_port), d->auth_fd );
log( log_buf, 0 );
*/
nonblock (d->auth_fd);
z = write (d->auth_fd, authbuf, strlen (authbuf));
if (errno == ECONNREFUSED || (z == -1 && d->atimes > 10))
{
close (d->auth_fd);
d->auth_fd = -1;
free_string (d->username);
d->username = str_dup ("no_identd");
d->auth_state = 0;
return;
}
if (z != strlen (authbuf))
{
if (d->atimes >= 15)
{
sprintf (log_buf, "auth request, broken pipe [%d/%d]", z, errno);
bug (log_buf, 0);
close (d->auth_fd);
d->auth_fd = -1;
d->auth_state -= WRITE_AUTH;
d->auth_state &= ~AUTH;
d->auth_inc = 0;
}
authsenderr:
d->atimes++;
return;
}
d->auth_state -= WRITE_AUTH; /* Successfully sent request */
d->atimes = 0;
return;
}
/* read_auth */
void
read_auth (struct descriptor_data *d)
{
char *s, *t;
int len; /* length read */
char ruser[100], system[100]; /* remote userid */
u_short remp = 0, locp = 0; /* remote port, local port */
*system = *ruser = '\0';
/*
* Can't allow any other reads from client fd while waiting on the
* authfd to return a full valid string. Use the client's input buffer
* to buffer the authd reply. May take more than one read.
*/
nonblock (d->auth_fd);
if ((len = read (d->auth_fd, d->abuf + d->auth_inc,
sizeof (d->abuf) - 1 - d->auth_inc)) >= 0)
{
d->auth_inc += len;
if (d->auth_inc > 90)
{
close (d->auth_fd);
d->auth_state = 0;
d->auth_fd = -1;
free_string (d->username);
d->username = str_dup ("no_identd");
d->atimes = 500;
return;
}
d->abuf[d->auth_inc] = '\0';
}
if (d->atimes < 20)
{
d->atimes++;
return;
}
if (d->abuf[0] != '\0')
if (
(sscanf (d->abuf, "%hd , %hd : USERID : %*[^:]: %10s",
&remp, &locp, ruser) == 3))
{
s = rindex (d->abuf, ':');
*s++ = '\0';
for (t = (rindex (d->abuf, ':') + 1); *t; t++)
if (!isspace (*t))
break;
strncpy (system, t, sizeof (system));
if (!str_prefix ("OTHER", system))
{
close (d->auth_fd);
d->auth_state = 0;
d->auth_fd = -1;
free_string (d->username);
d->username = str_dup ("no_identd");
d->atimes = 500;
return;
}
for (t = ruser; *s && (t < ruser + sizeof (ruser)); s++)
if (!isspace (*s) && *s != ':')
*t++ = *s;
*t = '\0';
sprintf (log_buf, "auth reply ok, incoming user: [%s]", ruser);
log_string (log_buf);
}
else if (len != 0)
{
if (!index (d->abuf, '\n') && !index (d->abuf, '\r'))
return;
sprintf (log_buf, "bad auth reply: %s", d->abuf);
*ruser = '\0';
}
close (d->auth_fd);
d->auth_inc = 0;
*d->abuf = '\0';
d->auth_fd = -1;
d->auth_state = 0;
if (ruser[0] == '\0')
strcpy (ruser, "no_inetd");
free_string (d->username);
d->username = str_dup (ruser);
return;
}
#ifdef WINDOWS
void
nonblock (int s)
{
if (fcntl (s, F_SETFL, FNDELAY) == -1)
{
perror ("Noblock");
/* exit(2); */
bug ("Noblock", 0);
}
}
#endif
#endif