Files
org-hyperion-cules/hercifc.c
2014-07-13 00:10:18 -07:00

280 lines
8.4 KiB
C

/* HERCIFC.H (c) Copyright Roger Bowler, 2000-2012 */
/* (c) Copyright James A. Pierson, 2002-2009 */
/* Hercules Interface Configuration Program */
/* */
/* Released under "The Q Public License Version 1" */
/* (http://www.hercules-390.org/herclic.html) as modifications to */
/* Hercules. */
// Based on code originally written by Roger Bowler
// Modified to communicate via unix sockets.
//
// This module configures the TUN/TAP interface for Hercules.
// It is invoked as a setuid root program by tuntap.c
//
// The are no command line arguments anymore.
//
// Error messages are written to stderr, which is redirected to
// the Hercules message log by ctcadpt.c
//
// The exit status is zero if successful, non-zero if error.
//
#include "hstdinc.h"
#if defined(BUILD_HERCIFC)
#include "hercules.h"
#include "hercifc.h"
// --------------------------------------------------------------------
// HERCIFC program entry point
// --------------------------------------------------------------------
int main( int argc, char **argv )
{
char* pszProgName = NULL; // Name of this program
char* pOp = NULL; // Operation text
char* pIF = NULL; // -> interface name
void* pArg = NULL; // -> hifr or rtentry
CTLREQ ctlreq; // Request Buffer
int fd_inet; // Socket descriptor
#if defined(ENABLE_IPV6)
int fd_inet6; // Socket descriptor
#endif /* defined(ENABLE_IPV6) */
int fd; // FD for ioctl
int rc; // Return code
pid_t ppid; // Parent's PID
int answer; // 1 = write answer to stdout
char szMsgBuffer[255];
UNREFERENCED( argc );
DROP_PRIVILEGES(CAP_NET_ADMIN);
pszProgName = strdup( argv[0] );
// Must not be run from the commandline
if( isatty( STDIN_FILENO ) )
{
fprintf( stderr,
_("HHCIF001E %s: Must be called from within Hercules.\n"),
pszProgName );
exit( 1 );
}
// Obtain a socket for ioctl operations
fd_inet = socket( AF_INET, SOCK_DGRAM, 0 );
if( fd_inet < 0 )
{
fprintf( stderr,
_("HHCIF002E %s: Cannot obtain inet socket: %s\n"),
pszProgName, strerror( errno ) );
exit( 2 );
}
#if defined(ENABLE_IPV6)
fd_inet6 = socket( AF_INET6, SOCK_DGRAM, 0 );
if( fd_inet6 < 0 )
{
fprintf( stderr,
_("HHCIF002E %s: Cannot obtain inet6 socket: %s\n"),
pszProgName, strerror( errno ) );
fd_inet6 = fd_inet;
}
#endif /* defined(ENABLE_IPV6) */
ppid = getppid();
// Process ioctl messages from Hercules
while( 1 )
{
rc = read( STDIN_FILENO,
&ctlreq,
CTLREQ_SIZE );
if( rc == -1 )
{
fprintf( stderr,
_("HHCIF003E %s: I/O error on read: %s.\n"),
pszProgName, strerror( errno ) );
exit( 3 );
}
if( ppid != getppid() )
{
sleep( 1 ); // Let other messages go first
fprintf( stderr,
_("HHCIF007E %s: Hercules disappeared!! .. exiting\n"),
pszProgName);
exit( 4 );
}
fd = fd_inet;
answer = 0;
switch( ctlreq.iCtlOp )
{
#if !defined(__APPLE__) && !defined(__FreeBSD__)
case TUNSETIFF:
pOp = "TUNSETIFF";
pArg = &ctlreq.iru.hifr.ifreq;
pIF = "?";
fd = ctlreq.iProcID;
answer = 1;
break;
#endif
case SIOCSIFADDR:
pOp = "SIOCSIFADDR";
#if defined(ENABLE_IPV6)
if( ctlreq.iru.hifr.hifr_afamily == AF_INET6 )
{
pArg = &ctlreq.iru.hifr.in6_ifreq;
fd = fd_inet6;
}
else
#endif /* defined(ENABLE_IPV6) */
{
pArg = &ctlreq.iru.hifr.ifreq;
}
pIF = ctlreq.iru.hifr.hifr_name;
break;
case SIOCSIFDSTADDR:
pOp = "SIOCSIFDSTADDR";
pArg = &ctlreq.iru.hifr.ifreq;
pIF = ctlreq.iru.hifr.hifr_name;
break;
case SIOCSIFFLAGS:
pOp = "SIOCSIFFLAGS";
pArg = &ctlreq.iru.hifr.ifreq;
pIF = ctlreq.iru.hifr.hifr_name;
break;
#if 0 /* (hercifc can't "get" information, only "set" it) */
case SIOCGIFFLAGS:
pOp = "SIOCGIFFLAGS";
pArg = &ctlreq.iru.hifr.ifreq;
pIF = ctlreq.iru.hifr.hifr_name;
answer = 1;
break;
#endif /* (caller should do 'ioctl' directly themselves instead) */
case SIOCSIFMTU:
pOp = "SIOCSIFMTU";
pArg = &ctlreq.iru.hifr.ifreq;
pIF = ctlreq.iru.hifr.hifr_name;
break;
case SIOCADDMULTI:
pOp = "SIOCADDMULTI";
pArg = &ctlreq.iru.hifr.ifreq;
pIF = ctlreq.iru.hifr.hifr_name;
break;
case SIOCDELMULTI:
pOp = "SIOCDELMULTI";
pArg = &ctlreq.iru.hifr.ifreq;
pIF = ctlreq.iru.hifr.hifr_name;
break;
#ifdef OPTION_TUNTAP_SETNETMASK
case SIOCSIFNETMASK:
pOp = "SIOCSIFNETMASK";
pArg = &ctlreq.iru.hifr.ifreq;
pIF = ctlreq.iru.hifr.hifr_name;
break;
#endif
#ifdef OPTION_TUNTAP_SETMACADDR
case SIOCSIFHWADDR:
pOp = "SIOCSIFHWADDR";
pArg = &ctlreq.iru.hifr.ifreq;
pIF = ctlreq.iru.hifr.hifr_name;
break;
#endif
#ifdef OPTION_TUNTAP_DELADD_ROUTES
case SIOCADDRT:
pOp = "SIOCADDRT";
pArg = &ctlreq.iru.rtentry;
pIF = ctlreq.szIFName;
ctlreq.iru.rtentry.rt_dev = ctlreq.szIFName;
break;
case SIOCDELRT:
pOp = "SIOCDELRT";
pArg = &ctlreq.iru.rtentry;
pIF = ctlreq.szIFName;
ctlreq.iru.rtentry.rt_dev = ctlreq.szIFName;
break;
#endif
#ifdef OPTION_TUNTAP_CLRIPADDR
case SIOCDIFADDR:
pOp = "SIOCDIFADDR";
pArg = &ctlreq.iru.hifr.ifreq;
pIF = ctlreq.iru.hifr.hifr_name;
break;
#endif
case CTLREQ_OP_DONE:
close( STDIN_FILENO );
close( STDOUT_FILENO );
close( STDERR_FILENO );
exit( 0 );
default:
snprintf( szMsgBuffer,sizeof(szMsgBuffer),
_("HHCIF004W %s: Unknown request: %lX\n"),
pszProgName, ctlreq.iCtlOp );
write( STDERR_FILENO, szMsgBuffer, strlen( szMsgBuffer ) );
continue;
}
#if defined(DEBUG) || defined(_DEBUG)
snprintf( szMsgBuffer,sizeof(szMsgBuffer),
_("HHCIF006I %s: Doing %s on %s\n"),
pszProgName, pOp, pIF);
write( STDERR_FILENO, szMsgBuffer, strlen( szMsgBuffer ) );
#endif /*defined(DEBUG) || defined(_DEBUG)*/
rc = ioctl( fd, ctlreq.iCtlOp, pArg );
if( rc < 0 )
{
if (1
#if defined(SIOCSIFHWADDR) && defined(ENOTSUP)
/* Suppress spurious error message */
&& !(ctlreq.iCtlOp == SIOCSIFHWADDR && errno == ENOTSUP)
#endif
#if defined(SIOCDIFADDR) && defined(EINVAL)
/* Suppress spurious error message */
&& !(ctlreq.iCtlOp == SIOCDIFADDR && errno == EINVAL)
#endif
#if defined(TUNSETIFF) && defined(EINVAL)
/* Suppress spurious error message */
&& !(ctlreq.iCtlOp == TUNSETIFF && errno == EINVAL)
#endif
)
{
snprintf( szMsgBuffer,sizeof(szMsgBuffer),
_("HHCIF005E %s: ioctl error doing %s on %s: %d %s\n"),
pszProgName, pOp, pIF, errno, strerror( errno ) );
write( STDERR_FILENO, szMsgBuffer, strlen( szMsgBuffer ) );
}
}
else if (answer)
{
write( STDOUT_FILENO, &ctlreq, CTLREQ_SIZE );
}
}
UNREACHABLE_CODE();
}
#endif // defined(BUILD_HERCIFC)