src/openvpn/openvpn.c
6fbf66fa
 /*
  *  OpenVPN -- An application to securely tunnel IP networks
  *             over a single TCP/UDP port, with support for SSL/TLS-based
  *             session authentication and key exchange,
  *             packet encryption, packet authentication, and
  *             packet compression.
  *
49979459
  *  Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
6fbf66fa
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
  *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
caa54ac3
  *  You should have received a copy of the GNU General Public License along
  *  with this program; if not, write to the Free Software Foundation, Inc.,
  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
6fbf66fa
  */
 
c110b289
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #elif defined(_MSC_VER)
 #include "config-msvc.h"
 #endif
 
6fbf66fa
 #include "syshead.h"
 
 #include "init.h"
 #include "forward.h"
 #include "multi.h"
5a2e9a25
 #include "win32.h"
c5b12817
 #include "platform.h"
6fbf66fa
 
 #include "memdbg.h"
 
 #include "forward-inline.h"
 
81d882d5
 #define P2P_CHECK_SIG() EVENT_LOOP_CHECK_SIGNAL(c, process_signal_p2p, c);
6fbf66fa
 
 static bool
81d882d5
 process_signal_p2p(struct context *c)
6fbf66fa
 {
81d882d5
     remap_signal(c);
     return process_signal(c);
6fbf66fa
 }
 
c5b12817
 /* Write our PID to a file */
 static void
 write_pid(const char *filename)
 {
     if (filename)
     {
         unsigned int pid = 0;
         FILE *fp = platform_fopen(filename, "w");
         if (!fp)
         {
             msg(M_ERR, "Open error on pid file %s", filename);
         }
 
         pid = platform_getpid();
         fprintf(fp, "%u\n", pid);
         if (fclose(fp))
         {
             msg(M_ERR, "Close error on pid file %s", filename);
         }
     }
 }
98619012
 
 
 /**************************************************************************/
 /**
  * Main event loop for OpenVPN in client mode, where only one VPN tunnel
  * is active.
  * @ingroup eventloop
  *
  * @param c - The context structure of the single active VPN tunnel.
  */
6fbf66fa
 static void
81d882d5
 tunnel_point_to_point(struct context *c)
6fbf66fa
 {
81d882d5
     context_clear_2(c);
6fbf66fa
 
81d882d5
     /* set point-to-point mode */
     c->mode = CM_P2P;
6fbf66fa
 
81d882d5
     /* initialize tunnel instance */
     init_instance_handle_signals(c, c->es, CC_HARD_USR1_TO_HUP);
     if (IS_SIG(c))
     {
         return;
     }
6fbf66fa
 
81d882d5
     /* main event loop */
     while (true)
6fbf66fa
     {
81d882d5
         perf_push(PERF_EVENT_LOOP);
6fbf66fa
 
81d882d5
         /* process timers, TLS, etc. */
         pre_select(c);
         P2P_CHECK_SIG();
6fbf66fa
 
81d882d5
         /* set up and do the I/O wait */
         io_wait(c, p2p_iow_flags(c));
         P2P_CHECK_SIG();
6fbf66fa
 
81d882d5
         /* timeout? */
         if (c->c2.event_set_status == ES_TIMEOUT)
         {
             perf_pop();
             continue;
         }
6fbf66fa
 
81d882d5
         /* process the I/O which triggered select */
         process_io(c);
         P2P_CHECK_SIG();
6fbf66fa
 
81d882d5
         perf_pop();
6fbf66fa
     }
 
81d882d5
     uninit_management_callback();
6fbf66fa
 
81d882d5
     /* tear down tunnel instance (unless --persist-tun) */
     close_instance(c);
6fbf66fa
 }
 
 #undef PROCESS_SIGNAL_P2P
 
