OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / openswan / programs / tncfg / tncfg.c
1 /*
2  * IPSEC interface configuration
3  * Copyright (C) 1996  John Ioannidis.
4  * Copyright (C) 1998, 1999, 2000, 2001  Richard Guy Briggs.
5  * Copyright (C) 2006 Michael Richardson <mcr@xelerance.com>
6  * 
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the
9  * Free Software Foundation; either version 2 of the License, or (at your
10  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
11  * 
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * for more details.
16  */
17
18 char tncfg_c_version[] = "use ipsec --version instead";
19
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h> /* system(), strtoul() */
24 #include <unistd.h> /* getuid() */
25 #include <linux/types.h>
26 #include <sys/ioctl.h> /* ioctl() */
27
28 #include <openswan.h>
29 #ifdef NET_21 /* from openswan.h */
30 #include <linux/sockios.h>
31 #include <sys/socket.h>
32 #endif /* NET_21 */ /* from openswan.h */
33
34 #if 0
35 #include <linux/if.h>
36 #else
37 #include <net/if.h>
38 #endif
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/wait.h>
42 #include <errno.h>
43 #include <getopt.h>
44 #include "socketwrapper.h"
45 #include "oswlog.h"
46
47 #include "openswan/pfkey.h"
48 #include "openswan/pfkeyv2.h"
49 #include "pfkey_help.h"
50
51 #include "openswan/ipsec_tunnel.h"
52
53 char *progname;
54
55 static void
56 usage(char *name)
57 {       
58         fprintf(stdout,"%s --create <virtual>\n", name);
59         fprintf(stdout,"%s --delete <virtual>\n", name);
60         fprintf(stdout,"%s --attach --virtual <virtual-device> --physical <physical-device>\n",
61                 name);
62         fprintf(stdout,"%s --detach --virtual <virtual-device>\n",
63                 name);
64         fprintf(stdout,"%s --clear\n",
65                 name);
66         fprintf(stdout,"%s --help\n",
67                 name);
68         fprintf(stdout,"%s --version\n",
69                 name);
70         fprintf(stdout,"%s\n",
71                 name);
72         fprintf(stdout, "        [ --debug ] is optional to any %s command.\n", name);
73         fprintf(stdout, "        [ --label <label> ] is optional to any %s command.\n", name);
74         exit(1);
75 }
76
77 static struct option const longopts[] =
78 {
79         {"virtual", 1, 0, 'V'},
80         {"physical", 1, 0, 'P'},
81         {"create", required_argument, 0, 'C'},
82         {"delete", required_argument, 0, 'D'},
83         {"attach", 0, 0, 'a'},
84         {"detach", 0, 0, 'd'},
85         {"clear", 0, 0, 'c'},
86         {"help", 0, 0, 'h'},
87         {"version", 0, 0, 'v'},
88         {"label", 1, 0, 'l'},
89         {"optionsfrom", 1, 0, '+'},
90         {"debug", 0, 0, 'g'},
91         {0, 0, 0, 0}
92 };
93
94 void check_conflict(uint32_t cf_cmd, int createdelete)
95 {
96         if(cf_cmd || createdelete) {
97                 fprintf(stderr, "%s: exactly one of \n\t'--attach', '--detach', '--create', '--delete' or '--clear'\noptions must be specified.\n",
98                         progname);
99                 exit(1);
100         }
101 }
102
103 uint32_t pfkey_seq = 0;
104
105 int createdelete_virtual(int createdelete, char *virtname)
106 {
107         int vifnum;
108         struct sadb_ext *extensions[K_SADB_EXT_MAX + 1];
109         struct sadb_msg *pfkey_msg;
110         int error;
111         int io_error, pfkey_sock;
112         
113         if(sscanf(virtname, "mast%d", &vifnum)==1) {
114                 /* good */
115         } else if(sscanf(virtname, "ipsec%d", &vifnum)==1) {
116                 vifnum += IPSECDEV_OFFSET;
117         } else {
118                 return 5;
119         }
120
121         pfkey_extensions_init(extensions);
122
123         if((error = pfkey_msg_hdr_build(&extensions[0],
124                                         createdelete,
125                                         0, 0,
126                                         ++pfkey_seq,
127                                         getpid()))) {
128                 fprintf(stderr, "%s: Trouble building message header, error=%d.\n",
129                         progname, error);
130                 pfkey_extensions_free(extensions);
131                 exit(1);
132         }
133
134         if((error = pfkey_outif_build(&extensions[SADB_X_EXT_PLUMBIF], vifnum))) {
135                 fprintf(stderr, "%s: Trouble building outif extension, error=%d.\n",
136                         progname, error);
137                 pfkey_extensions_free(extensions);
138                 exit(1);
139         }
140
141         if((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN))) {
142                 fprintf(stderr, "%s: Trouble building pfkey message, error=%d.\n",
143                         progname, error);
144                 pfkey_extensions_free(extensions);
145                 pfkey_msg_free(&pfkey_msg);
146                 exit(1);
147         }
148
149         pfkey_sock = pfkey_open_sock_with_error();
150         if(pfkey_sock < 0) {
151             exit(1);
152         }
153
154         io_error = write(pfkey_sock,
155                          pfkey_msg,
156                          pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
157
158         
159         if(io_error != (pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) {
160                 perror("pfkey write");
161                 exit(2);
162         }
163         
164         return 0;
165 }
166
167 void exit_tool(int code)
168 {
169         exit(code);
170 }
171
172
173 int debug = 0;
174
175 int
176 main(int argc, char *argv[])
177 {
178         struct ifreq ifr;
179         struct ipsectunnelconf shc;
180         int s;
181         int c;
182         int argcount = argc;
183         int createdelete = 0;
184         char virtname[64];
185         struct stat sts;
186      
187         memset(&ifr, 0, sizeof(ifr));
188         memset(&shc, 0, sizeof(shc));
189         virtname[0]='\0';
190         progname = argv[0];
191
192         tool_init_log();
193
194         while((c = getopt_long_only(argc, argv, ""/*"adchvV:P:l:+:"*/, longopts, 0)) != EOF) {
195                 switch(c) {
196                 case 'g':
197                         debug = 1;
198                         argcount--;
199                         break;
200                 case 'a':
201                         check_conflict(shc.cf_cmd, createdelete);
202                         shc.cf_cmd = IPSEC_SET_DEV;
203                         break;
204                 case 'd':
205                         check_conflict(shc.cf_cmd, createdelete);
206                         shc.cf_cmd = IPSEC_DEL_DEV;
207                         break;
208                 case 'c':
209                         check_conflict(shc.cf_cmd, createdelete);
210                         shc.cf_cmd = IPSEC_CLR_DEV;
211                         break;
212                 case 'h':
213                         usage(progname);
214                         break;
215                 case 'v':
216                         if(optarg) {
217                                 fprintf(stderr, "%s: warning; '-v' and '--version' options don't expect arguments, arg '%s' found, perhaps unintended.\n",
218                                         progname, optarg);
219                         }
220                         fprintf(stdout, "%s, %s\n", progname, tncfg_c_version);
221                         exit(1);
222                         break;
223
224                 case 'C':
225                         check_conflict(shc.cf_cmd, createdelete);
226                         createdelete = SADB_X_PLUMBIF;
227                         strncat(virtname, optarg, sizeof(virtname)-1);
228                         break;
229                 case 'D':
230                         check_conflict(shc.cf_cmd, createdelete);
231                         createdelete = SADB_X_UNPLUMBIF;
232                         strncat(virtname, optarg, sizeof(virtname)-1);
233                         break;
234
235                 case 'V':
236                         strncpy(ifr.ifr_name, optarg, sizeof(ifr.ifr_name));
237                         break;
238                 case 'P':
239                         strncpy(shc.cf_name, optarg, sizeof(shc.cf_name));
240                         break;
241                 case 'l':
242                         progname = malloc(strlen(argv[0])
243                                               + 10 /* update this when changing the sprintf() */
244                                               + strlen(optarg));
245                         sprintf(progname, "%s --label %s",
246                                 argv[0],
247                                 optarg);
248                         argcount -= 2;
249                         break;
250                 case '+': /* optionsfrom */
251                         optionsfrom(optarg, &argc, &argv, optind, stderr);
252                         /* no return on error */
253                         break;
254                 default:
255                         usage(progname);
256                         break;
257                 }
258         }
259
260         if ( ((stat ("/proc/net/pfkey", &sts)) == 0) )  {
261                 fprintf(stderr, "%s: NETKEY does not support virtual interfaces.\n",progname);
262                 exit(1);
263         }
264
265         if(argcount == 1) {
266                 int ret = 1;
267                 if ((stat ("/proc/net/ipsec_tncfg", &sts)) != 0)  {
268                         fprintf(stderr, "%s: No tncfg - no IPsec support in kernel (are the modules loaded?)\n", progname);
269                 } else {
270                         ret = system("cat /proc/net/ipsec_tncfg");
271                         ret = ret != -1 && WIFEXITED(ret) ? WEXITSTATUS(ret) : 1;
272                 }
273                 exit(ret);
274         }
275
276         /* overlay our struct ipsectunnel onto ifr.ifr_ifru union (hope it fits!) */
277         if (sizeof(ifr.ifr_ifru) < sizeof(shc)) {
278             fprintf(stderr, "%s: Internal error: struct ipsectunnelconf won't fit inside struct ifreq\n",
279                 progname);
280             exit(1);
281         }
282         memcpy(&ifr.ifr_ifru.ifru_newname, &shc, sizeof(shc));
283
284         /* are we creating/deleting a virtual (mastXXX/ipsecXXX) interface? */
285         if(createdelete) {
286                 exit(createdelete_virtual(createdelete, virtname));
287         }
288
289         switch(shc.cf_cmd) {
290         case IPSEC_SET_DEV:
291                 if(!shc.cf_name[0]) {
292                         fprintf(stderr, "%s: physical I/F parameter missing.\n",
293                                 progname);
294                         exit(1);
295                 }
296         case IPSEC_DEL_DEV:
297                 if(!ifr.ifr_name[0]) {
298                         fprintf(stderr, "%s: virtual I/F parameter missing.\n",
299                                 progname);
300                         exit(1);
301                 }
302                 break;
303         case IPSEC_CLR_DEV:
304                 strncpy(ifr.ifr_name, "ipsec0", sizeof(ifr.ifr_name));
305                 break;
306         default:
307                 fprintf(stderr, "%s: exactly one of '--attach', '--detach' or '--clear' options must be specified.\n"
308                         "Try %s --help' for usage information.\n",
309                         progname, progname);
310                 exit(1);
311         }
312
313         s=safe_socket(AF_INET, SOCK_DGRAM,0);
314         if(s==-1)
315         {
316                 fprintf(stderr, "%s: Socket creation failed -- ", progname);
317                 switch(errno)
318                 {
319                 case EACCES:
320                         if(getuid()==0)
321                                 fprintf(stderr, "Root denied permission!?!\n");
322                         else
323                                 fprintf(stderr, "Run as root user.\n");
324                         break;
325                 case EPROTONOSUPPORT:
326                         fprintf(stderr, "Internet Protocol not enabled");
327                         break;
328                 case EMFILE:
329                 case ENFILE:
330                 case ENOBUFS:
331                         fprintf(stderr, "Insufficient system resources.\n");
332                         break;
333                 case ENODEV:
334                         fprintf(stderr, "No such device.  Is the virtual device valid?  Is the ipsec module linked into the kernel or loaded as a module?\n");
335                         break;
336                 default:
337                         fprintf(stderr, "Unknown socket error %d.\n", errno);
338                 }
339                 exit(1);
340         }
341         if(ioctl(s, shc.cf_cmd, &ifr)==-1)
342         {
343                 switch (shc.cf_cmd)
344                 {
345                 case IPSEC_SET_DEV:
346                         fprintf(stderr, "%s: Socket ioctl failed on attach -- ", progname);
347                         switch(errno)
348                         {
349                         case EINVAL:
350                                 fprintf(stderr, "Invalid argument, check kernel log messages for specifics.\n");
351                                 break;
352                         case ENODEV:
353                                 fprintf(stderr, "No such device.  Is the virtual device valid?  Is the ipsec module linked into the kernel or loaded as a module?\n");
354                                 break;
355                         case ENXIO:
356                                 fprintf(stderr, "No such device.  Is the physical device valid?\n");
357                                 break;
358                         case EBUSY:
359                                 fprintf(stderr, "Device busy.  Virtual device %s is already attached to a physical device -- Use detach first.\n",
360                                        ifr.ifr_name);
361                                 break;
362                         default:
363                                 fprintf(stderr, "Unknown socket error %d.\n", errno);
364                         }
365                         exit(1);
366
367                 case IPSEC_DEL_DEV:
368                         fprintf(stderr, "%s: Socket ioctl failed on detach -- ", progname);
369                         switch(errno)
370                         {
371                         case EINVAL:
372                                 fprintf(stderr, "Invalid argument, check kernel log messages for specifics.\n");
373                                 break;
374                         case ENODEV:
375                                 fprintf(stderr, "No such device.  Is the virtual device valid?  The ipsec module may not be linked into the kernel or loaded as a module.\n");
376                                 break;
377                         case ENXIO:
378                                 fprintf(stderr, "Device requested is not linked to any physical device.\n");
379                                 break;
380                         default:
381                                 fprintf(stderr, "Unknown socket error %d.\n", errno);
382                         }
383                         exit(1);
384
385                 case IPSEC_CLR_DEV:
386                         fprintf(stderr, "%s: Socket ioctl failed on clear -- ", progname);
387                         switch(errno)
388                         {
389                         case EINVAL:
390                                 fprintf(stderr, "Invalid argument, check kernel log messages for specifics.\n");
391                                 break;
392                         case ENODEV:
393                                 fprintf(stderr, "Failed.  Is the ipsec module linked into the kernel or loaded as a module?.\n");
394                                 break;
395                         default:
396                                 fprintf(stderr, "Unknown socket error %d.\n", errno);
397                         }
398                         exit(1);
399                 default:
400                         fprintf(stderr, "%s: Socket ioctl failed on unknown operation %u -- %s", progname, (unsigned) shc.cf_cmd, strerror(errno));
401                         exit(1);
402                 }
403         }
404         exit(0);
405 }
406         
407 /*
408  * $Log: tncfg.c,v $
409  * Revision 1.33  2005/07/08 02:56:38  paul
410  * gcc4 fixes that were not commited because vault was down
411  *
412  * Revision 1.32  2004/04/06 03:05:06  mcr
413  *      freeswan->openswan changes.
414  *
415  * Revision 1.31  2004/04/04 01:53:50  ken
416  * Use openswan includes
417  *
418  * Revision 1.30  2002/04/24 07:55:32  mcr
419  *      #include patches and Makefiles for post-reorg compilation.
420  *
421  * Revision 1.29  2002/04/24 07:35:41  mcr
422  * Moved from ./klips/utils/tncfg.c,v
423  *
424  * Revision 1.28  2002/03/08 21:44:05  rgb
425  * Update for all GNU-compliant --version strings.
426  *
427  * Revision 1.27  2001/06/14 19:35:15  rgb
428  * Update copyright date.
429  *
430  * Revision 1.26  2001/05/21 02:02:55  rgb
431  * Eliminate 1-letter options.
432  *
433  * Revision 1.25  2001/05/16 05:07:20  rgb
434  * Fixed --label option in KLIPS manual utils to add the label to the
435  * command name rather than replace it in error text.
436  * Fix 'print table' non-option in KLIPS manual utils to deal with --label
437  * and --debug options.
438  *
439  * Revision 1.24  2000/09/12 13:09:05  rgb
440  * Fixed real/physical discrepancy between tncfg.8 and tncfg.c.
441  *
442  * Revision 1.23  2000/08/27 01:48:30  rgb
443  * Update copyright.
444  *
445  * Revision 1.22  2000/07/26 03:41:46  rgb
446  * Changed all printf's to fprintf's.  Fixed tncfg's usage to stderr.
447  *
448  * Revision 1.21  2000/06/21 16:51:27  rgb
449  * Added no additional argument option to usage text.
450  *
451  * Revision 1.20  2000/01/21 06:26:31  rgb
452  * Added --debug switch to command line.
453  *
454  * Revision 1.19  1999/12/08 20:32:41  rgb
455  * Cleaned out unused cruft.
456  * Changed include file, limiting scope, to avoid conflicts in 2.0.xx
457  * kernels.
458  *
459  * Revision 1.18  1999/12/07 18:27:10  rgb
460  * Added headers to silence fussy compilers.
461  * Converted local functions to static to limit scope.
462  *
463  * Revision 1.17  1999/11/18 04:09:21  rgb
464  * Replaced all kernel version macros to shorter, readable form.
465  *
466  * Revision 1.16  1999/05/25 01:45:36  rgb
467  * Fix version macros for 2.0.x as a module.
468  *
469  * Revision 1.15  1999/05/05 22:02:34  rgb
470  * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
471  *
472  * Revision 1.14  1999/04/15 15:37:28  rgb
473  * Forward check changes from POST1_00 branch.
474  *
475  * Revision 1.10.6.2  1999/04/13 20:58:10  rgb
476  * Add argc==1 --> /proc/net/ipsec_*.
477  *
478  * Revision 1.10.6.1  1999/03/30 17:01:36  rgb
479  * Make main() return type explicit.
480  *
481  * Revision 1.13  1999/04/11 00:12:09  henry
482  * GPL boilerplate
483  *
484  * Revision 1.12  1999/04/06 04:54:39  rgb
485  * Fix/Add RCSID Id: and Log: bits to make PHMDs happy.  This includes
486  * patch shell fixes.
487  *
488  * Revision 1.11  1999/03/17 15:40:54  rgb
489  * Make explicit main() return type of int.
490  *
491  * Revision 1.10  1998/11/12 21:08:04  rgb
492  * Add --label option to identify caller from scripts.
493  *
494  * Revision 1.9  1998/10/09 18:47:30  rgb
495  * Add 'optionfrom' to get more options from a named file.
496  *
497  * Revision 1.8  1998/10/09 04:36:55  rgb
498  * Changed help output from stderr to stdout.
499  * Deleted old commented out cruft.
500  *
501  * Revision 1.7  1998/08/28 03:15:14  rgb
502  * Add some manual long options to the usage text.
503  *
504  * Revision 1.6  1998/08/05 22:29:00  rgb
505  * Change includes to accomodate RH5.x.
506  * Force long option names.
507  * Add ENXIO error return code to narrow down error reporting.
508  *
509  * Revision 1.5  1998/07/29 21:45:28  rgb
510  * Convert to long option names.
511  *
512  * Revision 1.4  1998/07/09 18:14:11  rgb
513  * Added error checking to IP's and keys.
514  * Made most error messages more specific rather than spamming usage text.
515  * Added more descriptive kernel error return codes and messages.
516  * Converted all spi translations to unsigned.
517  * Removed all invocations of perror.
518  *
519  * Revision 1.3  1998/05/27 18:48:20  rgb
520  * Adding --help and --version directives.
521  *
522  * Revision 1.2  1998/04/23 21:11:39  rgb
523  * Fixed 0 argument usage case to prevent sigsegv.
524  *
525  * Revision 1.1.1.1  1998/04/08 05:35:09  henry
526  * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
527  *
528  * Revision 0.5  1997/06/03 04:31:55  ji
529  * New file.
530  *
531  */