1 /* HERCIFC.C    (c) Copyright Roger Bowler, 2000-2012                */
2 /*              (c) Copyright James A. Pierson, 2002-2009            */
3 /*              Hercules Interface Configuration Program             */
4 
5 // Based on code originally written by Roger Bowler
6 // Modified to communicate via unix sockets.
7 //
8 // This module configures the TUN/TAP interface for Hercules.
9 // It is invoked as a setuid root program by tuntap.c
10 //
11 // The are no command line arguments anymore.
12 //
13 // Error messages are written to stderr, which is redirected to
14 // the Hercules message log by ctcadpt.c
15 //
16 // The exit status is zero if successful, non-zero if error.
17 //
18 
19 #include "hstdinc.h"
20 
21 #if defined(BUILD_HERCIFC)
22 #include "hercules.h"
23 #include "hercifc.h"
24 
25 // --------------------------------------------------------------------
26 // HERCIFC program entry point
27 // --------------------------------------------------------------------
28 
main(int argc,char ** argv)29 int main( int argc, char **argv )
30 {
31     char*       pszProgName  = NULL;    // Name of this program
32     char*       pOp          = NULL;    // Operation text
33     char*       pIF          = NULL;    // -> interface name
34     void*       pArg         = NULL;    // -> ifreq or rtentry
35     CTLREQ      ctlreq;                 // Request Buffer
36     int         sockfd;                 // Socket descriptor
37     int         fd;                     // FD for ioctl
38     int         rc;                     // Return code
39     pid_t       ppid;                   // Parent's PID
40     int         answer;                 // 1 = write answer to stdout
41     char        szMsgBuffer[255];
42 
43     UNREFERENCED( argc );
44 
45     DROP_PRIVILEGES(CAP_NET_ADMIN);
46 
47     pszProgName = strdup( argv[0] );
48 
49     // Must not be run from the commandline
50     if( isatty( STDIN_FILENO ) )
51     {
52         fprintf( stderr,
53                  _("HHCIF001E %s: Must be called from within Hercules.\n"),
54                  pszProgName );
55         exit( 1 );
56     }
57 
58     // Obtain a socket for ioctl operations
59     sockfd = socket( AF_INET, SOCK_DGRAM, 0 );
60 
61     if( sockfd < 0 )
62     {
63         fprintf( stderr,
64                  _("HHCIF002E %s: Cannot obtain socket: %s\n"),
65                  pszProgName, strerror( errno ) );
66         exit( 2 );
67     }
68 
69     ppid = getppid();
70 
71     // Process ioctl messages from Hercules
72     while( 1 )
73     {
74         rc = read( STDIN_FILENO,
75                    &ctlreq,
76                    CTLREQ_SIZE );
77 
78         if( rc == -1 )
79         {
80             fprintf( stderr,
81                      _("HHCIF003E %s: I/O error on read: %s.\n"),
82                      pszProgName, strerror( errno ) );
83             exit( 3 );
84         }
85 
86         if( ppid != getppid() )
87         {
88             sleep( 1 ); // Let other messages go first
89             fprintf( stderr,
90                      _("HHCIF007E %s: Hercules disappeared!! .. exiting\n"),
91                      pszProgName);
92             exit( 4 );
93         }
94 
95         fd = sockfd;
96         answer = 0;
97 
98         switch( ctlreq.iCtlOp )
99         {
100         case TUNSETIFF:
101             pOp  = "TUNSETIFF";
102             pArg = &ctlreq.iru.ifreq;
103             pIF  = "?";
104             fd = ctlreq.iProcID;
105             answer = 1;
106             break;
107 
108         case SIOCSIFADDR:
109             pOp  = "SIOCSIFADDR";
110             pArg = &ctlreq.iru.ifreq;
111             pIF  = ctlreq.iru.ifreq.ifr_name;
112             break;
113 
114         case SIOCSIFDSTADDR:
115             pOp  = "SIOCSIFDSTADDR";
116             pArg = &ctlreq.iru.ifreq;
117             pIF  = ctlreq.iru.ifreq.ifr_name;
118             break;
119 
120         case SIOCSIFFLAGS:
121             pOp  = "SIOCSIFFLAGS";
122             pArg = &ctlreq.iru.ifreq;
123             pIF  = ctlreq.iru.ifreq.ifr_name;
124             break;
125 
126 #if 0 /* (hercifc can't "get" information, only "set" it) */
127         case SIOCGIFFLAGS:
128             pOp  = "SIOCGIFFLAGS";
129             pArg = &ctlreq.iru.ifreq;
130             pIF  = ctlreq.iru.ifreq.ifr_name;
131             answer = 1;
132             break;
133 #endif /* (caller should do 'ioctl' directly themselves instead) */
134 
135         case SIOCSIFMTU:
136             pOp  = "SIOCSIFMTU";
137             pArg = &ctlreq.iru.ifreq;
138             pIF  = ctlreq.iru.ifreq.ifr_name;
139             break;
140 
141         case SIOCADDMULTI:
142             pOp  = "SIOCADDMULTI";
143             pArg = &ctlreq.iru.ifreq;
144             pIF  = ctlreq.iru.ifreq.ifr_name;
145             break;
146 
147         case SIOCDELMULTI:
148             pOp  = "SIOCDELMULTI";
149             pArg = &ctlreq.iru.ifreq;
150             pIF  = ctlreq.iru.ifreq.ifr_name;
151             break;
152 
153 #ifdef OPTION_TUNTAP_SETNETMASK
154         case SIOCSIFNETMASK:
155             pOp  = "SIOCSIFNETMASK";
156             pArg = &ctlreq.iru.ifreq;
157             pIF  = ctlreq.iru.ifreq.ifr_name;
158             break;
159 #endif
160 #ifdef OPTION_TUNTAP_SETMACADDR
161         case SIOCSIFHWADDR:
162             pOp  = "SIOCSIFHWADDR";
163             pArg = &ctlreq.iru.ifreq;
164             pIF  = ctlreq.iru.ifreq.ifr_name;
165             break;
166 #endif
167 #ifdef OPTION_TUNTAP_DELADD_ROUTES
168         case SIOCADDRT:
169             pOp  = "SIOCADDRT";
170             pArg = &ctlreq.iru.rtentry;
171             pIF  = ctlreq.szIFName;
172             ctlreq.iru.rtentry.rt_dev = ctlreq.szIFName;
173             break;
174 
175         case SIOCDELRT:
176             pOp  = "SIOCDELRT";
177             pArg = &ctlreq.iru.rtentry;
178             pIF  = ctlreq.szIFName;
179             ctlreq.iru.rtentry.rt_dev = ctlreq.szIFName;
180             break;
181 #endif
182 #ifdef OPTION_TUNTAP_CLRIPADDR
183         case SIOCDIFADDR:
184             pOp  = "SIOCDIFADDR";
185             pArg = &ctlreq.iru.ifreq;
186             pIF  = ctlreq.iru.ifreq.ifr_name;
187             break;
188 #endif
189         case CTLREQ_OP_DONE:
190             close( STDIN_FILENO  );
191             close( STDOUT_FILENO );
192             close( STDERR_FILENO );
193             exit( 0 );
194 
195         default:
196             snprintf( szMsgBuffer,sizeof(szMsgBuffer),
197                      _("HHCIF004W %s: Unknown request: %lX\n"),
198                      pszProgName, ctlreq.iCtlOp );
199             write( STDERR_FILENO, szMsgBuffer, strlen( szMsgBuffer ) );
200             continue;
201         }
202 
203 #if defined(DEBUG) || defined(_DEBUG)
204         snprintf( szMsgBuffer,sizeof(szMsgBuffer),
205                  _("HHCIF006I %s: Doing %s on %s\n"),
206                  pszProgName, pOp, pIF);
207 
208         write( STDERR_FILENO, szMsgBuffer, strlen( szMsgBuffer ) );
209 #endif /*defined(DEBUG) || defined(_DEBUG)*/
210 
211         rc = ioctl( fd, ctlreq.iCtlOp, pArg );
212         if( rc < 0 )
213         {
214             if (1
215         #if defined(SIOCSIFHWADDR) && defined(ENOTSUP)
216                  /* Suppress spurious error message */
217              && !(ctlreq.iCtlOp == SIOCSIFHWADDR && errno == ENOTSUP)
218         #endif
219         #if defined(SIOCDIFADDR) && defined(EINVAL)
220                  /* Suppress spurious error message */
221              && !(ctlreq.iCtlOp == SIOCDIFADDR   && errno == EINVAL)
222         #endif
223         #if defined(TUNSETIFF) && defined(EINVAL)
224                  /* Suppress spurious error message */
225              && !(ctlreq.iCtlOp == TUNSETIFF   && errno == EINVAL)
226         #endif
227                )
228             {
229                 snprintf( szMsgBuffer,sizeof(szMsgBuffer),
230                      _("HHCIF005E %s: ioctl error doing %s on %s: %d %s\n"),
231                      pszProgName, pOp, pIF, errno, strerror( errno ) );
232 
233                 write( STDERR_FILENO, szMsgBuffer, strlen( szMsgBuffer ) );
234             }
235         }
236         else if (answer)
237         {
238             write( STDOUT_FILENO, &ctlreq, CTLREQ_SIZE );
239         }
240     }
241 
242     // Never reached.
243     return 0;
244 }
245 
246 #endif // defined(BUILD_HERCIFC)
247 
248