98619012
 
 /**************************************************************************/
 /**
  * OpenVPN's main init-run-cleanup loop.
  * @ingroup eventloop
  *
  * This function contains the two outer OpenVPN loops.  Its structure is
  * as follows:
  *  - Once-per-process initialization.
  *  - Outer loop, run at startup and then once per \c SIGHUP:
  *    - Level 1 initialization
  *    - Inner loop, run at startup and then once per \c SIGUSR1:
  *      - Call event loop function depending on client or server mode:
  *        - \c tunnel_point_to_point()
  *        - \c tunnel_server()
  *    - Level 1 cleanup
  *  - Once-per-process cleanup.
  *
  * @param argc - Commandline argument count.
  * @param argv - Commandline argument values.
  */
74370aa8
 static
6fbf66fa
 int
81d882d5
 openvpn_main(int argc, char *argv[])
6fbf66fa
 {
81d882d5
     struct context c;
6fbf66fa
 
 #if PEDANTIC
81d882d5
     fprintf(stderr, "Sorry, I was built with --enable-pedantic and I am incapable of doing any real work!\n");
     return 1;
6fbf66fa
 #endif
 
445b192a
 #ifdef _WIN32
81d882d5
     SetConsoleOutputCP(CP_UTF8);
6ba68180
 #endif
 
81d882d5
     CLEAR(c);
6fbf66fa
 
81d882d5
     /* signify first time for components which can
      * only be initialized once per program instantiation. */
     c.first_time = true;
6fbf66fa
 
81d882d5
     /* initialize program-wide statics */
     if (init_static())
6fbf66fa
     {
81d882d5
         /*
          * This loop is initially executed on startup and then
          * once per SIGHUP.
          */
         do
         {
             /* enter pre-initialization mode with regard to signal handling */
             pre_init_signal_catch();
 
             /* zero context struct but leave first_time member alone */
             context_clear_all_except_first_time(&c);
 
             /* static signal info object */
             CLEAR(siginfo_static);
             c.sig = &siginfo_static;
 
             /* initialize garbage collector scoped to context object */
             gc_init(&c.gc);
 
             /* initialize environmental variable store */
             c.es = env_set_create(NULL);
445b192a
 #ifdef _WIN32
81d882d5
             set_win_sys_path_via_env(c.es);
5a2e9a25
 #endif
6fbf66fa
 
 #ifdef ENABLE_MANAGEMENT
81d882d5
             /* initialize management subsystem */
             init_management(&c);
6fbf66fa
 #endif
 
81d882d5
             /* initialize options to default state */
             init_options(&c.options, true);
6fbf66fa
 
81d882d5
             /* parse command line options, and read configuration file */
             parse_argv(&c.options, argc, argv, M_USAGE, OPT_P_DEFAULT, NULL, c.es);
6fbf66fa
 
3c7f2f55
 #ifdef ENABLE_PLUGIN
81d882d5
             /* plugins may contribute options configuration */
             init_verb_mute(&c, IVM_LEVEL_1);
             init_plugins(&c);
             open_plugins(&c, true, OPENVPN_PLUGIN_INIT_PRE_CONFIG_PARSE);
3c7f2f55
 #endif
 
81d882d5
             /* init verbosity and mute levels */
             init_verb_mute(&c, IVM_LEVEL_1);
6fbf66fa
 
81d882d5
             /* set dev options */
             init_options_dev(&c.options);
6fbf66fa
 
81d882d5
             /* openssl print info? */
             if (print_openssl_info(&c.options))
             {
                 break;
             }
6fbf66fa
 
81d882d5
             /* --genkey mode? */
             if (do_genkey(&c.options))
             {
                 break;
             }
6fbf66fa
 
81d882d5
             /* tun/tap persist command? */
             if (do_persist_tuntap(&c.options))
             {
                 break;
             }
6fbf66fa
 
81d882d5
             /* sanity check on options */
             options_postprocess(&c.options);
6fbf66fa
 
81d882d5
             /* show all option settings */
             show_settings(&c.options);
6fbf66fa
 
81d882d5
             /* print version number */
             msg(M_INFO, "%s", title_string);
445b192a
 #ifdef _WIN32
81d882d5
             show_windows_version(M_INFO);
cdc65ea0
 #endif
81d882d5
             show_library_versions(M_INFO);
6fbf66fa
 
81d882d5
             /* misc stuff */
             pre_setup(&c.options);
6fbf66fa
 
81d882d5
             /* test crypto? */
             if (do_test_crypto(&c.options))
             {
                 break;
             }
315f6fbc
 
81d882d5
             /* Query passwords before becoming a daemon if we don't use the
              * management interface to get them. */
d4fbe287
 #ifdef ENABLE_MANAGEMENT
81d882d5
             if (!(c.options.management_flags & MF_QUERY_PASSWORDS))
d4fbe287
 #endif
81d882d5
             init_query_passwords(&c);
315f6fbc
 
81d882d5
             /* become a daemon if --daemon */
             if (c.first_time)
             {
                 c.did_we_daemonize = possibly_become_daemon(&c.options);
                 write_pid(c.options.writepid);
             }
da9b2927
 
6fbf66fa
 #ifdef ENABLE_MANAGEMENT
81d882d5
             /* open management subsystem */
             if (!open_management(&c))
             {
                 break;
             }
             /* query for passwords through management interface, if needed */
             if (c.options.management_flags & MF_QUERY_PASSWORDS)
             {
                 init_query_passwords(&c);
             }
6fbf66fa
 #endif
6add6b2f
 
81d882d5
             /* set certain options as environmental variables */
             setenv_settings(c.es, &c.options);
6fbf66fa
 
81d882d5
             /* finish context init */
             context_init_1(&c);
 
             do
             {
                 /* run tunnel depending on mode */
                 switch (c.options.mode)
                 {
                     case MODE_POINT_TO_POINT:
                         tunnel_point_to_point(&c);
                         break;
6fbf66fa
 
 #if P2MP_SERVER
81d882d5
                     case MODE_SERVER:
                         tunnel_server(&c);
                         break;
 
6fbf66fa
 #endif
81d882d5
                     default:
                         ASSERT(0);
                 }
 
                 /* indicates first iteration -- has program-wide scope */
                 c.first_time = false;
 
                 /* any signals received? */
                 if (IS_SIG(&c))
                 {
                     print_signal(c.sig, NULL, M_INFO);
                 }
 
                 /* pass restart status to management subsystem */
                 signal_restart_status(c.sig);
             }
             while (c.sig->signal_received == SIGUSR1);
 
7170bef5
             env_set_destroy(c.es);
81d882d5
             uninit_options(&c.options);
             gc_reset(&c.gc);
         }
         while (c.sig->signal_received == SIGHUP);
6fbf66fa
     }
 
81d882d5
     context_gc_free(&c);
6fbf66fa
 
 #ifdef ENABLE_MANAGEMENT
81d882d5
     /* close management interface */
     close_management();
6fbf66fa
 #endif
 
81d882d5
     /* uninitialize program-wide statics */
     uninit_static();
6fbf66fa
 
81d882d5
     openvpn_exit(OPENVPN_EXIT_STATUS_GOOD); /* exit point */
     return 0;                               /* NOTREACHED */
6fbf66fa
 }
74370aa8
 
445b192a
 #ifdef _WIN32
74370aa8
 int
4cd4899e
 wmain(int argc, wchar_t *wargv[])
 {
81d882d5
     char **argv;
     int ret;
     int i;
74370aa8
 
81d882d5
     if ((argv = calloc(argc+1, sizeof(char *))) == NULL)
     {
         return 1;
     }
74370aa8
 
81d882d5
     for (i = 0; i < argc; i++)
74370aa8
     {
81d882d5
         int n = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, NULL, 0, NULL, NULL);
         argv[i] = malloc(n);
         WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], n, NULL, NULL);
74370aa8
     }
 
81d882d5
     ret = openvpn_main(argc, argv);
74370aa8
 
81d882d5
     for (i = 0; i < argc; i++)
74370aa8
     {
81d882d5
         free(argv[i]);
74370aa8
     }
81d882d5
     free(argv);
74370aa8
 
81d882d5
     return ret;
74370aa8
 }
81d882d5
 #else  /* ifdef _WIN32 */
74370aa8
 int
4cd4899e
 main(int argc, char *argv[])
 {
81d882d5
     return openvpn_main(argc, argv);
74370aa8
 }
81d882d5
 #endif /* ifdef _WIN32 */