LTP GCOV extension - code coverage report
Current view: directory - trunk/src - main.c
Test: lcov.info
Date: 2007-05-09 Instrumented lines: 184
Code covered: 0.0 % Executed lines: 0

       1                 : /*
       2                 :  * main.c - Unix Teredo server & relay implementation
       3                 :  *          command line handling and core functions
       4                 :  * $Id: main.c 1938 2007-02-22 20:55:28Z remi $
       5                 :  */
       6                 : 
       7                 : /***********************************************************************
       8                 :  *  Copyright © 2004-2007 Rémi Denis-Courmont.                         *
       9                 :  *  This program is free software; you can redistribute and/or modify  *
      10                 :  *  it under the terms of the GNU General Public License as published  *
      11                 :  *  by the Free Software Foundation; version 2 of the license.         *
      12                 :  *                                                                     *
      13                 :  *  This program is distributed in the hope that it will be useful,    *
      14                 :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of     *
      15                 :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               *
      16                 :  *  See the GNU General Public License for more details.               *
      17                 :  *                                                                     *
      18                 :  *  You should have received a copy of the GNU General Public License  *
      19                 :  *  along with this program; if not, you can get it from:              *
      20                 :  *  http://www.gnu.org/copyleft/gpl.html                               *
      21                 :  ***********************************************************************/
      22                 : 
      23                 : #ifdef HAVE_CONFIG_H
      24                 : # include <config.h>
      25                 : #endif
      26                 : 
      27                 : #include <gettext.h>
      28                 : #include "binreloc.h"
      29                 : 
      30                 : #include <stdio.h>
      31                 : #include <stdlib.h> /* strtoul(), clearenv() */
      32                 : #include <string.h> /* strerror() */
      33                 : 
      34                 : #include <locale.h>
      35                 : 
      36                 : #include <sys/types.h>
      37                 : #include <sys/time.h> /* for <sys/resource.h> */
      38                 : #include <sys/resource.h> /* getrlimit() */
      39                 : #include <sys/stat.h> /* fstat(), mkdir */
      40                 : #include <unistd.h>
      41                 : #include <errno.h> /* errno */
      42                 : #include <fcntl.h> /* O_RDONLY */
      43                 : #include <resolv.h> /* res_init() */
      44                 : #include <pthread.h>
      45                 : #ifdef HAVE_SYS_CAPABILITY_H
      46                 : # include <sys/capability.h>
      47                 : #endif
      48                 : 
      49                 : #include <pwd.h> /* getpwnam() */
      50                 : #include <grp.h> /* setgroups() */
      51                 : 
      52                 : #ifdef HAVE_GETOPT_H
      53                 : # include <getopt.h>
      54                 : #endif
      55                 : 
      56                 : #include "miredo.h"
      57                 : 
      58                 : /*
      59                 :  * RETURN VALUES:
      60                 :  * 0: ok
      61                 :  * 1: I/O error
      62                 :  * 2: command line syntax error
      63                 :  */
      64                 : 
      65                 : static int
      66                 : quick_usage (const char *path)
      67               0 : {
      68               0 :         fprintf (stderr, _("Try \"%s -h | more\" for more information.\n"),
      69                 :                  path);
      70               0 :         return 2;
      71                 : }
      72                 : 
      73                 : 
      74                 : static int
      75                 : usage (const char *path)
      76               0 : {
      77               0 :         printf (_(
      78                 : "Usage: %s [OPTIONS] [SERVER_NAME]\n"
      79                 : "Creates a Teredo tunneling interface for encapsulation of IPv6 over UDP.\n"
      80                 : "\n"
      81                 : "  -c, --config     specify an configuration file\n"
      82                 : "  -f, --foreground run in the foreground\n"
      83                 : "  -h, --help       display this help and exit\n"
      84                 : "  -p, --pidfile    override the location of the PID file\n"
      85                 : "  -u, --user       override the user to set UID to\n"
      86                 : "  -V, --version    display program version and exit\n"), path);
      87               0 :         return 0;
      88                 : }
      89                 : 
      90                 : 
      91                 : extern int
      92                 : miredo_version (void)
      93               0 : {
      94                 : #ifndef VERSION
      95                 : # define VERSION "unknown version"
      96                 : #endif
      97               0 :         printf (_("Miredo: Teredo IPv6 tunneling software %s (%s)\n"
      98                 :                   " built %s on %s (%s)\n"),
      99                 :                 VERSION, PACKAGE_HOST, __DATE__,
     100                 :                 PACKAGE_BUILD_HOSTNAME, PACKAGE_BUILD);
     101               0 :         printf (_("Configured with: %s\n"), PACKAGE_CONFIGURE_INVOCATION);
     102               0 :         puts (_("Written by Remi Denis-Courmont.\n"));
     103                 : 
     104               0 :         printf (_("Copyright (C) 2004-%u Remi Denis-Courmont\n"
     105                 : "This is free software; see the source for copying conditions.\n"
     106                 : "There is NO warranty; not even for MERCHANTABILITY or\n"
     107                 : "FITNESS FOR A PARTICULAR PURPOSE.\n"), 2006);
     108               0 :         return 0;
     109                 : }
     110                 : 
     111                 : 
     112                 : static int
     113                 : error_dup (int opt, const char *already, const char *additionnal)
     114               0 : {
     115               0 :         fprintf (stderr, _(
     116                 : "Duplicate parameter \"%s\" for option -%c\n"
     117                 : "would override previous value \"%s\".\n"),
     118                 :                  additionnal, opt, already);
     119               0 :         return 2;
     120                 : }
     121                 : 
     122                 : 
     123                 : #if 0
     124                 : static int
     125                 : error_qty (int opt, const char *qty)
     126                 : {
     127                 :         fprintf (stderr, _(
     128                 : "Invalid number (or capacity exceeded) \"%s\" for option -%c\n"), qty, opt);
     129                 :         return 2;
     130                 : }
     131                 : #endif
     132                 : 
     133                 : 
     134                 : static int
     135                 : error_extra (const char *extra)
     136               0 : {
     137               0 :         fprintf (stderr, _("%s: unexpected extra parameter\n"), extra);
     138               0 :         return 2;
     139                 : }
     140                 : 
     141                 : 
     142                 : static int
     143                 : error_errno (const char *str)
     144               0 : {
     145               0 :         fprintf (stderr, _("Error (%s): %s\n"), str, strerror (errno));
     146               0 :         return -1;
     147                 : }
     148                 : 
     149                 : 
     150                 : /**
     151                 :  * Creates a Process-ID file.
     152                 :  */
     153                 : #ifndef O_NOFOLLOW
     154                 : # define O_NOFOLLOW 0
     155                 : #endif
     156                 : static int
     157                 : open_pidfile (const char *path)
     158               0 : {
     159                 :         int fd;
     160                 : 
     161               0 :         fd = open (path, O_WRONLY|O_CREAT|O_NOFOLLOW, 0644);
     162               0 :         if (fd != -1)
     163                 :         {
     164                 :                 struct stat s;
     165                 : 
     166               0 :                 errno = 0;
     167                 :                 /* We only check the lock. The actual locking occurs
     168                 :                  * after (possibly) calling daemon(). */
     169               0 :                 if ((fstat (fd, &s) == 0)
     170                 :                  && S_ISREG(s.st_mode)
     171                 :                  && (lockf (fd, F_TEST, 0) == 0))
     172               0 :                         return fd;
     173                 : 
     174               0 :                 if (errno == 0) /* !S_ISREG */
     175               0 :                         errno = EACCES;
     176                 : 
     177               0 :                 (void)close (fd);
     178                 :         }
     179               0 :         return -1;
     180                 : }
     181                 : 
     182                 : 
     183                 : static int
     184                 : write_pid (int fd)
     185               0 : {
     186                 :         char buf[20]; // enough for > 2^64
     187                 : 
     188                 :         /* Actually lock the file */
     189               0 :         if (lockf (fd, F_TLOCK, 0))
     190               0 :                 return -1;
     191                 : 
     192               0 :         (void)snprintf (buf, sizeof (buf), "%d", (int)getpid ());
     193               0 :         buf[sizeof (buf) - 1] = '\0';
     194               0 :         size_t len = strlen (buf);
     195                 : 
     196               0 :         if (ftruncate (fd, 0)
     197                 :          || (write (fd, buf, len) != (ssize_t)len)
     198                 :          || fdatasync (fd))
     199               0 :                 return -1;
     200               0 :         return 0;
     201                 : }
     202                 : 
     203                 : 
     204                 : static int
     205                 : close_pidfile (int fd)
     206               0 : {
     207               0 :         if (lockf (fd, F_ULOCK, 0))
     208               0 :                 return -1;
     209               0 :         if (close (fd))
     210               0 :                 return -1;
     211               0 :         return 0;
     212                 : }
     213                 : 
     214                 : 
     215                 : #ifdef MIREDO_DEFAULT_USERNAME
     216                 : static void
     217                 : setuid_notice (void)
     218               0 : {
     219               0 :         fputs (_(
     220                 : "That is usually an indication that you are trying to start\n"
     221                 : "the program as an user with insufficient system privileges.\n"
     222                 : "This program should normally be started by root.\n"), stderr);
     223               0 : }
     224                 : #endif
     225                 : 
     226                 : 
     227                 : static void *dummy_thread (void *data)
     228               0 : {
     229               0 :         pause ();
     230               0 :         return data;
     231                 : }
     232                 : 
     233                 : static int check_threading (void)
     234               0 : {
     235                 :         /* Hack to ensure that thread library is working:
     236                 :          * - this avoids infinite crashes/restart loops on broken OSes
     237                 :          * - this eases setting chroots (preloads libgcc_s on glibc)
     238                 :          */
     239                 :         pthread_t dummyth;
     240               0 :         errno = pthread_create (&dummyth, NULL, dummy_thread, NULL);
     241               0 :         if (errno)
     242               0 :                 return error_errno ("pthread_create");
     243                 : 
     244               0 :         pthread_cancel (dummyth);
     245               0 :         pthread_join (dummyth, NULL);
     246               0 :         return 0;
     247                 : }
     248                 : 
     249                 : 
     250                 : /**
     251                 :  * Initialize daemon context.
     252                 :  */
     253                 : static int
     254                 : init_security (const char *username)
     255               0 : {
     256                 :         int val;
     257                 : 
     258                 :         /* Sets sensible umask */
     259               0 :         (void)umask (022);
     260                 : 
     261                 :         /*
     262                 :          * We close all file handles, except 0, 1 and 2.
     263                 :          * This ensures that select() fd_set won't overflow.
     264                 :          *
     265                 :          * Those last 3 handles will be opened as /dev/null
     266                 :          * by later daemon().
     267                 :          */
     268               0 :         errno = 0;
     269               0 :         if (closefrom (3) && (errno != EBADF))
     270               0 :                 return -1;
     271                 : 
     272                 :         /*
     273                 :          * Make sure 0, 1 and 2 are open.
     274                 :          */
     275               0 :         val = dup (2);
     276               0 :         if (val < 3)
     277               0 :                 return -1;
     278               0 :         close (val);
     279                 : 
     280                 :         /* Initialize libc resolver: 
     281                 :          * - before clearenv() for LOCALDOMAIN
     282                 :          * - before chroot() for /etc/resolv.conf
     283                 :          * - after closefrom() just in case
     284                 :          */
     285               0 :         (void)res_init ();
     286                 : 
     287                 :         /* Clears environment */
     288               0 :         (void)clearenv ();
     289                 : 
     290               0 :         if (check_threading ())
     291               0 :                 return -1;
     292                 : 
     293                 : #ifdef MIREDO_DEFAULT_USERNAME
     294                 :         /* Determines unpriviledged user */
     295               0 :         errno = 0;
     296               0 :         struct passwd *pw = getpwnam (username);
     297               0 :         if (pw == NULL)
     298                 :         {
     299               0 :                 fprintf (stderr, _("User \"%s\": %s\n"),
     300                 :                                 username, errno ? strerror (errno)
     301                 :                                         : _("User not found"));
     302               0 :                 fprintf (stderr,
     303                 :                         _("Error: This program was asked to run in the\n"
     304                 :                         "security context of system user \"%s\", but it\n"
     305                 :                         "does not seem to exist on your system.\n"
     306                 :                         "\n"
     307                 :                         "Use command line option \"-u <username>\" to run\n"
     308                 :                         "this program in the security context of another\n"
     309                 :                         "user.\n"
     310                 :                         ), username);
     311               0 :                 return -1;
     312                 :         }
     313                 : 
     314               0 :         if (pw->pw_uid == 0)
     315                 :         {
     316               0 :                 fputs (_("Error: This program is not supposed to keep root\n"
     317                 :                         "privileges. That is potentially very dangerous\n"
     318                 :                         "(all the more as it has never been externally audited).\n"),
     319                 :                         stderr);
     320               0 :                 return -1;
     321                 :         }
     322               0 :         unpriv_uid = pw->pw_uid;
     323                 : 
     324                 :         /* Ensure we have root privilege before initialization */
     325               0 :         if (seteuid (0))
     326                 :         {
     327               0 :                 fprintf (stderr, _("SetUID to root: %s\n"), strerror (errno));
     328               0 :                 setuid_notice ();
     329               0 :                 return -1;
     330                 :         }
     331                 : 
     332                 :         /* Unpriviledged group */
     333               0 :         (void)setgid (pw->pw_gid);
     334               0 :         (void)initgroups (username, pw->pw_gid);
     335                 : #else
     336                 :         (void)username;
     337                 : #endif /* MIREDO_DEFAULT_USERNAME */
     338                 : 
     339                 : 
     340                 : #ifdef HAVE_LIBCAP
     341                 :         /* POSIX.1e capabilities support */
     342               0 :         cap_t s = cap_init ();
     343               0 :         if (s == NULL)
     344               0 :                 return error_errno ("cap_init"); // unlikely
     345                 : 
     346                 :         static cap_value_t caps[] =
     347                 :         {
     348                 :                 CAP_KILL, // required by the signal handler
     349                 :                 CAP_SETUID
     350                 :         };
     351               0 :         cap_set_flag (s, CAP_PERMITTED, 3, caps, CAP_SET);
     352               0 :         cap_set_flag (s, CAP_EFFECTIVE, 3, caps, CAP_SET);
     353                 : 
     354               0 :         if (miredo_chrootdir != NULL)
     355                 :         {
     356                 :                 static cap_value_t chroot_cap[] = { CAP_SYS_CHROOT };
     357               0 :                 cap_set_flag (s, CAP_PERMITTED, 1, chroot_cap, CAP_SET);
     358               0 :                 cap_set_flag (s, CAP_EFFECTIVE, 1, chroot_cap, CAP_SET);
     359                 :         }
     360                 : 
     361               0 :         cap_set_flag (s, CAP_PERMITTED, miredo_capc,
     362                 :                       (cap_value_t *)miredo_capv, CAP_SET);
     363               0 :         cap_set_flag (s, CAP_EFFECTIVE, miredo_capc,
     364                 :                       (cap_value_t *)miredo_capv, CAP_SET);
     365                 : 
     366               0 :         val = cap_set_proc (s);
     367               0 :         cap_free (s);
     368                 : 
     369               0 :         if (val)
     370                 :         {
     371               0 :                 error_errno ("cap_set_proc");
     372               0 :                 setuid_notice ();
     373               0 :                 return -1;
     374                 :         }
     375                 : #endif
     376                 : 
     377               0 :         return 0;
     378                 : }
     379                 : 
     380                 : 
     381                 : static void init_locale (void)
     382               0 : {
     383               0 :         (void)br_init (NULL);
     384               0 :         (void)setlocale (LC_ALL, "");
     385               0 :         char *path = br_find_locale_dir (LOCALEDIR);
     386                 :         (void)bindtextdomain (PACKAGE, path);
     387               0 :         free (path);
     388                 :         (void)textdomain (PACKAGE);
     389               0 : }
     390                 : 
     391                 : 
     392                 : int miredo_main (int argc, char *argv[])
     393               0 : {
     394               0 :         const char *username = NULL, *conffile = NULL, *servername = NULL,
     395               0 :                    *pidfile = NULL, *chrootdir = NULL;
     396                 :         struct
     397                 :         {
     398                 :                 unsigned foreground:1; /* Run in the foreground */
     399                 :         } flags;
     400                 : 
     401                 :         static const struct option opts[] =
     402                 :         {
     403                 :                 { "conf",       required_argument, NULL, 'c' },
     404                 :                 { "config",     required_argument, NULL, 'c' },
     405                 :                 { "foreground", no_argument,       NULL, 'f' },
     406                 :                 { "help",       no_argument,       NULL, 'h' },
     407                 :                 { "pidfile",    required_argument, NULL, 'p' },
     408                 :                 { "chroot",     required_argument, NULL, 't' },
     409                 :                 { "chrootdir",  required_argument, NULL, 't' },
     410                 :                 { "user",       required_argument, NULL, 'u' },
     411                 :                 { "username",   required_argument, NULL, 'u' },
     412                 :                 { "version",    no_argument,       NULL, 'V' },
     413                 :                 { NULL,         no_argument,       NULL, '\0'}
     414                 :         };
     415                 : 
     416               0 :         init_locale ();
     417                 : 
     418                 : #define ONETIME_SETTING( setting ) \
     419                 :         if (setting != NULL) \
     420                 :                 return error_dup (c, optarg, setting); \
     421                 :         else \
     422                 :                 setting = optarg;
     423                 : 
     424               0 :         memset (&flags, 0, sizeof (flags));
     425                 : 
     426                 :         int c;
     427               0 :         while ((c = getopt_long (argc, argv, "c:fhp:t:u:V", opts, NULL)) != -1)
     428               0 :                 switch (c)
     429                 :                 {
     430                 : 
     431                 :                         case 'c':
     432               0 :                                 ONETIME_SETTING (conffile);
     433               0 :                                 break;
     434                 : 
     435                 :                         case 'f':
     436               0 :                                 flags.foreground = 1;
     437               0 :                                 break;
     438                 : 
     439                 :                         case 'h':
     440               0 :                                 return usage (argv[0]);
     441                 : 
     442                 :                         case 'p':
     443               0 :                                 ONETIME_SETTING (pidfile);
     444               0 :                                 break;
     445                 : 
     446                 :                         case 'u':
     447               0 :                                 ONETIME_SETTING (username);
     448               0 :                                 break;
     449                 : 
     450                 :                         case 't':
     451               0 :                                 ONETIME_SETTING (chrootdir);
     452               0 :                                 break;
     453                 : 
     454                 :                         case 'V':
     455               0 :                                 return miredo_version ();
     456                 : 
     457                 :                         case '?':
     458                 :                         default:
     459               0 :                                 return quick_usage (argv[0]);
     460                 :                 }
     461                 : 
     462               0 :         if (optind < argc)
     463               0 :                 servername = argv[optind++];
     464                 : 
     465               0 :         if (optind < argc)
     466               0 :                 return error_extra (argv[optind]);
     467                 : 
     468                 : #ifdef MIREDO_DEFAULT_USERNAME
     469               0 :         if (username == NULL)
     470               0 :                 username = MIREDO_DEFAULT_USERNAME;
     471                 : #else
     472                 :         if (username != NULL)
     473                 :                 return error_extra (username);
     474                 : #endif
     475                 : 
     476                 :         size_t str_len;
     477                 :         char *path;
     478               0 :         if (conffile == NULL)
     479                 :         {
     480               0 :                 path = br_find_etc_dir (SYSCONFDIR);
     481               0 :                 str_len = strlen (path) + strlen (miredo_name)
     482                 :                                         + sizeof ("/miredo/.conf");
     483                 :         }
     484                 :         else
     485               0 :                 str_len = 0;
     486                 : 
     487               0 :         char conffile_buf[str_len];
     488               0 :         if (conffile == NULL)
     489                 :         {
     490               0 :                 snprintf (conffile_buf, str_len, "%s/miredo/%s.conf", path,
     491                 :                           miredo_name);
     492               0 :                 free (path);
     493               0 :                 conffile = conffile_buf;
     494                 :         }
     495                 : 
     496                 :         /* Check if config file and chroot dir are present */
     497               0 :         if ((servername == NULL) && access (conffile, R_OK))
     498                 :         {
     499               0 :                 fprintf (stderr, _("Reading configuration from %s: %s\n"),
     500                 :                                 conffile, strerror (errno));
     501               0 :                 return 1;
     502                 :         }
     503                 : 
     504               0 :         if (chrootdir != NULL)
     505                 :         {
     506                 :                 struct stat s;
     507               0 :                 errno = 0;
     508                 : 
     509               0 :                 if (stat (chrootdir, &s) || !S_ISDIR(s.st_mode)
     510                 :                  || access (chrootdir, X_OK))
     511                 :                 {
     512               0 :                         if (errno == 0)
     513               0 :                                 errno = ENOTDIR;
     514                 : 
     515               0 :                         error_errno (chrootdir);
     516               0 :                         return 1;
     517                 :                 }
     518                 :         }
     519               0 :         miredo_chrootdir = chrootdir;
     520                 : 
     521               0 :         if (pidfile == NULL)
     522               0 :                 str_len = sizeof (LOCALSTATEDIR"/run/" ".pid") + strlen (miredo_name);
     523                 :         else
     524               0 :                 str_len = 0;
     525                 : 
     526               0 :         char pidfile_buf[str_len];
     527               0 :         if (pidfile == NULL)
     528                 :         {
     529               0 :                 snprintf (pidfile_buf, str_len, LOCALSTATEDIR"/run/%s.pid",
     530                 :                           miredo_name);
     531               0 :                 pidfile = pidfile_buf;
     532                 :         }
     533                 : 
     534               0 :         if (init_security (username))
     535               0 :                 return 1;
     536                 : 
     537               0 :         if (miredo_diagnose ())
     538               0 :                 return 1;
     539                 : 
     540                 :         /* Opens pidfile */
     541               0 :         int fd = open_pidfile (pidfile);
     542               0 :         if (fd == -1)
     543                 :         {
     544               0 :                 fprintf (stderr, _("Cannot create PID file %s:\n %s\n"),
     545                 :                          pidfile, strerror (errno));
     546               0 :                 if (errno == EAGAIN)
     547               0 :                         fprintf (stderr, "%s\n",
     548                 :                                  _("Make sure another instance of the program is not "
     549                 :                                    "already running."));
     550               0 :                 return -1;
     551                 :         }
     552                 : 
     553                 :         /* Detaches */
     554               0 :         if (!flags.foreground && daemon (0, 0))
     555                 :         {
     556               0 :                 fprintf (stderr, _("Error (%s): %s\n"), "daemon", strerror (errno));
     557               0 :                 return -1;
     558                 :         }
     559                 : 
     560               0 :         if (write_pid (fd))
     561                 :         {
     562               0 :                 close (fd);
     563               0 :                 return -1;
     564                 :         }
     565                 : 
     566                 :         /*
     567                 :          * Run
     568                 :          */
     569               0 :         c = miredo (conffile, servername, fd);
     570                 : 
     571               0 :         close_pidfile (fd);
     572               0 :         (void)unlink (pidfile);
     573                 : 
     574               0 :         return c ? 1 : 0;
     575                 : }
     576                 : 

Generated by: LTP GCOV extension version 1.5