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