From fd9e4ae6dbf9a5efe7e0c3a3bb578bbd82a9e685 Mon Sep 17 00:00:00 2001 From: Heiko Hund Date: Thu, 18 Dec 2008 11:08:35 +0000 Subject: [PATCH] import of openvpn-gui-1.0.3.zip git-svn-id: https://openvpn-gui.svn.sourceforge.net/svnroot/openvpn-gui/trunk@2 43a1345a-9c20-4331-951f-9845fc178312 --- COPYING | 14 + COPYRIGHT.GPL | 340 +++++++++++++ Makefile | 44 ++ OpenVPN GUI ReadMe.txt | 231 +++++++++ changes.txt | 635 +++++++++++++++++++++++++ chartable.h | 280 +++++++++++ connected.ico | Bin 0 -> 1406 bytes connecting.ico | Bin 0 -> 1406 bytes disconnected.ico | Bin 0 -> 1406 bytes ieproxy.c | 137 ++++++ ieproxy.h | 24 + main.c | 500 +++++++++++++++++++ main.h | 108 +++++ openvpn-gui-en.rc | 351 ++++++++++++++ openvpn-gui-res.h | 243 ++++++++++ openvpn-gui.ico | Bin 0 -> 3262 bytes openvpn.c | 974 ++++++++++++++++++++++++++++++++++++++ openvpn.h | 39 ++ openvpn_config.c | 252 ++++++++++ openvpn_config.h | 22 + openvpn_monitor_process.c | 649 +++++++++++++++++++++++++ openvpn_monitor_process.h | 22 + options.c | 352 ++++++++++++++ options.h | 137 ++++++ passphrase.c | 902 +++++++++++++++++++++++++++++++++++ passphrase.h | 43 ++ proxy.c | 569 ++++++++++++++++++++++ proxy.h | 37 ++ reconnecting.ico | Bin 0 -> 1406 bytes registry.c | 272 +++++++++++ registry.h | 27 ++ scripts.c | 291 ++++++++++++ scripts.h | 24 + service.c | 304 ++++++++++++ service.h | 25 + shellapi.h | 326 +++++++++++++ tray.c | 591 +++++++++++++++++++++++ tray.h | 61 +++ viewlog.c | 121 +++++ viewlog.h | 23 + 40 files changed, 8970 insertions(+) create mode 100644 COPYING create mode 100644 COPYRIGHT.GPL create mode 100644 Makefile create mode 100644 OpenVPN GUI ReadMe.txt create mode 100644 changes.txt create mode 100644 chartable.h create mode 100644 connected.ico create mode 100644 connecting.ico create mode 100644 disconnected.ico create mode 100644 ieproxy.c create mode 100644 ieproxy.h create mode 100644 main.c create mode 100644 main.h create mode 100644 openvpn-gui-en.rc create mode 100644 openvpn-gui-res.h create mode 100644 openvpn-gui.ico create mode 100644 openvpn.c create mode 100644 openvpn.h create mode 100644 openvpn_config.c create mode 100644 openvpn_config.h create mode 100644 openvpn_monitor_process.c create mode 100644 openvpn_monitor_process.h create mode 100644 options.c create mode 100644 options.h create mode 100644 passphrase.c create mode 100644 passphrase.h create mode 100644 proxy.c create mode 100644 proxy.h create mode 100644 reconnecting.ico create mode 100644 registry.c create mode 100644 registry.h create mode 100644 scripts.c create mode 100644 scripts.h create mode 100644 service.c create mode 100644 service.h create mode 100644 shellapi.h create mode 100644 tray.c create mode 100644 tray.h create mode 100644 viewlog.c create mode 100644 viewlog.h diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..850335f --- /dev/null +++ b/COPYING @@ -0,0 +1,14 @@ +OpenVPN GUI -- A Windows GUI for OpenVPN + +Copyright (C) 2004-2005 by Mathias Sundman + + + OpenVPN GUI is distributed under GPL license. + (see COPYRIGHT.GPL) + + Parts of the source code for OpenVPN GUI is taken from + openvpnserv.c included with the OpenVPN [1] distribution. + + [1] OpenVPN is copyrighted by OpenVPN Solutions LLC , + and distributed under GPL license. + diff --git a/COPYRIGHT.GPL b/COPYRIGHT.GPL new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/COPYRIGHT.GPL @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a330a0a --- /dev/null +++ b/Makefile @@ -0,0 +1,44 @@ +# This makefile builds OpenVPN-GUI using the mingw environment. + +OPENSSL = /c/OpenSSL + +RES_LANG = en +GUI_VERSION = 1.0.3 + +EXE = openvpn-gui-$(GUI_VERSION)-$(RES_LANG).exe + +HEADERS = main.h openvpn.h openvpn_monitor_process.h tray.h viewlog.h \ + service.h options.h passphrase.h openvpn-gui-res.h proxy.h \ + ieproxy.h registry.h openvpn_config.h chartable.h scripts.h + +OBJS = main.o tray.o openvpn.o openvpn_monitor_process.o viewlog.o \ + service.o options.o passphrase.o proxy.o ieproxy.o registry.o \ + openvpn_config.o scripts.o openvpn-gui-$(RES_LANG).res + +INCLUDE_DIRS = -I. -I${OPENSSL}/include +LIB_DIRS = -L${OPENSSL}/lib/MinGW + +WARNS = -W -Wall -Wfloat-equal -Wundef -Wshadow -Wpointer-arith -Wbad-function-cast \ + -Wcast-align -Wwrite-strings -Wconversion -Wsign-compare \ + -Waggregate-return -Wmissing-noreturn -Wmissing-format-attribute \ + -Wredundant-decls -Winline -Wdisabled-optimization \ + -Wno-unused-function -Wno-unused-variable + +CC = gcc +CFLAGS = -g -O2 ${WARNS} -mno-cygwin +LDFLAGS = -mwindows -s +#LDFLAGS = -mwindows +WINDRES = windres.exe + +all : ${OBJS} + ${CC} -o ${EXE} ${OBJS} ${LIB_DIRS} -leay32 -lWinInet ${LDFLAGS} +# ${CC} -o ${EXE} ${OBJS} ${LIB_DIRS} -lWinInet ${LDFLAGS} + +clean : + rm -f *.o *.exe *.res + +%.o : %.c ${HEADERS} + ${CC} ${CFLAGS} ${INCLUDE_DIRS} -c $< -o $@ + +openvpn-gui-$(RES_LANG).res : openvpn-gui-$(RES_LANG).rc openvpn-gui-res.h + $(WINDRES) -i openvpn-gui-$(RES_LANG).rc -I rc -o openvpn-gui-$(RES_LANG).res -O coff diff --git a/OpenVPN GUI ReadMe.txt b/OpenVPN GUI ReadMe.txt new file mode 100644 index 0000000..f650357 --- /dev/null +++ b/OpenVPN GUI ReadMe.txt @@ -0,0 +1,231 @@ +Installation Instructions for OpenVPN GUI for Windows +----------------------------------------------------- + +You can either get my installation package for OpenVPN 2.0.X where I've +bundled the gui in the installation package, or you can use the original +installation package from OpenVPN, and then manually install OpenVPN GUI. + + +Installation using the bundled OpenVPN package with OpenVPN GUI included +------------------------------------------------------------------------ + +* Download openvpn-2.0.X-gui-1.0.X-install.exe from + http://openvpn.se + +* If you have a previous version of OpenVPN GUI installed, shut it down. + Make sure it's closed by ALL logged on users. + +* Run the install program. During the installation you can choose if the GUI + should be started automatically at system startup. The default is yes. + +* Create a xxxx.ovpn config-file with your favorite texteditor and save it in: + C:\Program files\OpenVPN\config\. You should NOT use the "log" or "log-append" + options as OpenVPN GUI redirect the normal output to a log file itself. + There is a sample config files in the "sample-config" folder. Please + refer to the OpenVPN project homepage for more information regarding + creating the configuration file. http://openvpn.net/ + + +Manual installation of OpenVPN GUI +---------------------------------- + +* Download and install OpenVPN from http://openvpn.net/ + +* Download openvpn-gui-1.0.X.exe and save it in OpenVPN's bin folder. + Default is "C:\Program Files\OpenVPN\bin\". You must put it in this folder + because OpenVPN GUI depends on the OpenSSL DLLs installed in this folder by + OpenVPN. + +* Create a xxxx.ovpn config-file with your favorite texteditor and save it in: + C:\Program files\OpenVPN\config\. You should NOT use the "log" or "log-append" + options as OpenVPN GUI redirect the normal output to a log file itself. + There is a sample config files in the "sample-config" folder. Please + refer to the OpenVPN project homepage for more information regarding + creating the configuration file. http://openvpn.net/ + +* Put a short-cut to openvpn-gui-1.0-X.exe in your + "Start->All Program->StartUp" folder if you want the gui started automatically + when you logon to Windows. + +* Start the GUI by double-clicking the openvpn-gui-1.0.X.exe file. + +*** You need to be Administrator the first time you run OpenVPN GUI for it to + create its registry keys. After that you don't have to be administrator + just to run the GUI, however OpenVPN requires the user to be + administrator to run! *** + + +Using OpenVPN GUI +----------------- + +When OpenVPN GUI is started your config folder (C:\Program Files\OpenVPN\config) +will be scanned for .ovpn files, and an icon will be displayed in the taskbar's +status area. + +If you do not have any openvpn connection running, the config dir will be +re-scanned for new config files every time you open the OpenVPN GUI menu by +right-clicking the icon. + +When you choose to connect to a site OpenVPN GUI will launch openvpn with +the specified config file. If you use a passphrase protected key you will be +prompted for the passphrase. + +If you want OpenVPN GUI to start a connection automatically when it's started, +you can use the --connect cmd-line option. You have to include the extention +for the config file. Example: + +openvpn-gui --connect office.ovpn + + +Run OpenVPN GUI as a Non-Admin user +----------------------------------- + +OpenVPN currently does not work as a normal (non-admin) user. OpenVPN GUI +2.0 will solve this by using an enhanced version of the OpenVPN service +to start and stop openvpn processes. + +In the mean time, it is possible to use OpenVPN GUI to control the current +OpenVPN Service to start and stop a connection. + +To use OpenVPN GUI to control the OpenVPN service, set the registry value +"service_only" to '1'. See the section about registry values below. + +Limitations with this way: + + There is no way for OpenVPN GUI ta hand over a password to the service + wrapper, so you can't use passphrase protected private keys or + username/password authentication. + + If you have multiple openvpn configurations, all will be started and + stopped at the same time. + + OpenVPN GUI is not able to retrieve any status info about the connections + from OpenVPN, so it will report connected as soon as the service is + started regarless of if OpenVPN has really succeded to connect or not. + + You cannot see the OpenVPN log in real-time. + + +Run Connect/Disconnect/Preconnect Scripts +----------------------------------------- + +There are three diffrent scripts that OpenVPN GUI can execute to help +with diffrent tasks like mapping network drives. + +Preconnect If a file named "xxx_pre.bat" exist in the config folder + where xxx is the same as your OpenVPN config file name, + this will be executed BEFORE the OpenVPN tunnel is established. + +Connect If a file named "xxx_up.bat" exist in the config folder + where xxx is the same as your OpenVPN config file name, + this will be executed AFTER the OpenVPN tunnel is established. + +Disconnect If a file named "xxx_down.bat" exist in the config folder + where xxx is the same as your OpenVPN config file name, + this will be executed BEFORE the OpenVPN tunnel is closed. + + +Registry Values affecting the OpenVPN GUI operation +--------------------------------------------------- + +All OpenVPN GUI reg-values are located below the following key: +HKEY_LOCAL_MACHINE\SOFTWARE\OpenVPN-GUI\ + +The follow keys are used to control the OpenVPN GUI + +config_dir + configuration file directory, defaults to "C:\Program Files\OpenVPN\config" + +config_ext + file extension on configuration files, defaults to "ovpn" + +connectscript_timeout + Time in seconds to wait for the connect script to finish. If set to 0 + the exitcode of the script is not checked. + +disconnectscript_timeout + Time in seconds to wait for the disconnect script to finish. Must be a + value between 1-99. + +preconnectscript_timeout + Time in seconds to wait for the preconnect script to finish. Must be a + value between 1-99. + +exe_path + path to openvpn.exe, defaults to "C:\Program Files\OpenVPN\bin\openvpn.exe" + +log_dir + log file directory, defaults to "C:\Program Files\OpenVPN\log" + +log_append + if set to "0", the log file will be truncated every time you start a + connection. If set to "1", the log will be appended to the log file. + +priority + the windows priority class for each instantiated OpenVPN process, + can be one of: + + * "IDLE_PRIORITY_CLASS" + * "BELOW_NORMAL_PRIORITY_CLASS" + * "NORMAL_PRIORITY_CLASS" (default) + * "ABOVE_NORMAL_PRIORITY_CLASS" + * "HIGH_PRIORITY_CLASS" + +allow_edit + If set to "1", the Edit config menu will be showed. + +allow_password + If set to "1", the Change Password menu will be showed. + +allow_proxy + If set to "1", the Proxy Settings menu will be showed. + +allow_service + If set to "1", the Service control menu will be showed. + +silent_connection + If set to "1", the status window with the OpenVPN log output will + not be showed while connecting. + +service_only + If set to "1", OpenVPN GUI's normal "Connect" and "Disconnect" + actions are changed so they start/stop the OpenVPN service instead + of launching openvpn.exe directly. + +show_balloon + If set to "0" - Never show any connected balloon. + "1" - Show balloon after initial connection is established. + "2" - Show balloon even after re-connects. +log_viewer + The program used to view your log files, defaults to + "C:\windows\notepad.exe" + +editor + The program used to edit your config files, defaults to + "C:\windows\notepad.exe" + +passphrase_attempts + Number of attempts to enter the passphrase to allow. + +All these registry options is also available as cmd-line options. +Use "openvpn-gui --help" for more info about cmd-line options. + + +If you have any problem getting OpenVPN GUI to work you can reach me via +email at mathias@nilings.se. + + +Building OpenVPN GUI from source +-------------------------------- + +* Download and install MinGW and MSYS from http://www.mingw.org/ + I'm using MinGW-3.2.0-rc-3 and MSYS-1.0.10. + +* Download and install the binary distribution of OpenSSL from + http://www.slproweb.com/products/Win32OpenSSL.html + +* Download and extract the OpenVPN GUI source archive. + +* Start a bash shell by running msys.bat. + +* Run "make" from the OpenVPN GUI source directory. diff --git a/changes.txt b/changes.txt new file mode 100644 index 0000000..761f08b --- /dev/null +++ b/changes.txt @@ -0,0 +1,635 @@ +[1.0.3 2005-08-18] + +Bug Fixes: + There was a bug in the code that expands variables in + registry values. If the expanded string was longer than + the original string it got incorrectly truncated. + + +[1.0.2 2005-07-27] + + Pass paths read in OpenVPN GUI's registry values through + ExpandEnvironmentStrings(). This allows the use of Windows + variables like %HOMEPATH% or %PROGRAMFILES%. This allows + multiple users on the same system to have their own set + of config files and keys in their home dir. + + +[1.0.1 2005-06-10] + +Bug Fixes: + The Change Password feature did not work correctly when TABs + were used in the config file between the key/pkcs12 keyword and + the accual path to the key file. + + +[1.0 2005-04-21] + +No changes + + +[1.0-rc5 2005-03-29] + +Bug Fixes: + [Pre/Dis]Connect scripts were not executed when starting or stopping + the OpenVPN Service, or using "Service Only" mode. + + +[1.0-rc4 2005-02-17] + + Increased the width of buttons and space between text labels and edit + controls on dialogs to ease localization of OpenVPN GUI. + +Bug Fixes: + Some fixed text strings was introduced in the code in 1.0-rc3. These + are moved to the resource file now to allow localization. + + If starting the OpenVPN service failed, OpenVPN GUI would get + stuck with a yellow icon. + + +[1.0-rc3 2005-02-14] + +New Features: + New registry value (show_balloon) to control whether to show the + "Connected Balloon" or not. show_ballon can have the following values + + 0=Never show any balloon. + 1=Show balloon when the connection establishes (default). + 2=Show balloon every time OpenVPN has reconnected (old behavior). + + Show "Connected since: XXX" and "Assigned IP: X.X.X.X" in the tray + icon tip msg. + + If a batch file named xxx_pre.bat exists in the config folder, where + xxx is the same name as an OpenVPN config file, this will be executed + before OpenVPN is launced. + + If a batch file named xxx_down.bat exists in the config folder, where + xxx is the same name as an OpenVPN config file, this will be executed + on disconnect, but before the OpenVPN tunnel is closed. + + Registry value "show_script_window" controls whether _up, _down and + _pre scripts should execute in the background or in a visible cmd-line + window. + + Registry value "[pre/dis]connectscript_timeout" controls how long to + wait for each script to finish. + + Updated information on the about dialog. + +Bug Fixes: + Removed unused code that tried to determine the path to "Program + Files". This code caused an error in some rare occasions. + + +[1.0-rc2 2005-01-12] + +New Features: + Support for one level of subdirectories below the config directory. + This means that if you have multiple connections, you can now put + them in a seperate subdirectory together with their keys and certs. + + "Service Only" mode. This is a mode that makes OpenVPN GUI more + friendly to use for non-admin users to control the OpenVPN Service. + Enable this mode by setting the registry value "service_only" to "1". + + In this mode the following happends: + + * The normal "Connect", "Disconnect" and "Show Status" is removed. + + * The Service menu items "Start", "Stop" and "Restart" is replaced + by "Connect", "Disconnect" and "Reconnect" directly on the main + menu. These now control the OpenVPN Service instead. + + * Dubbleclicking the icon starts the OpenVPN Service. + + * Dubbleclicking the icon when the service is running brings up a + dialog asking if you want to disconnect. + + * The Proxy Settings menu item is removed as it can't control the service anyway. + + The "OpenVPN Service started" dialog msg is replaced with a + balloon msg. + + Ask the user if he really wants to exit OpenVPN GUI if the OpenVPN + Service is running. + +Bug Fixes: + Full rights were required to control the OpenVPN Service. Now only + Start/Stop permissions are required, which allows a normal user to + control the OpenVPN Service if these rights are granted to the user. + (Can be done with subinacl.exe from the resource kit) + + When passwords were retrieved from a user, OpenVPN GUI received them + in the default windows codepage (ISO 8859-1 on english XP), and this + was passed on untouched to OpenVPN. When OpenVPN is run from command- + line on the other hand, the old DOS CP850 codepage is used. This + caused passwords containing non-ASCII (7-bit) chars that worked from + cmd-line not to work from OpenVPN GUI. This is now solved by + retrieving passwords in unicode and translate them to CP850 before + supplying them to OpenVPN. + + Re-scan the config dir for new files when dubble-clicking the tray + icon. + + +[1.0-rc1 2005-01-06] + +New Features: + Show a warning message if "log" or "log-append" is found in the config + file. + +Bug Fixed: + Added a bunch of compiler warnings which revealed a lot of minor + programming errors. Mostly cast conversion errors between signed and + unsigned intergers. All fixed now. + + Set focus on the log window when the status window is re-opened to make + sure the log is scrolled automatically. + + Set focus on the log window when clicking disconnect to allow the log + to continue scrolling automatically until OpenVPN is terminated. + + +[1.0-beta26 2004-12-04] + +New Features: + Show "Connecting to: xxx" msg in tray icon tip message in addition to + the previously displayed "Connected to:" msg. + +Bug Fixes: + Don't ask if you are sure you want to change your password to an EMPTY + password if you're not allowed to use passwords shorter than 8 chars. + + Clear password buffers after use to avoid having passwords in memory. + + +[1.0-beta25 2004-12-01] + + Changed button labels on the status dialog from DisConnect and ReConnect + to Disconnect and Reconnect. + + Don't show "Assigned IP:" at all in the connected balloon if no IP + address is known, as when a real remote DHCP server is used. + + Stripped out the last hardcoded strings to the resource file. + + Raised maximum number of configs from 20 to 50. + +Bug Fixes: + If OpenVPN printed a line longer that 1024 chars, OpenVPN GUI would crash. + This could happend when using "verb 5" or higher as OpenVPN then prints + an "r" or "w" for every packet without any line breaks. A new line will + now be inserted when 1024 chars is reached. + + Ask if you want to close active connections when WM_CLOSE is received. + + Handle WM_QUERYENDSESSION and WM_ENDSESSION correctly by closing any + active connections and then terminate. + + +[1.0-beta24 2004-11-15] + +Bug Fixes: + Some openssl #includes were not #ifdef:ed when building a nochangepsw + version causing the build to fail if the openssl headers were not + available. + + When using OpenVPN 1.5/1.6 and entering a false private key passphrase, + OpenVPN GUI would falsely think that the user attempted to start another + connection. + + +[1.0-beta23 2004-11-08] + +Bug Fixes: + Passphrase protected keys stored in MS Certificate Store did not work + due to the way the openvpn console window was hidden. + + +[1.0-beta22 2004-11-05] + +Bug Fixes: + OpenVPN GUI did not pass a CR/LF correctly after supplying OpenVPN + with the private key passphrase! OpenVPN 2.0-beta12 and higher which + uses a new prompt worked, but not earlier versions of OpenVPN. + + If the Shell (explorer.exe) is restarted, OpenVPN GUI did not + re-register the tray icon. + + +[1.0-beta21 2004-10-29] + +New Features: + Added support for username/password based authentication. + + Support for Localization. Language have to chosen at build time. + Available are english, german, czech and swedish. + +Bug Fixes: + Fixed crash after displaying that too many connections exist. + + Removed duplicate length-check on setting new password. + + Fixed error dialog which had the error message shown in window caption. + + Status windows did not change to yellow icon while ReConnecting. + + DisConnect and ReConnect button was not disabled after a termination. + This bug was introduced with beta20. + + The Change Password feature did not parse the key/pkcs12 line in the + config file correctly if there was TABs after the filename. + + The Change Password feature did not work if a relative path with + subdirectories was used. + + +[1.0-beta20 2004-10-18] + +New Features: + Accept the new passphrase prompt introduced with OpenVPN 2.0-beta12. + + When the machine is about to enter suspend mode the connection is + closed. When the machine is powered up again, the connection is + re-established. + + Registry option "disconnect_on_suspend". Set to zero to disable the + above feature. + + ReConnect button on the status dialog. + + Registry option "allow_proxy" to hide the Proxy Settings menu item. + + Registry option "silent_connection" that suppresses the status + dialog from being showed while connecting. + + Command-line option to set the time to wait for the connect script + to finish. + + Icon color now reflects the status of the OpenVPN Service. + +Bug Fixes: + Included shellapi.h with the sourcecode, as the one distributed with + the current stable version of MinGW miss some definitions. + + When closing OpenVPN GUI it waits for all connections to close before + exiting (Max 5 sec). + + Made the password dialog always be on top of other windows. + + Fixed a bug that occured if opening the log file for writing failed. + (which happends if you try to run OpenVPN GUI without admin rights) + + The menuitems on the OpenVPN Service menu was incorrectly enabled/ + disabled. This bug was introduced with beta19 as a result of the + dynamic rescanning for configs on every menu opening. + + Starting OpenVPN GUI with OpenVPN 1.5/1.6 installed and OpenVPN + Service running failed with previous versions. (CreateEvent() error) + + The installation package did not remove the OpenVPN-GUI registry key + on uninstall. + + Removed dependency on libeay32.dll for the no change password build. + + +[1.0-beta19 2004-09-22] + +New Features: + The menu is restructured. Previous versions had all "actions" on the + main menu, and a submenu with all configs for every action. This version + lists all configs on the main menu, and have a submenu with actions. + + If only one config exist, the actions are placed on the main menu. + + If no connection is running, the config dir is re-scanned for configs + every time the menu is opened. + + If a file exists in the config folder named xxxx_up.bat, where xxxx + is the same name as an existing config file, this batch file will be + executed after a connection has been establish. If the batch file + fails (return an exitcode other than 0), an error message is displayed. + + Auto-hide status window after a connection is established and show + a systray info balloon instead. + + Show assigned IP address in connected balloon. + + Don't allow starting multiple instances of OpenVPN GUI. + + Added a cancel button to the Ask Password dialog. + +Bug Fixes: + Removed [nopass] parameter on --connect option as the password prompt + is only showed if the private key really is passphrase protected. + + Show an error msg if --connect refers to a non existing config file. + + Ignore case of config file extension. + + +[1.0-beta18 2004-09-13] + +New Features: + New Icons! Supplied by Radek Hladik. + + If only one config file exists, dubble-clicking the systray icon will + start that connection. + +Bug Fixes: + + A bug in the GetRegKey() function caused OpenVPN GUI sometimes to + fail starting with the following error msg: + Error creating exit_event when checking openvpn version. + + +[1.0-beta17 2004-09-02] + +New Features: + A dialog to configure Proxy Settings. You can now set http-proxy or + socks-proxy address and port from the GUI. You can also make the GUI + ask for proxy username and password, which will then be supplied to + OpenVPN via an auth file. + + Use Internet Explorer Proxy Settings (Ewan Bhamrah Harley) + + A "Hide" button on the status dialog. + + Show an error message if the client certificate has expired or is not + yet valid. + +Bug Fixes: + If OpenVPN was installed in a non default folder, OpenVPN GUI would try + to locate openvpn.exe, log-dir and conf-dir in the default openvpn + folder anyway. Fixed in this version. + + OpenVPN GUI tried to check the status of the OpenVPN Service even + if the service menu was disabled in the registry, which caused an + error message to be showed if the service was not installed properly. + + Wait for two seconds when exiting OpenVPN GUI, so running openvpn + processes can exit cleanly. + + Disable Disconnect menu item while waiting for an openvpn process + to terminate. + + +[1.0-beta16 2004-08-25] + +Bug Fixes: + + When only a filename (no full path) was specified in the config file + for --key or --pkcs12, OpenVPN GUI did not look for the file in the + config dir when changing password. Fixed in this version. + + +[1.0-beta15 2004-08-25] + + When changing password, require new password to be at least 8 chars. + + +[v1.0-beta14 2004-08-24] + +New Features: + Change password of the private key. Both PEM and PKCS #12 files + are supported. + + +[v1.0-beta13 2004-08-19] + +New Features: + Shows which connections are connected in the TrayIcon tip msg + +Bug Fixes: + The "Enter Passphrase" dialog was a bit miss-designed. The textlabel + and the editbox was overlapping a few pixels which made it look a + little strange in some occasions. + + +[v1.0-beta12 2004-08-16] + +New Features: + Show a Status Window while connecting that shows the output from + OpenVPN in real-time. + + A new menuitem to show the real-time status window. + + If only one connection is running, dubbleclicking the trayicon will + show the status window for the running connection. + + Show a yellow TrayIcon while connecting. + + Detect "restarting process" message, and shows "Connecting" status + until a new connected msg is received. + + +[v1.0-beta11a 2004-08-15] + +Bug Fix: + The exit_event handle was not closed after checking the openvpn version + which made it impossible to restart connections with OpenVPN versions + lower than 2.0-beta6. You received the following msg when trying to + connect a second time: + + "I seem to be running as a service, but my exit event object is telling + me to exit immediately" + + This bug was introduced with OpenVPN GUI v1.0-beta10. + + +[v1.0-beta11 2004-08-09] + +New Features: + This version is bundled with a patched version of openvpn that will + output a log message AFTER routes have been added to the system. This + allows the GUI to report "Connected" after this msg. This patch will + be included in next official release of OpenVPN 2.0-beta, so the GUI + will continue to work with future official releases of openvpn. Older + versions of openvpn will still work with this version of OpenVPN GUI, + but "Connected" will then be reported before routes are added as it + did with OpenVPN GUI 1.0-beta10. + + If wrong passphrase is entered, openvpn will automatically be restarted + a specified nr of times (default 3), which allows the user to re-enter + his passphrase. + + Number of passphase attempts to allow can be specified with reg-key + "passphrase_attempts" or cmd-line option with the same name. + +Bug Fixes: + An empty line was printed in the log when prompting for passphrase. + + +[v1.0-beta10 2004-08-08] + + Default registry setting for showing the "Edit Config" menuitem is + changed to "1" (Show it). If a previous version of OpenVPN GUI has + been used, the registry key will of cource not change without manually + changing it. + +New Features: + Check version of openvpn.exe, so it can support all versions of OpenVPN + without a special build of OpenVPN GUI. Tested with 1.5.0, 1.6.0, + 2.0-beta4, 2.0-beta7 and 2.0-beta10. Older versions than 2.0-beta6 still + only support one simultaneous connection though. + + Redirect StdIn/StdOut/StdErr through OpenVPN GUI, so we can pass the + private key passphrase to openvpn without requiring a patched version + of OpenVPN. This also allows OpenVPN GUI to prompt for a passphrase only + when it's needed. + + If connecting fails, ask the user if he wants to view the log. + + Show a dialog while connecting to allow the user to abort the connection. + +Bug Fixes: + Disable both "Connect" and "DisConnect" while connecting. + + +[v1.0-beta9 2004-07-23] + +The passphrase support added in v1.5-beta1 has been merched into the v1.0 +source so v1.5 does not exist any longer! + +New Features: + Cmd-line options: + --connect cnn [nopass]: Autoconnect to "cnn" at startup. If "nopass" + is used, no passphrase will be asked for. + --help : Show list of cmd-line options. + + And all registry settings is now available as cmd-line options: + --exe_path : Path to openvpn.exe.\n" + --config_dir : Path to dir to search for config files in.\n" + --ext_string : Extension on config files.\n" + --log_dir : Path to dir where log files will be saved.\n" + --priority_string : Priority string (See install.txt for more info).\n" + --append_string : 1=Append to log file. 0=Truncate logfile.\n" + --log_viewer : Path to log viewer.\n" + --editor : Path to config editor.\n" + --allow_edit : 1=Show Edit Config menu\n" + --allow_service : 1=Show Service control menu\n" + +Bug Fixes: + If the GUI was started from a cmd prompt and no passphrase was given + openvpn.exe would query the user for the passphrase from the console + (which is not showed), so the openvpn process got stuck there. + + +[v1.5-beta1 2004-07-16] + +This version is based on v1.0-beta8. + +v1.5 is just a temporary version in wait for the management interface +to OpenVPN. When this is available features added in v1.5 will be +rewritten to use this interface instead in v2.0 of OpenVPN-GUI. + +New Features: + Support for passphrase protected private keys. OpenVPN-GUI will now + always query the user for a passphrase before connecting. The + passphrase is then supplied to OpenVPN via the --passphrase option. + This requires a patched version of OpenVPN that supports the + --passphrase option. A patched version that supports this is included + in the OpenVPN-GUI v1.5-betaX installation package. + + The user will always be asked for a passphrase even if the private + key is not encrypted. This is because the GUI does not know in advance + if the key is encrypted or not. This will be fixed in v2.0 when we + have the management interface ready. + + +[v1.0-beta8 2004-07-16] +New Features: + Tray Icon now shows red/green if any connection is established. + +Bug Fixes: + If something failed before starting openvpn.exe, exit_event and + log_handle was not closed correctly which could make it impossible + to make any more connections without restarting OpenVPN-GUI. + + +[v1.0-beta7 2004-07-08] +New Features: + A seperate build version supporting OpenVPN v1.5, v1.6 and the + 2.0 series before beta6. This version only supports having one + connection running at the same time. + + Added an About box. + + If there are active connections when "Exit OpenVPN-GUI" is selected, + a "Are you sure you want to exit?" box is displayed. + +Bug Fixes + It was not possible to have cmd-line options on the reg-keys + "log_viewer" or "editor". This is now possible. + + +[v1.0-beta6 2004-07-05] +Bug Fixes: + The default values for paths created by beta3, beta4 and beta5 used + hardcoded values for "C:\windows..." and "C:\program files...", which + did not work on some localized Windows versions that is not using + these folders. This is fixed now by getting those pathnames from the + system. + + *** If you have installed beta3-beta5 you need to manualy delete the + whole HKEY_LM\SOFTWARE\OpenVPN-GUI key in the registry. The correct + reg-keys will then be recreated when OpenVPN-GUI is started. *** + + +[v1.0-beta5 2004-07-04] +New Features: + Menu-commands to Start/Stop/Restart the OpenVPN Service. Enable this + feature by setting the following reg-key to 1: + HKEY_LM\SOFTWARE\OpenVPN-GUI\allow_service + +Bug Fixes: + v1.0-beta4 always opened the registry with write-access, which made + it imposible to start it without administator rights. + + +[v1.0-beta4 2004-07-04] +New Features: + Menu-command to open a config-file for editing. Enable this feature + by setting the following reg-key to 1: + HKEY_LM\SOFTWARE\OpenVPN-GUI\allow_edit + + +[v1.0-beta3 2004-07-04] +New Features: + Log Viewer. As default OpenVPN-GUI launches Notepad to view the log. + The program used to view the log can be changed with this reg-key: + HKEY_LM\SOFTWARE\OpenVPN-GUI\log-viewer + + OpenVPN-GUI now uses its own registry-keys, instead of the same as + the service wrapper uses. It now stores its values under this key: + HKEY_LM\SOFTWARE\OpenVPN-GUI\ + If this key does not exist, OpenVPN-GUI will create it with the same + default values as the service-wrapper uses, so if you want to use the + service-wrapper on config-files indepentent of the GUI you should + change the "config-dir" key to another folder. + + +[v1.0-beta2 2004-07-03] +New Features: + Connect/Disconnect now shows a sub-menu so each connection can be + brought up/down individually. + + Upon connect OpenVPN-GUI will wait for 3 seconds and then check if + the openvpn process is still alive and report "Connection successful" + only if this is the case. + + OpenVPN-GUI monitors the openvpn processes it has started, and if a + process is terminated before the user has chosen to take it down, this + will be reported to the user. + + If no config files is found when OpenVPN-GUI is started, it will + notify the user of this and terminate. + + +[v1.0-beta1 2004-07-02] Initial release +Features: + Adds itself as a system tray icon. + Menuitem "Connect" - Starts openvpn for all config-files it has found. + diff --git a/chartable.h b/chartable.h new file mode 100644 index 0000000..c0201a4 --- /dev/null +++ b/chartable.h @@ -0,0 +1,280 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +WCHAR unicode_to_ascii[256] = { +0x0000, +0x0001, +0x0002, +0x0003, +0x0004, +0x0005, +0x0006, +0x0007, +0x0008, +0x0009, +0x000a, +0x000b, +0x000c, +0x000d, +0x000e, +0x000f, +0x0010, +0x0011, +0x0012, +0x0013, +0x0014, +0x0015, +0x0016, +0x0017, +0x0018, +0x0019, +0x001a, +0x001b, +0x001c, +0x001d, +0x001e, +0x001f, +0x0020, +0x0021, +0x0022, +0x0023, +0x0024, +0x0025, +0x0026, +0x0027, +0x0028, +0x0029, +0x002a, +0x002b, +0x002c, +0x002d, +0x002e, +0x002f, +0x0030, +0x0031, +0x0032, +0x0033, +0x0034, +0x0035, +0x0036, +0x0037, +0x0038, +0x0039, +0x003a, +0x003b, +0x003c, +0x003d, +0x003e, +0x003f, +0x0040, +0x0041, +0x0042, +0x0043, +0x0044, +0x0045, +0x0046, +0x0047, +0x0048, +0x0049, +0x004a, +0x004b, +0x004c, +0x004d, +0x004e, +0x004f, +0x0050, +0x0051, +0x0052, +0x0053, +0x0054, +0x0055, +0x0056, +0x0057, +0x0058, +0x0059, +0x005a, +0x005b, +0x005c, +0x005d, +0x005e, +0x005f, +0x0060, +0x0061, +0x0062, +0x0063, +0x0064, +0x0065, +0x0066, +0x0067, +0x0068, +0x0069, +0x006a, +0x006b, +0x006c, +0x006d, +0x006e, +0x006f, +0x0070, +0x0071, +0x0072, +0x0073, +0x0074, +0x0075, +0x0076, +0x0077, +0x0078, +0x0079, +0x007a, +0x007b, +0x007c, +0x007d, +0x007e, +0x007f, +0x00c7, +0x00fc, +0x00e9, +0x00e2, +0x00e4, +0x00e0, +0x00e5, +0x00e7, +0x00ea, +0x00eb, +0x00e8, +0x00ef, +0x00ee, +0x00ec, +0x00c4, +0x00c5, +0x00c9, +0x00e6, +0x00c6, +0x00f4, +0x00f6, +0x00f2, +0x00fb, +0x00f9, +0x00ff, +0x00d6, +0x00dc, +0x00f8, +0x00a3, +0x00d8, +0x00d7, +0x0192, +0x00e1, +0x00ed, +0x00f3, +0x00fa, +0x00f1, +0x00d1, +0x00aa, +0x00ba, +0x00bf, +0x00ae, +0x00ac, +0x00bd, +0x00bc, +0x00a1, +0x00ab, +0x00bb, +0x2591, +0x2592, +0x2593, +0x2502, +0x2524, +0x00c1, +0x00c2, +0x00c0, +0x00a9, +0x2563, +0x2551, +0x2557, +0x255d, +0x00a2, +0x00a5, +0x2510, +0x2514, +0x2534, +0x252c, +0x251c, +0x2500, +0x253c, +0x00e3, +0x00c3, +0x255a, +0x2554, +0x2569, +0x2566, +0x2560, +0x2550, +0x256c, +0x00a4, +0x00f0, +0x00d0, +0x00ca, +0x00cb, +0x00c8, +0x0131, +0x00cd, +0x00ce, +0x00cf, +0x2518, +0x250c, +0x2588, +0x2584, +0x00a6, +0x00cc, +0x2580, +0x00d3, +0x00df, +0x00d4, +0x00d2, +0x00f5, +0x00d5, +0x00b5, +0x00fe, +0x00de, +0x00da, +0x00db, +0x00d9, +0x00fd, +0x00dd, +0x00af, +0x00b4, +0x00ad, +0x00b1, +0x2017, +0x00be, +0x00b6, +0x00a7, +0x00f7, +0x00b8, +0x00b0, +0x00a8, +0x00b7, +0x00b9, +0x00b3, +0x00b2, +0x25a0, +0x00a0 +}; + diff --git a/connected.ico b/connected.ico new file mode 100644 index 0000000000000000000000000000000000000000..a2868681067bef88923ab98480ad289c95d03951 GIT binary patch literal 1406 zcmeH{OGs2<7=|AktuZUD%*s4vrlXc=nrUWc7t_qtyrh|zoQN<-GlU>h#D!F229c;O zx(Go~A#Ebcl`V9mQb-#S%{D>M%GneI(|ZOd3Zi8z-@|+U@BW|fJN!TR=m`o!Z!2|v z5CX)AG7&DC_J6_cb~83K#JeX>##&k!ebob>;mWl(DynL@UtLXScPI7EdK%grDSlo= zpSzFLFPSi)$~VCg3O%+svbt;Gu?5_a(f|qP;XwinD@-bP9S+k)UI`eN;Jf5U;+v#k z1xg51$*x;`a5@>a+v#;QG9j}ot%!Vg6TFrZpnCoN%nc7SH8R3`$>Xi9v|nu|CkyVC z!$TWn{K%J}_)by7aJgK}&(HI5c9v=7jt>kFeLWWYSJiz1QFTyUrr2JwL%a<$Q&W7J zn`3%%l9`DKMg|9Y+0_M4<$or&LAw@ni#uY3dSV$AWam(LA&&GgC{0%1GIxvmEOIrc zhRe-dY-~bZn=O0(m6k;;PT)UJpvG#oo`qWbIlH-Yyos{%(-mhbE32wWJeGSr??iq< z;mM-nlG0Norti-STD@lNFWujNdB6%?TVB7J<@* literal 0 HcmV?d00001 diff --git a/connecting.ico b/connecting.ico new file mode 100644 index 0000000000000000000000000000000000000000..00d77ad9a6f110bc4abb4109ec1d49cdefd05521 GIT binary patch literal 1406 zcmeH{OGs2<7=|AktuZUD%*s4vrlXc=nrUWc7t_qtyrh|zoQN<-GlU>h#D!F23X!NS zx(Go~A#Ebcl`V9mQb-#S&6YtcXHyVN?-`sZh?cE<5AXTE`+vUg@c-bWCnyNLt$2UGih`ZBnoT zB?PKu*Bw4Oos8M-^f?-tl-ZS5M83NT-be{hy@3JdM@E<)9p!`MiPl!yuQ!vE1^3J0 zkqt6_J4LTrL(C7Wgzb$Bc3(1_z108H@d^>b``iIw&qvY@gU6_Q34)G@s|^ znVFhmc5;%@p&?#%b-^?FpNnnKuEpHqt{9=7SOEpuITT)sBRvdClhwD(-J(8=T+ONB zYBQG`n^4zg%btIwWeH0Y_|Frlv0AO?q1JxEZtfg!qOAOE#ktDLs%jEXoy~Nd&G`NzvUhTZwT4AX>;fn7Ioj%YXXDTu3P_0_xE2Juu9jK*KcO|{zYFV wSS%J_uirB~Z<6Bw&~+|7@Fq!lcS}dzM}kSAW09upv6*&VXTS5CbPrYUCsfst(*OVf literal 0 HcmV?d00001 diff --git a/disconnected.ico b/disconnected.ico new file mode 100644 index 0000000000000000000000000000000000000000..b99aacdb43daa8300fc4a1cd0ac5f9acb014b3f6 GIT binary patch literal 1406 zcmeH{OGs2<7=|AktuZUD%*s4vrlXc=nrUWc7t_qtyrh|zoQN<-GlU>h#D!F229c;O zx(Gp#A#Ebcl`V9mQb-#S&6YtcXHyVN?-`sZh?cE<5AXTE`+vUg@c-bWCnyNLt#7HPA6k_JH3uZCS`V|6_M|5f;UnERIk6E`H>N(M@RV}d7`zI_Up~$WWj@S zcx;1=ANdj#-zjPsE|-gig#|v%%`v0giGcy4Z^mN(s=6;Bst$_F6x%Cyh<9OjdYaGk z^UO?5F*`ZQ=+F?ay1L-G{DWc}v}-Z9xF<%aCssf~b`FJ?;z$pJ(q#25bGN9^B3E;2 zxZ2F+#wOIY*|O(fX<5S31pe~`YOGf4d8oBtu$w!_nq6?uy&( z=Wim+*t*RK-yX3e(r>v3!5cz0ZrU8Wg+<+W^_sw-wd>aZ(*6Bc2CUMx<@K9czJJk| x2^NdR*X#ET&zq$9KXjc-54=fI-rdqs_mN;y=vbsFdu*m%*V*s + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +LPCTSTR getIeHttpProxyError=NULL; + +/* getIeHttpProxy fetches the current IE proxy settings for http */ + +LPCTSTR getIeHttpProxy() +{ + DWORD psize=0; + INTERNET_PROXY_INFO *pinfo; + LPTSTR proxyString; + LPTSTR p; + LPTSTR q; + unsigned int len; + + /* first see how big a buffer we need for the IPO structure */ + InternetQueryOption(NULL, INTERNET_OPTION_PROXY, NULL, &psize); + if(!psize) + { + getIeHttpProxyError="InternetQueryOption failed to return buffer size"; + return(NULL); + } + + /* allocate memory for IPO */ + pinfo = malloc (psize*sizeof(TCHAR)); + if (pinfo == NULL) + { + getIeHttpProxyError="malloc failed (1)"; + return(NULL); + } + + /* now run the real query */ + if(!InternetQueryOption(NULL, INTERNET_OPTION_PROXY, (LPVOID) pinfo, &psize)) + { + getIeHttpProxyError="InternetQueryOption() failed to find proxy info"; + free(pinfo); + return(NULL); + } + + + /* see what sort of result we got */ + + if(pinfo->dwAccessType == INTERNET_OPEN_TYPE_DIRECT) + { + /* No proxy configured */ + free(pinfo); + return(""); + } + else if(pinfo->dwAccessType == INTERNET_OPEN_TYPE_PROXY) + { + /* we have a proxy - now parse result string */ + /* if result string does NOT contain an '=' sign then */ + /* there is a single proxy for all protocols */ + for (p=(LPTSTR)pinfo->lpszProxy; *p && *p != '='; p++); + if(!*p) + { + /* single proxy */ + /* allocate a new string to return */ + len = 1+strlen(pinfo->lpszProxy); + proxyString = malloc (len*sizeof(TCHAR)); + if (proxyString == NULL) + { + getIeHttpProxyError="malloc failed (2)"; + free(pinfo); + return(NULL); + } + strncpy(proxyString, pinfo->lpszProxy,len); + proxyString[len]=0; + free(pinfo); + return(proxyString); + } + else + { + /* multiple space seperated proxies defined in the form */ + /* protocol=proxyhost[:port] */ + /* we want the one marked "http=", if any. */ + p=(LPTSTR)pinfo->lpszProxy; + while(*p && strncmp(p, "http=", 5)) + { + for(; *p && *p != ' '; p++); + if(*p) p++; + } + if(*p) + { + /* found the proxy */ + p+=5; + for(q=p; *q && *q != ' '; q++); + /* allocate a buffer for the proxy information */ + len=1+(q-p); + proxyString=malloc(len*sizeof(TCHAR)); + if(proxyString==NULL) + { + getIeHttpProxyError="malloc failed (3)"; + free(pinfo); + return(NULL); + } + strncpy(proxyString, p, len); + proxyString[len]=0; + free(pinfo); + return(proxyString); + } + else + { + /* No http proxy in list */ + free(pinfo); + return(""); + } + } + } + else + { + /* InternetQueryOption returned a proxy type we don't know about*/ + getIeHttpProxyError="Unknown Proxy Type"; + free(pinfo); + return(NULL); + } +} diff --git a/ieproxy.h b/ieproxy.h new file mode 100644 index 0000000..0786c05 --- /dev/null +++ b/ieproxy.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2004 Ewan Bhamrah Harley + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __GETIEHTTPPROXY__ +#define __GETIEHTTPPROXY__ +extern LPTSTR getIeHttpProxyError; +LPCTSTR getIeHttpProxy(); +#endif diff --git a/main.c b/main.c new file mode 100644 index 0000000..6a6c4ba --- /dev/null +++ b/main.c @@ -0,0 +1,500 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include "tray.h" +#include "openvpn.h" +#include "openvpn_config.h" +#include "viewlog.h" +#include "service.h" +#include "main.h" +#include "options.h" +#include "passphrase.h" +#include "proxy.h" +#include "registry.h" +#include "openvpn-gui-res.h" + +#ifndef DISABLE_CHANGE_PASSWORD +#include +#include +#endif + +/* Declare Windows procedure */ +LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); +BOOL CALLBACK AboutDialogFunc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +void CloseApplication(HWND hwnd); + +/* Class name and window title */ +char szClassName[ ] = "OpenVPN-GUI"; +char szTitleText[ ] = "OpenVPN"; + +/* Options structure */ +struct options o; + +int WINAPI WinMain (HINSTANCE hThisInstance, + UNUSED HINSTANCE hPrevInstance, + LPSTR lpszArgument, + UNUSED int nCmdShow) +{ + HWND hwnd; /* This is the handle for our window */ + MSG messages; /* Here messages to the application are saved */ + WNDCLASSEX wincl; /* Data structure for the windowclass */ + HWND hwndAbout; + DWORD shell32_version; + + + /* initialize options to default state */ + init_options (&o); + +#ifdef DEBUG + /* Open debug file for output */ + if (!(o.debug_fp = fopen(DEBUG_FILE, "w"))) + { + /* can't open debug file */ + ShowLocalizedMsg(GUI_NAME, ERR_OPEN_DEBUG_FILE, DEBUG_FILE); + exit(1); + } + PrintDebug("Starting OpenVPN GUI v%s", GUI_VERSION); +#endif + + + o.hInstance = hThisInstance; + + if(!GetModuleHandle("RICHED20.DLL")) + { + LoadLibrary("RICHED20.DLL"); + } + else + { + /* can't load riched20.dll */ + ShowLocalizedMsg(GUI_NAME, ERR_LOAD_RICHED20, ""); + exit(1); + } + + /* Check version of shell32.dll */ + shell32_version=GetDllVersion("shell32.dll"); + if (shell32_version < PACKVERSION(5,0)) + { + /* shell32.dll version to low */ + ShowLocalizedMsg(GUI_NAME, ERR_SHELL_DLL_VERSION, shell32_version); + exit(1); + } +#ifdef DEBUG + PrintDebug("Shell32.dll version: 0x%lx", shell32_version); +#endif + + + /* Parse command-line options */ + Createargcargv(&o, lpszArgument); + + /* Check if a previous instance is already running. */ + if ((FindWindow (szClassName, NULL)) != NULL) + { + /* GUI already running */ + ShowLocalizedMsg(GUI_NAME, ERR_GUI_ALREADY_RUNNING, ""); + exit(1); + } + + if (!GetRegistryKeys()) { + exit(1); + } + if (!CheckVersion()) { + exit(1); + } + if (!BuildFileList()) { + exit(1); + } + if (!VerifyAutoConnections()) { + exit(1); + } + GetProxyRegistrySettings(); + +#ifndef DISABLE_CHANGE_PASSWORD + /* Initialize OpenSSL */ + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); +#endif + + /* The Window structure */ + wincl.hInstance = hThisInstance; + wincl.lpszClassName = szClassName; + wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */ + wincl.style = CS_DBLCLKS; /* Catch double-clicks */ + wincl.cbSize = sizeof (WNDCLASSEX); + + /* Use default icon and mouse-pointer */ + wincl.hIcon = LoadIcon (hThisInstance, MAKEINTRESOURCE(APP_ICON)); + wincl.hIconSm = LoadIcon (hThisInstance, MAKEINTRESOURCE(APP_ICON)); + wincl.hCursor = LoadCursor (NULL, IDC_ARROW); + wincl.lpszMenuName = NULL; /* No menu */ + wincl.cbClsExtra = 0; /* No extra bytes after the window class */ + wincl.cbWndExtra = 0; /* structure or the window instance */ + /* Use Windows's default color as the background of the window */ + wincl.hbrBackground = (HBRUSH) COLOR_3DSHADOW; //COLOR_BACKGROUND; + + /* Register the window class, and if it fails quit the program */ + if (!RegisterClassEx (&wincl)) + return 1; + + /* The class is registered, let's create the program*/ + hwnd = CreateWindowEx ( + 0, /* Extended possibilites for variation */ + szClassName, /* Classname */ + szTitleText, /* Title Text */ + WS_OVERLAPPEDWINDOW, /* default window */ + (int)CW_USEDEFAULT, /* Windows decides the position */ + (int)CW_USEDEFAULT, /* where the window ends up on the screen */ + 230, /* The programs width */ + 200, /* and height in pixels */ + HWND_DESKTOP, /* The window is a child-window to desktop */ + NULL, /* No menu */ + hThisInstance, /* Program Instance handler */ + NULL /* No Window Creation data */ + ); + + + /* Run the message loop. It will run until GetMessage() returns 0 */ + while (GetMessage (&messages, NULL, 0, 0)) + { + TranslateMessage(&messages); + DispatchMessage(&messages); + } + + /* The program return-value is 0 - The value that PostQuitMessage() gave */ + return messages.wParam; +} + + +/* This function is called by the Windows function DispatchMessage() */ +LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + static UINT s_uTaskbarRestart; + int i; + + switch (message) { + case WM_CREATE: + + /* Save Window Handle */ + o.hWnd = hwnd; + + s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated")); + + CreatePopupMenus(); /* Create popup menus */ + LoadAppIcon(); /* Load App Icon */ + ShowTrayIcon(); + if (o.allow_service[0]=='1' || o.service_only[0]=='1') + CheckServiceStatus(); // Check if service is running or not + if (!AutoStartConnections()) { + SendMessage(hwnd, WM_CLOSE, 0, 0); + break; + } + break; + + case WM_NOTIFYICONTRAY: + OnNotifyTray(lParam); // Manages message from tray + return TRUE; + + case WM_COMMAND: + if ( (LOWORD(wParam) >= IDM_CONNECTMENU) && (LOWORD(wParam) < IDM_CONNECTMENU + MAX_CONFIGS) ) { + StartOpenVPN(LOWORD(wParam) - IDM_CONNECTMENU); + } + if ( (LOWORD(wParam) >= IDM_DISCONNECTMENU) && (LOWORD(wParam) < IDM_DISCONNECTMENU + MAX_CONFIGS) ) { + StopOpenVPN(LOWORD(wParam) - IDM_DISCONNECTMENU); + } + if ( (LOWORD(wParam) >= IDM_STATUSMENU) && (LOWORD(wParam) < IDM_STATUSMENU + MAX_CONFIGS) ) { + ShowWindow(o.cnn[LOWORD(wParam) - IDM_STATUSMENU].hwndStatus, SW_SHOW); + } + if ( (LOWORD(wParam) >= IDM_VIEWLOGMENU) && (LOWORD(wParam) < IDM_VIEWLOGMENU + MAX_CONFIGS) ) { + ViewLog(LOWORD(wParam) - IDM_VIEWLOGMENU); + } + if ( (LOWORD(wParam) >= IDM_EDITMENU) && (LOWORD(wParam) < IDM_EDITMENU + MAX_CONFIGS) ) { + EditConfig(LOWORD(wParam) - IDM_EDITMENU); + } +#ifndef DISABLE_CHANGE_PASSWORD + if ( (LOWORD(wParam) >= IDM_PASSPHRASEMENU) && (LOWORD(wParam) < IDM_PASSPHRASEMENU + MAX_CONFIGS) ) { + ShowChangePassphraseDialog(LOWORD(wParam) - IDM_PASSPHRASEMENU); + } +#endif + if (LOWORD(wParam) == IDM_PROXY) { + ShowProxySettingsDialog(); + } + if (LOWORD(wParam) == IDM_ABOUT) { + DialogBox(o.hInstance, (LPCTSTR)IDD_ABOUTDIALOG, NULL, (DLGPROC)AboutDialogFunc); + } + if (LOWORD(wParam) == IDM_CLOSE) { + CloseApplication(hwnd); + } + if (LOWORD(wParam) == IDM_SERVICE_START) { + MyStartService(); + } + if (LOWORD(wParam) == IDM_SERVICE_STOP) { + MyStopService(); + } + if (LOWORD(wParam) == IDM_SERVICE_RESTART) MyReStartService(); + break; + + case WM_CLOSE: + CloseApplication(hwnd); + break; + + case WM_DESTROY: + StopAllOpenVPN(); + OnDestroyTray(); /* Remove Tray Icon and destroy menus */ + PostQuitMessage (0); /* Send a WM_QUIT to the message queue */ + break; + + case WM_QUERYENDSESSION: + return(TRUE); + + case WM_ENDSESSION: + StopAllOpenVPN(); + OnDestroyTray(); + break; + + case WM_POWERBROADCAST: + switch (wParam) { + case PBT_APMSUSPEND: + if (o.disconnect_on_suspend[0] == '1') + { + /* Suspend running connections */ + for (i=0; itm_year + 1900, + time_struct->tm_mon + 1, + time_struct->tm_mday, + time_struct->tm_hour, + time_struct->tm_min, + time_struct->tm_sec); + + fprintf(o.debug_fp, "%s %s\n", date, msg); + fflush(o.debug_fp); +} + +void PrintErrorDebug(char *msg) +{ + LPVOID lpMsgBuf; + char *buf; + + /* Get last error message */ + if (!FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL )) + { + /* FormatMessage failed! */ + PrintDebug("FormatMessage() failed. %s ", msg); + return; + } + + /* Cut of CR/LFs */ + buf = (char *)lpMsgBuf; + buf[strlen(buf) - 3] = '\0'; + + PrintDebug("%s %s", msg, (LPCTSTR)lpMsgBuf); + +} +#endif + +bool +init_security_attributes_allow_all (struct security_attributes *obj) +{ + CLEAR (*obj); + + obj->sa.nLength = sizeof (SECURITY_ATTRIBUTES); + obj->sa.lpSecurityDescriptor = &obj->sd; + obj->sa.bInheritHandle = FALSE; + if (!InitializeSecurityDescriptor (&obj->sd, SECURITY_DESCRIPTOR_REVISION)) + return false; + if (!SetSecurityDescriptorDacl (&obj->sd, TRUE, NULL, FALSE)) + return false; + return true; +} + +#define PACKVERSION(major,minor) MAKELONG(minor,major) +DWORD GetDllVersion(LPCTSTR lpszDllName) +{ + HINSTANCE hinstDll; + DWORD dwVersion = 0; + + /* For security purposes, LoadLibrary should be provided with a + fully-qualified path to the DLL. The lpszDllName variable should be + tested to ensure that it is a fully qualified path before it is used. */ + hinstDll = LoadLibrary(lpszDllName); + + if(hinstDll) + { + DLLGETVERSIONPROC pDllGetVersion; + pDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hinstDll, + "DllGetVersion"); + + /* Because some DLLs might not implement this function, you + must test for it explicitly. Depending on the particular + DLL, the lack of a DllGetVersion function can be a useful + indicator of the version. */ + + if(pDllGetVersion) + { + DLLVERSIONINFO dvi; + HRESULT hr; + + ZeroMemory(&dvi, sizeof(dvi)); + dvi.cbSize = sizeof(dvi); + + hr = (*pDllGetVersion)(&dvi); + + if(SUCCEEDED(hr)) + { + dwVersion = PACKVERSION(dvi.dwMajorVersion, dvi.dwMinorVersion); + } + } + + FreeLibrary(hinstDll); + } + return dwVersion; +} diff --git a/main.h b/main.h new file mode 100644 index 0000000..a9c0587 --- /dev/null +++ b/main.h @@ -0,0 +1,108 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +/* Define this to enable DEBUG build */ +//#define DEBUG +#define DEBUG_FILE "c:\\openvpngui_debug.txt" + +/* Define this to disable Change Password support */ +//#define DISABLE_CHANGE_PASSWORD + +#define GUI_NAME "OpenVPN GUI" +#define GUI_VERSION "1.0.3" + +/* Registry key for User Settings */ +#define GUI_REGKEY_HKCU "Software\\Nilings\\OpenVPN-GUI" + +/* Registry key for Global Settings */ +#define GUI_REGKEY_HKLM "SOFTWARE\\OpenVPN-GUI" + +#define MAX_LOG_LINES 500 /* Max number of lines in LogWindow */ +#define DEL_LOG_LINES 10 /* Number of lines to delete from LogWindow */ + + + +/* bool definitions */ +#define bool int +#define true 1 +#define false 0 + +/* GCC function attributes */ +#define UNUSED __attribute__ ((unused)) +#define NORETURN __attribute__ ((noreturn)) + +#define PACKVERSION(major,minor) MAKELONG(minor,major) +struct security_attributes +{ + SECURITY_ATTRIBUTES sa; + SECURITY_DESCRIPTOR sd; +}; + + +/* clear an object */ +#define CLEAR(x) memset(&(x), 0, sizeof(x)) + +/* snprintf with guaranteed null termination */ +#define mysnprintf(out, args...) \ + { \ + snprintf (out, sizeof(out), args); \ + out [sizeof (out) - 1] = '\0'; \ + } + + +/* Show Message */ +#define ShowMsg(caption, args...) \ + { \ + char x_msg[256]; \ + mysnprintf (x_msg, args); \ + MessageBox(NULL, x_msg, caption, MB_OK | MB_SETFOREGROUND); \ + } + +#define ShowLocalizedMsg(caption, id, args...) \ + { \ + char x_msg[256]; \ + TCHAR x_buf[1000]; \ + LoadString(o.hInstance, id, x_buf, sizeof(x_buf)/sizeof(TCHAR)); \ + mysnprintf(x_msg, x_buf, args); \ + MessageBox(NULL, x_msg, caption, MB_OK | MB_SETFOREGROUND); \ + } +#define myLoadString(id) \ + { \ + LoadString(o.hInstance, id, buf, sizeof(buf)/sizeof(TCHAR)); \ + } + +#ifdef DEBUG +/* Print Debug Message */ +#define PrintDebug(args...) \ + { \ + char x_msg[256]; \ + mysnprintf (x_msg, args); \ + PrintDebugMsg(x_msg); \ + } + +void PrintDebugMsg(char *msg); +void PrintErrorDebug(char *msg); +bool init_security_attributes_allow_all (struct security_attributes *obj); +#endif + +DWORD GetDllVersion(LPCTSTR lpszDllName); diff --git a/openvpn-gui-en.rc b/openvpn-gui-en.rc new file mode 100644 index 0000000..b9fef5e --- /dev/null +++ b/openvpn-gui-en.rc @@ -0,0 +1,351 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "openvpn-gui-res.h" +#include + +/* Application Icons */ +APP_ICON ICON DISCARDABLE "openvpn-gui.ico" +APP_ICON_CONNECTED ICON DISCARDABLE "connected.ico" +APP_ICON_CONNECTING ICON DISCARDABLE "connecting.ico" +APP_ICON_DISCONNECTED ICON DISCARDABLE "disconnected.ico" + +/* About Dialog - designed with lcc-win32 resource editor */ +IDD_ABOUTDIALOG DIALOG 0, 0, 260, 135 +STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_CENTER +CAPTION "About - OpenVPN GUI for Windows" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "OK", IDOK, 99, 115, 63, 14 + ICON APP_ICON_CONNECTED, 204, 11, 8, 21, 20 + LTEXT "", ID_TEXT_OPENVPNGUI, 40, 5, 215, 8 + LTEXT "Copyright (C) 2004-2005 Mathias Sundman ", 102, 40, 15, 215, 8 + LTEXT "http://openvpn.se/", 103, 40, 25, 215, 8 + LTEXT "OpenVPN - An application to securely tunnel IP networks " \ + "over a single UDP port, with support for SSL/TLS-based " \ + "session authentication and key exchange, packet " \ + "encryption, packet authentication, and packet compression.", + 104, 11, 51, 235, 34 + LTEXT "Copyright (C) 2002-2005 OpenVPN Solutions LLC ", 105, 11, 87, 235, 11 + LTEXT "http://openvpn.net/", 106, 11, 98, 235, 10 +END + +/* Passphrase Dialog */ +IDD_PASSPHRASE DIALOGEX 6, 18, 120, 51 +STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | DS_CENTER | DS_SETFOREGROUND +EXSTYLE WS_EX_TOPMOST +CAPTION "OpenVPN" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Enter Password:", 201, 6, 6, 100, 10 + EDITTEXT EDIT_PASSPHRASE, 6, 17, 107, 12, ES_PASSWORD | ES_AUTOHSCROLL + PUSHBUTTON "OK", IDOK, 6, 33, 50, 14 + PUSHBUTTON "Cancel", IDCANCEL, 64, 33, 50, 14 +END + +/* Auth Username/Password Dialog */ +IDD_AUTH_PASSWORD DIALOG 6, 18, 160, 62 +STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | DS_CENTER | DS_SETFOREGROUND +CAPTION "OpenVPN - User Authentication" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Username:", 0, 6, 9, 50, 10 + LTEXT "Password:", 0, 6, 26, 50, 10 + EDITTEXT EDIT_AUTH_USERNAME, 60, 6, 94, 12, ES_AUTOHSCROLL + EDITTEXT EDIT_AUTH_PASSWORD, 60, 23, 94, 12, ES_PASSWORD | ES_AUTOHSCROLL + PUSHBUTTON "OK", IDOK, 20, 42, 50, 14 + PUSHBUTTON "Cancel", IDCANCEL, 90, 42, 52, 14 +END + +/* Status Dialog */ +IDD_STATUS DIALOG 6, 18, 380, 210 +STYLE WS_SIZEBOX | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | DS_CENTER +CAPTION "OpenVPN" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Connecting...", TEXT_STATUS, 20, 5, 200, 10 + PUSHBUTTON "Disconnect", ID_DISCONNECT, 50, 190, 50, 14 + PUSHBUTTON "Reconnect", ID_RESTART, 150, 190, 50, 14 + PUSHBUTTON "Hide", ID_HIDE, 100, 190, 50, 14 + LTEXT "", TEXT_CONFIG, 0, 0, 0, 0 +END + +/* Change Passphrase Dialog */ +IDD_CHANGEPSW DIALOG 6, 18, 193, 82 +STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_CENTER +CAPTION "OpenVPN - Change Passphrase" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Old Password:", 171, 6, 9, 85, 10 + LTEXT "New Password:", 172, 6, 26, 85, 10 + LTEXT "Confirm New Password:", 173, 6, 42, 85, 10 + EDITTEXT EDIT_PSW_CURRENT, 95, 6, 90, 12, ES_PASSWORD | ES_AUTOHSCROLL + EDITTEXT EDIT_PSW_NEW, 95, 23, 90, 12, ES_PASSWORD | ES_AUTOHSCROLL + EDITTEXT EDIT_PSW_NEW2, 95, 39, 90, 12, ES_PASSWORD | ES_AUTOHSCROLL + PUSHBUTTON "OK", IDOK, 40, 59, 50, 14 + PUSHBUTTON "Cancel", IDCANCEL, 103, 59, 50, 14 + LTEXT "", TEXT_KEYFORMAT, 0, 0, 0, 0 + LTEXT "", TEXT_KEYFILE, 0, 0, 0, 0 +END + +/* Proxy Settings Dialog */ +IDD_PROXY DIALOG 6, 18, 269, 228 +STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_CENTER +CAPTION "OpenVPN - Proxy Settings" +FONT 8, "MS Sans Serif" +BEGIN + GROUPBOX "", 201, 13, 62, 243, 137 + AUTORADIOBUTTON "Use OpenVPN Config-file Settings", RB_PROXY_USE_OPENVPN, \ + 20, 12, 200, 10, WS_GROUP | WS_TABSTOP + AUTORADIOBUTTON "Use Internet Explorer Settings (manually configured)", \ + RB_PROXY_USE_IE, 20, 31, 200, 10 + AUTORADIOBUTTON "Manual Configuration", RB_PROXY_USE_MANUAL, 20, 50, 200, 10 + AUTORADIOBUTTON "HTTP Proxy", RB_PROXY_HTTP, 20, 74, 59, 10, WS_GROUP | WS_TABSTOP + AUTORADIOBUTTON "SOCKS Proxy", RB_PROXY_SOCKS, 20, 147, 67, 10 + GROUPBOX "", 202, 20, 86, 225, 43 + LTEXT "Address:", TEXT_PROXY_HTTP_ADDRESS, 27, 98, 41, 10 + LTEXT "Port:", TEXT_PROXY_HTTP_PORT, 176, 98, 25, 10 + EDITTEXT EDIT_PROXY_HTTP_ADDRESS, 70, 96, 92, 12, ES_AUTOHSCROLL + EDITTEXT EDIT_PROXY_HTTP_PORT, 206, 96, 30, 12, ES_AUTOHSCROLL + AUTOCHECKBOX "Prompt for username/password when connecting.", CHECKB_PROXY_AUTH, 27, 112, 183, 10 + GROUPBOX "", 203, 20, 158, 225, 33 + LTEXT "Address:", TEXT_PROXY_SOCKS_ADDRESS, 27, 172, 41, 10 + LTEXT "Port:", TEXT_PROXY_SOCKS_PORT, 176, 172, 20, 10 + EDITTEXT EDIT_PROXY_SOCKS_ADDRESS, 70, 170, 98, 12, ES_AUTOHSCROLL + EDITTEXT EDIT_PROXY_SOCKS_PORT, 206, 170, 30, 12, ES_AUTOHSCROLL + PUSHBUTTON "OK", IDOK, 63, 206, 50, 14 + PUSHBUTTON "Cancel", IDCANCEL, 159, 206, 50, 14 +END + +/* Proxy Authentication Dialog */ +IDD_PROXY_AUTH DIALOG 29, 23, 154, 65 +STYLE DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | DS_CENTER +CAPTION "OpenVPN - Proxy Authentication" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Username:", 201, 9, 8, 38, 10 + EDITTEXT EDIT_PROXY_USERNAME, 49, 5, 94, 12, ES_AUTOHSCROLL + LTEXT "Password:", 202, 9, 26, 38, 10 + EDITTEXT EDIT_PROXY_PASSWORD, 49, 23, 94, 12, ES_PASSWORD | ES_AUTOHSCROLL + PUSHBUTTON "OK", IDOK, 58, 43, 40, 14 +END + +STRINGTABLE +BEGIN + /* About Dialog */ + TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - A Windows GUI for OpenVPN" + + /* Tray - Resources */ + MSG_TIP "OpenVPN GUI " + MSG_TIP_CONNECTED "\nConnected to: " + MSG_TIP_CONNECTING "\nConnecting to: " + MSG_TIP_CONNECTED_SINCE "\nConnected since: " + MSG_TIP_ASSIGNED_IP "\nAssigned IP: %s" + IDM_TEXT_SERVICE "OpenVPN Service" + IDM_TEXT_PROXY "Proxy Settings" + IDM_TEXT_ABOUT "About" + IDM_TEXT_CLOSE "Exit" + IDM_TEXT_CONNECT "Connect" + IDM_TEXT_DISCONNECT "Disconnect" + IDM_TEXT_STATUS "Show Status" + IDM_TEXT_VIEWLOG "View Log" + IDM_TEXT_EDITCONFIG "Edit Config" + IDM_TEXT_PASSPHRASE "Change Password" + IDM_TEXT_SERVICE_START "Start" + IDM_TEXT_SERVICE_STOP "Stop" + IDM_TEXT_SERVICE_RESTART "Restart" + IDM_TEXT_SERVICEONLY_START "Connect" + IDM_TEXT_SERVICEONLY_STOP "Disconnect" + IDM_TEXT_SERVICEONLY_RESTART "Reconnect" + IDM_TEXT_ASK_STOP_SERVICE "Do you want to disconnect (Stop the OpenVPN Service)?" + + /* Logviewer - Resources */ + ERR_START_LOG_VIEWER "Error starting log-viewer: %s" + ERR_START_CONF_EDITOR "Error starting config-editor: %s" + + /* OpenVPN */ + ERR_TO_MANY_CONFIGS "OpenVPN GUI does not support more than %d configs. Please contact the author if you have the need for more." + ERR_CANNOT_CONSTRUCT_LOG "Cannot construct logfile name based on: %s" + ERR_ONLY_ONE_CONN_OLD_VERSION "You can only have one connection running at the same time when using an older version on OpenVPN than 2.0-beta6." + ERR_STOP_SERV_ON_OLD_VERSION "You cannot use OpenVPN GUI to start a connection while the OpenVPN Service is running (with OpenVPN 1.5/1.6). Stop OpenVPN Service first if you want to use OpenVPN GUI." + ERR_CREATE_EVENT "CreateEvent failed on exit event: %s" + ERR_UNKNOWN_PRIORITY "Unknown priority name: %s" + ERR_LOG_APPEND_BOOL "Log file append flag (given as '%s') must be '0' or '1'" + ERR_GET_IE_PROXY_SETTINGS "Unable to get IE proxy settings because:\n%s" + ERR_INIT_SEC_DESC "InitializeSecurityDescriptor failed." + ERR_SET_SEC_DESC_ACL "SetSecurityDescriptorDacl failed." + ERR_CREATE_PIPE_OUTPUT "CreatePipe on hOutputWrite failed." + ERR_DUP_HANDLE_ERR_WRITE "DuplicateHandle on hErrorWrite failed." + ERR_CREATE_PIPE_INPUT "CreatePipe on hInputRead failed." + ERR_DUP_HANDLE_OUTPUT_READ "DuplicateHandle on hOutputRead failed." + ERR_DUP_HANDLE_INPUT_WRITE "DuplicateHandle on hInputWrite failed." + ERR_CLOSE_HANDLE_TMP "CloseHandle on hOutputReadTmp/hInputWriteTmp failed." + ERR_CREATE_PROCESS "CreateProcess failed, exe='%s' cmdline='%s' dir='%s'" + ERR_CLOSE_HANDLE "CloseHandle failed." + ERR_CREATE_THREAD_STATUS "CreateThread to show Status window Failed." + INFO_STATE_WAIT_TERM "Current State: Waiting for OpenVPN to terminate..." + ERR_OPEN_LOG_WRITE "Error opening logfile for writing: %s. You probably don't have administrator privileges, which are necessary to run OpenVPN." + INFO_STATE_CONNECTED "Current State: Connected" + INFO_NOW_CONNECTED "%s is now connected." + INFO_ASSIG_IP "Assigned IP: %s" + ERR_CERT_EXPIRED "Unable to connect because your certificate has expired or the system time is incorrect." + ERR_CERT_NOT_YET_VALID "Unable to connect because your certificate is not yet valid. Check that your system time is correct." + INFO_STATE_RECONNECTING "Current State: Reconnecting" + INFO_STATE_DISCONNECTED "Current State: Disconnected" + INFO_CONN_TERMINATED "Connection to %s was terminated." + INFO_STATE_FAILED "Current State: Failed to connect" + INFO_CONN_FAILED "Connecting to %s has failed." + INFO_STATE_FAILED_RECONN "Current State: Failed to reconnect" + INFO_RECONN_FAILED "ReConnecting to %s has failed." + INFO_STATE_SUSPENDED "Current State: Suspended" + ERR_READ_STDOUT_PIPE "Error reading from OpenVPN StdOut Pipe." + ERR_CREATE_RICHED_LOGWINDOW "Creating RichEdit LogWindow Failed!!" + ERR_SET_SIZE "Set Size failed!" + ERR_AUTOSTART_CONF_NOT_FOUND "Cannot find requested config to autostart: %s" + ERR_VERSION_CREATE_EVENT "CreateEvent() failed when checking openvpn version." + ERR_CREATE_PIPE_INPUT_READ "CreatePipe on hInputRead failed." + INFO_STATE_CONNECTING "Current State: Connecting" + INFO_CONNECTION_XXX "OpenVPN Connection (%s)" + ERR_CREATE_THREAD_READ_STDOUT "CreateThread to read openvpn process stdout failed." + INFO_STATE_CONN_SCRIPT "Current State: Running Connect Script" + INFO_STATE_DISCONN_SCRIPT "Current State: Running Disconnect Script" + ERR_RUN_CONN_SCRIPT "Error running Connect Script: %s" + ERR_GET_EXIT_CODE "Failed to get ExitCode of Connect Script (%s)" + ERR_CONN_SCRIPT_FAILED "Connect Script failed. (exitcode=%ld)" + ERR_RUN_CONN_SCRIPT_TIMEOUT "Connect Script failed. TimeOut after %d sec." + ERR_CONFIG_ALREADY_EXIST "There already exist a config file named '%s'. You cannot " \ + "have multiple config files with the same name, even if " \ + "they reside in diffrent folders." + /* main - Resources */ + ERR_OPEN_DEBUG_FILE "Error opening debug file (%s) for output." + ERR_LOAD_RICHED20 "Could not load RICHED20.DLL." + ERR_SHELL_DLL_VERSION "Your shell32.dll version is to low (0x%lx). You need at least version 5.0." + ERR_GUI_ALREADY_RUNNING "OpenVPN GUI is already running." + INFO_SERVICE_STARTED "OpenVPN Service started." + INFO_SERVICE_STOPPED "OpenVPN Service stopped." + INFO_ACTIVE_CONN_EXIT "There are still active connections that will be closed if you exit OpenVPN GUI." \ + "\n\nAre you sure you want to exit?" + INFO_SERVICE_ACTIVE_EXIT "You are currently connected (the OpenVPN Service is running). " \ + "You will stay connected even if you exit OpenVPN GUI.\n\n" \ + "Do you want to proceed and exit OpenVPN GUI?" + ERR_OPTION_LOG_IN_CONFIG "You have ""log"" or ""log-append"" in your OpenVPN config file. These options " \ + "should not be used with OpenVPN GUI as they prevents OpenVPN GUI from reading " \ + "the log output of OpenVPN which is necessary for correct operation of OpenVPN " \ + "GUI. The log is always written to a logfile when OpenVPN GUI is beeing used " \ + "anyway, so you should remove this option.\n\nDo you want to proceed connecting " \ + "anyway?" + + /* options - Resources */ + INFO_USAGE "--help\t\t\t: Show this message.\n" \ + "--connect cnn \t\t: Connect to ""cnn"" at startup. (extension must be included)\n" \ + "\t\t\t Example: openvpn-gui --connect office.ovpn\n" \ + "\n" \ + "Options to override registry settings:\n" \ + "--exe_path\t\t: Path to openvpn.exe.\n" \ + "--config_dir\t\t: Path to dir to search for config files in.\n" \ + "--ext_string\t\t: Extension on config files.\n" \ + "--log_dir\t\t\t: Path to dir where log files will be saved.\n" \ + "--priority_string\t\t: Priority string (See install.txt for more info).\n" \ + "--append_string\t\t: 1=Append to log file. 0=Truncate logfile when connecting.\n" \ + "--log_viewer\t\t: Path to log viewer.\n" \ + "--editor\t\t\t: Path to config editor.\n" \ + "--allow_edit\t\t: 1=Show Edit Config menu item.\n" \ + "--allow_service\t\t: 1=Show Service control menu.\n" \ + "--allow_password\t\t: 1=Show Change Password menu item.\n" \ + "--allow_proxy\t\t: 1=Show Proxy Settings menu.\n" \ + "--show_balloon\t\t: 0=Never, 1=At initial connect, 2=At every re-connect.\n" \ + "--service_only\t\t: 1=Enable Service Only mode.\n" \ + "--silent_connection\t\t: 1=Do not show the status dialog while connecting.\n" \ + "--show_script_window\t: 0=Hide Script execution window, 1=Show it.\n" \ + "--passphrase_attempts\t: Number of passphrase attempts to allow.\n" \ + "--connectscript_timeout\t: Time to wait for connect script to finish.\n" \ + "--disconnectscript_timeout\t: Time to wait for disconnect script to finish.\n" \ + "--preconnectscript_timeout\t: Time to wait for preconnect script to finish.\n" + + INFO_USAGECAPTION "OpenVPN GUI Usage" + ERR_BAD_PARAMETER "I'm trying to parse ""%s"" as an --option parameter " \ + "but I don't see a leading '--'" + ERR_BAD_OPTION "Options error: Unrecognized option or missing parameter(s): --%s\n" \ + "Use openvpn-gui --help for more info." + + /* passphrase - Resources */ + ERR_CREATE_PASS_THREAD "CreateThread to show ChangePassphrase dialog failed." + INFO_CHANGE_PWD "Change Password (%s)" + ERR_PWD_DONT_MATCH "The passwords you typed do not match. Try again." + ERR_PWD_TO_SHORT "Your new password must be at least %d characters long." + INFO_EMPTY_PWD "Are you sure you want to set an EMPTY password?" + ERR_UNKNOWN_KEYFILE_FORMAT "Unknown keyfile format." + ERR_OPEN_PRIVATE_KEY_FILE "Error opening private key file (%s)." + ERR_OLD_PWD_INCORRECT "The old password is incorrect." + ERR_OPEN_WRITE_KEY "Error opening private key file for writing (%s)." + ERR_WRITE_NEW_KEY "Error writing new private key file (%s)." + INFO_PWD_CHANGED "Your password has been changed." + ERR_READ_PKCS12 "Error reading PKCS #12 file (%s)." + ERR_CREATE_PKCS12 "Error creating new PKCS #12 object. Change Password has failed." + ERR_OPEN_CONFIG "Could not open config file for reading: (%s)" + ERR_ONLY_ONE_KEY_OPTION "You cannot have more than one ""key"" option in your config." + ERR_ONLY_KEY_OR_PKCS12 "You cannot have both ""key"" and ""pkcs12"" options in your config." + ERR_ONLY_ONE_PKCS12_OPTION "You cannot have more than one ""pkcs12"" option in your config." + ERR_MUST_HAVE_KEY_OR_PKCS12 "Your config file does not contain any ""key"" or ""pkcs12"" option." + ERR_KEY_FILENAME_TO_LONG "Your key filename in the config is too long!" + ERR_PASSPHRASE2STDIN "Error passing passphrase to stdin." + ERR_AUTH_USERNAME2STDIN "Error passing auth username to stdin." + ERR_AUTH_PASSWORD2STDIN "Error passing auth password to stdin." + ERR_CR2STDIN "Error passing CR to stdin." + ERR_INVALID_CHARS_IN_PSW "Your new password contains non-valid characters. " \ + "Please choose another one." + /* proxy */ + ERR_HTTP_PROXY_ADDRESS "You must specify a HTTP proxy address." + ERR_HTTP_PROXY_PORT "You must specify a HTTP proxy port." + ERR_HTTP_PROXY_PORT_RANGE "You must specify a HTTP proxy port between 1-65535" + ERR_SOCKS_PROXY_ADDRESS "You must specify a SOCKS proxy address." + ERR_SOCKS_PROXY_PORT "You must specify a SOCKS proxy port." + ERR_SOCKS_PROXY_PORT_RANGE "You must specify a SOCKS proxy port between 1-65535" + ERR_CREATE_REG_HKCU_KEY "Error creating ""HKEY_CURRENT_USER\\%s"" key." + ERR_GET_TEMP_PATH "Error determining TempPath with GetTempPath(). Using ""C:\\"" instead." + ERR_CREATE_AUTH_FILE "Error creating AUTH file. (%s)" + + /* service */ + ERR_OPEN_SCMGR_ADMIN "OpenSCManager failed. You need Administrator rights to start a service." + ERR_OPEN_VPN_SERVICE "Failed to open ""OpenVPNService""" + ERR_START_SERVICE "Failed to start ""OpenVPNService""" + ERR_QUERY_SERVICE "Failed to query service status." + ERR_SERVICE_START_FAILED "OpenVPN Service failed to start." + ERR_OPEN_SCMGR "OpenSCManager failed (%d)" + ERR_STOP_SERVICE "Failed to stop OpenVPN Service" + INFO_RESTARTED "OpenVPN Service Restarted." + + /* registry */ + ERR_GET_WINDOWS_DIR "Error getting Windows Directory." + ERR_GET_PROGRAM_DIR "Error getting ""Program"" folder name." + ERR_OPEN_REGISTRY "Error opening registry for reading (HKLM\\SOFTWARE\\OpenVPN).\n " \ + "OpenVPN is probably not installed" + ERR_READING_REGISTRY "Error reading registry value (HKLM\\SOFTWARE\\OpenVPN)." + ERR_PASSPHRASE_ATTEMPTS "Registry value ""passphrase_attempts"" must be a number between 1 and 9." + ERR_CONN_SCRIPT_TIMEOUT "Registry value ""connectscript_timeout"" must be a number between 0 and 99." + ERR_DISCONN_SCRIPT_TIMEOUT "Registry value ""disconnectscript_timeout"" must be a number between 1 and 99." + ERR_PRECONN_SCRIPT_TIMEOUT "Registry value ""preconnectscript_timeout"" must be a number between 1 and 99." + ERR_CREATE_REG_KEY "Error creating HKLM\\SOFTWARE\\OpenVPN-GUI key." + ERR_OPEN_WRITE_REG "Failed to open the registry for writing. You need to run this application " \ + "once as Administrator to update the registry." + ERR_READ_SET_KEY "Error reading and setting registry key ""%s""." + ERR_WRITE_REGVALUE "Error writing registry value ""HKEY_CURRENT_USER\\%s\\%s""." +END diff --git a/openvpn-gui-res.h b/openvpn-gui-res.h new file mode 100644 index 0000000..be7b7db --- /dev/null +++ b/openvpn-gui-res.h @@ -0,0 +1,243 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Icons */ +#define APP_ICON 90 +#define APP_ICON_CONNECTED 91 +#define APP_ICON_CONNECTING 92 +#define APP_ICON_DISCONNECTED 93 + +/* About Dialog */ +#define IDD_ABOUTDIALOG 100 +#define ID_TEXT_OPENVPNGUI 101 +#define TEXT_ABOUT_OPENVPNGUI 102 + +/* Ask for Passphrase Dialog */ +#define IDD_PASSPHRASE 150 +#define EDIT_PASSPHRASE 151 + +/* Status Dialog */ +#define IDD_STATUS 160 +#define TEXT_STATUS 161 +#define EDIT_LOG 162 +#define ID_DISCONNECT 163 +#define ID_RESTART 164 +#define ID_HIDE 165 +/* A hidden textbox used to pass the config nr so dialog knows + * which connection to cancel. If anyone knows of another way + * to pass a variable to dialog, please let me know. + */ +#define TEXT_CONFIG 166 + +/* Change Passphrase Dialog */ +#define IDD_CHANGEPSW 170 +#define EDIT_PSW_CURRENT 174 +#define EDIT_PSW_NEW 175 +#define EDIT_PSW_NEW2 176 +#define TEXT_KEYFILE 177 +#define TEXT_KEYFORMAT 178 + +/* Auth Username/Password Dialog */ +#define IDD_AUTH_PASSWORD 180 +#define EDIT_AUTH_USERNAME 181 +#define EDIT_AUTH_PASSWORD 182 + +/* Proxy Settings Dialog */ +#define IDD_PROXY 200 +#define RB_PROXY_USE_OPENVPN 210 +#define RB_PROXY_USE_IE 211 +#define RB_PROXY_USE_MANUAL 212 +#define RB_PROXY_HTTP 213 +#define EDIT_PROXY_HTTP_ADDRESS 214 +#define EDIT_PROXY_HTTP_PORT 215 +#define TEXT_PROXY_HTTP_ADDRESS 216 +#define TEXT_PROXY_HTTP_PORT 217 +#define CHECKB_PROXY_AUTH 218 +#define RB_PROXY_SOCKS 219 +#define EDIT_PROXY_SOCKS_ADDRESS 220 +#define EDIT_PROXY_SOCKS_PORT 221 +#define TEXT_PROXY_SOCKS_ADDRESS 222 +#define TEXT_PROXY_SOCKS_PORT 223 + +/* Proxy Auth Dialog */ +#define IDD_PROXY_AUTH 250 +#define EDIT_PROXY_USERNAME 251 +#define EDIT_PROXY_PASSWORD 252 + +/* Tray - Resources */ +#define MSG_TIP 1001 +#define MSG_TIP_CONNECTED 1002 +#define MSG_TIP_CONNECTING 1003 +#define MSG_TIP_CONNECTED_SINCE 1004 +#define MSG_TIP_ASSIGNED_IP 1005 +#define IDM_TEXT_SERVICE 1006 +#define IDM_TEXT_PROXY 1007 +#define IDM_TEXT_ABOUT 1008 +#define IDM_TEXT_CLOSE 1009 +#define IDM_TEXT_CONNECT 1010 +#define IDM_TEXT_DISCONNECT 1011 +#define IDM_TEXT_STATUS 1012 +#define IDM_TEXT_VIEWLOG 1013 +#define IDM_TEXT_EDITCONFIG 1014 +#define IDM_TEXT_PASSPHRASE 1015 +#define IDM_TEXT_SERVICE_START 1016 +#define IDM_TEXT_SERVICE_STOP 1017 +#define IDM_TEXT_SERVICE_RESTART 1018 +#define IDM_TEXT_SERVICEONLY_START 1019 +#define IDM_TEXT_SERVICEONLY_STOP 1020 +#define IDM_TEXT_SERVICEONLY_RESTART 1021 +#define IDM_TEXT_ASK_STOP_SERVICE 1022 + +/* LogViewer */ +#define ERR_START_LOG_VIEWER 1101 +#define ERR_START_CONF_EDITOR 1102 + +/* OpenVpn */ +#define ERR_TO_MANY_CONFIGS 1201 +#define ERR_CANNOT_CONSTRUCT_LOG 1202 +#define ERR_ONLY_ONE_CONN_OLD_VERSION 1203 +#define ERR_STOP_SERV_ON_OLD_VERSION 1204 +#define ERR_CREATE_EVENT 1205 +#define ERR_UNKNOWN_PRIORITY 1206 +#define ERR_LOG_APPEND_BOOL 1207 +#define ERR_GET_IE_PROXY_SETTINGS 1208 +#define ERR_INIT_SEC_DESC 1209 +#define ERR_SET_SEC_DESC_ACL 1210 +#define ERR_CREATE_PIPE_OUTPUT 1211 +#define ERR_DUP_HANDLE_ERR_WRITE 1212 +#define ERR_CREATE_PIPE_INPUT 1213 +#define ERR_DUP_HANDLE_OUTPUT_READ 1214 +#define ERR_DUP_HANDLE_INPUT_WRITE 1215 +#define ERR_CLOSE_HANDLE_TMP 1216 +#define ERR_CREATE_PROCESS 1217 +#define ERR_CLOSE_HANDLE 1218 +#define ERR_CREATE_THREAD_STATUS 1219 +#define INFO_STATE_WAIT_TERM 1220 +#define ERR_OPEN_LOG_WRITE 1221 +#define INFO_STATE_CONNECTED 1222 +#define INFO_NOW_CONNECTED 1223 +#define INFO_ASSIG_IP 1224 +#define ERR_CERT_EXPIRED 1225 +#define ERR_CERT_NOT_YET_VALID 1226 +#define INFO_STATE_RECONNECTING 1227 +#define INFO_STATE_DISCONNECTED 1228 +#define INFO_CONN_TERMINATED 1229 +#define INFO_STATE_FAILED 1230 +#define INFO_CONN_FAILED 1231 +#define INFO_STATE_FAILED_RECONN 1232 +#define INFO_RECONN_FAILED 1233 +#define INFO_STATE_SUSPENDED 1234 +#define ERR_READ_STDOUT_PIPE 1235 +#define ERR_CREATE_RICHED_LOGWINDOW 1236 +#define ERR_SET_SIZE 1237 +#define ERR_AUTOSTART_CONF_NOT_FOUND 1238 +#define ERR_VERSION_CREATE_EVENT 1239 +#define ERR_CREATE_PIPE_INPUT_READ 1240 +#define INFO_STATE_CONNECTING 1241 +#define INFO_CONNECTION_XXX 1242 +#define ERR_CREATE_THREAD_READ_STDOUT 1243 +#define INFO_STATE_CONN_SCRIPT 1244 +#define INFO_STATE_DISCONN_SCRIPT 1245 +#define ERR_RUN_CONN_SCRIPT 1246 +#define ERR_GET_EXIT_CODE 1247 +#define ERR_CONN_SCRIPT_FAILED 1248 +#define ERR_RUN_CONN_SCRIPT_TIMEOUT 1249 +#define ERR_OPTION_LOG_IN_CONFIG 1250 +#define ERR_CONFIG_ALREADY_EXIST 1251 + +/* main */ +#define ERR_OPEN_DEBUG_FILE 1301 +#define ERR_LOAD_RICHED20 1302 +#define ERR_SHELL_DLL_VERSION 1303 +#define ERR_GUI_ALREADY_RUNNING 1304 +#define INFO_SERVICE_STARTED 1305 +#define INFO_SERVICE_STOPPED 1306 +#define INFO_ACTIVE_CONN_EXIT 1307 +#define INFO_SERVICE_ACTIVE_EXIT 1308 + +/* options */ +#define INFO_USAGE 1401 +#define INFO_USAGECAPTION 1402 +#define ERR_BAD_PARAMETER 1403 +#define ERR_BAD_OPTION 1404 + +/* passphrase */ +#define ERR_CREATE_PASS_THREAD 1501 +#define INFO_CHANGE_PWD 1502 +#define ERR_PWD_DONT_MATCH 1503 +#define ERR_PWD_TO_SHORT 1504 +#define INFO_EMPTY_PWD 1505 +#define ERR_UNKNOWN_KEYFILE_FORMAT 1506 +#define ERR_OPEN_PRIVATE_KEY_FILE 1507 +#define ERR_OLD_PWD_INCORRECT 1508 +#define ERR_OPEN_WRITE_KEY 1509 +#define ERR_WRITE_NEW_KEY 1510 +#define INFO_PWD_CHANGED 1511 +#define ERR_READ_PKCS12 1512 +#define ERR_CREATE_PKCS12 1513 +#define ERR_OPEN_CONFIG 1514 +#define ERR_ONLY_ONE_KEY_OPTION 1515 +#define ERR_ONLY_KEY_OR_PKCS12 1516 +#define ERR_ONLY_ONE_PKCS12_OPTION 1517 +#define ERR_MUST_HAVE_KEY_OR_PKCS12 1518 +#define ERR_KEY_FILENAME_TO_LONG 1519 +#define ERR_PASSPHRASE2STDIN 1520 +#define ERR_CR2STDIN 1521 +#define ERR_AUTH_USERNAME2STDIN 1522 +#define ERR_AUTH_PASSWORD2STDIN 1523 +#define ERR_INVALID_CHARS_IN_PSW 1524 + + +/* proxy */ +#define ERR_HTTP_PROXY_ADDRESS 1601 +#define ERR_HTTP_PROXY_PORT 1602 +#define ERR_HTTP_PROXY_PORT_RANGE 1603 +#define ERR_SOCKS_PROXY_ADDRESS 1604 +#define ERR_SOCKS_PROXY_PORT 1605 +#define ERR_SOCKS_PROXY_PORT_RANGE 1606 +#define ERR_CREATE_REG_HKCU_KEY 1607 +#define ERR_GET_TEMP_PATH 1608 +#define ERR_CREATE_AUTH_FILE 1609 + +/* service */ +#define ERR_OPEN_SCMGR_ADMIN 1701 +#define ERR_OPEN_VPN_SERVICE 1702 +#define ERR_START_SERVICE 1703 +#define ERR_QUERY_SERVICE 1704 +#define ERR_SERVICE_START_FAILED 1705 +#define ERR_OPEN_SCMGR 1706 +#define ERR_STOP_SERVICE 1707 +#define INFO_RESTARTED 1708 + +/* registry */ +#define ERR_GET_WINDOWS_DIR 1801 +#define ERR_GET_PROGRAM_DIR 1802 +#define ERR_OPEN_REGISTRY 1803 +#define ERR_READING_REGISTRY 1804 +#define ERR_PASSPHRASE_ATTEMPTS 1805 +#define ERR_CONN_SCRIPT_TIMEOUT 1806 +#define ERR_DISCONN_SCRIPT_TIMEOUT 1807 +#define ERR_PRECONN_SCRIPT_TIMEOUT 1808 +#define ERR_CREATE_REG_KEY 1809 +#define ERR_OPEN_WRITE_REG 1810 +#define ERR_READ_SET_KEY 1811 +#define ERR_WRITE_REGVALUE 1812 + diff --git a/openvpn-gui.ico b/openvpn-gui.ico new file mode 100644 index 0000000000000000000000000000000000000000..1dfae196293709f5a545db4435469681ef41a5ab GIT binary patch literal 3262 zcmds)YfO_@7{~v*7&n+#T!XAbMzEj~Z4e3~^TH4j5Cn+`g1jKsN=qT-rqv)Sb5J|( z^n#T!R6s0vHeOY3{P7AHLNLFUD4?F!o?|a_UH^1|o z^E`P@USI+F+1Y_ytx@wKKm*`Jj0|B1G5xqXO(K)?k_B;WPDIq<*@}&4A5Tmwk;qJt z1d3V(tOS+;%Z(y^4n>*XncdN-R2rr7hD;{O&MwT%5(|a1m72hfiaaDp=j0TppUdKA z@~H?PrmGFSmtY?d3uv$GjGV)ZXdp0)qWMt&=;GnL*f3&xEpslT=uC7&~Xcmbg%XZ;9P-{>z za2ngUArm+YWCJ3gfbiX6&&LW+U@@q8%EZ^Tw~xPkIWa!|^Tfo9v9ZyI4|RQgy3Wo) zm8z?%>XI~zpA#8;-H&Q+z}7RNhYSm$#)F!q-urq%;Du~Lk+ z92B`?3aHtD&;wXUHoMfYj4a>+@RcFt%Vzd}K&^h%(ebRWZ(?NR`OuJVaB!r(eORd+ zP$+ux^71e6L(c^57kh`vJoe?$1J5HVN)PX{(eqo^;KViroVT*=Vk}cy&BU7oCeV<$ zWRHO9{OMOJ$21zV$w82XqsLiKo|e`M zsL}x_*`ez*2+vK*P1F3em+D zk?28g?rim@rFF)}*0Yb5aue^dSSFumcU}U$z!=?Wa!W{sg4#Qk#L#&_4a5PK_~H9n zq6TSxd1~s7lvH&}%4{_sKYlAFrt&Degv;wT@CQG_we=`tBF`P2bp0xR16}~bOILN% zovI?;&da>LD?inzaTKrwovLD@TcQ(+=;*m5jgK$la=Q$C0uR^^R|=o-^-~c3E8tI{ z2lyILuC}=CvMP#Wfy;*dSvJEL31WjbZk$VjE-rgmth8;LD}9;q)N015g*Ng9OH~L< zM;QxJSCqIwz82-ysIy+wy4vET>mpVV0uJf(f7<^ehe)vhq1pQ~eZ-W#%mr88!@xq~ z`o}7;cyQrhQ#{!IxV#DV*3bYFfJd%|T53MuXD2J?9PeOhz`E-7o1$0w~c}I#vj{HaKHPD`q&?8tUhK`QK!6GP1*S*&MfZ(}nO*0{_-f|L4nZ=5kGGR*;&UEzZsmWhCU16NSgiOpHrplY>v3N6v(q zHebFtEXP8bc&FtKU?30PoiLS?T!0%bczyq|1*A(NVenSUCIQxBOOU{lV`8nVHx!=F#!W1dkP2s3o3H;B zLSdTlblGKcI-1q)wl>WxyP7VF3B0cUrdf1SUEA8`m0g_*g_-2(*WR7~>jKRh4f#aS k8(|u48c(id++?P~>5lPT<9#t1p3|l@So}9zL!Q_C1=~KqK>z>% literal 0 HcmV?d00001 diff --git a/openvpn.c b/openvpn.c new file mode 100644 index 0000000..46b959f --- /dev/null +++ b/openvpn.c @@ -0,0 +1,974 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Parts of this sourcefile is taken from openvpnserv.c from the + * OpenVPN source, with approval from the author, James Yonan + * . + */ + + +#include +#include +#include +#include +#include "tray.h" +#include "main.h" +#include "openvpn.h" +#include "openvpn_monitor_process.h" +#include "openvpn-gui-res.h" +#include "options.h" +#include "scripts.h" +#include "viewlog.h" +#include "proxy.h" +#include "passphrase.h" +#include + +extern struct options o; + +/* + * Creates a unique exit_event name based on the + * config file number. + */ +int CreateExitEvent(int config) +{ + o.cnn[config].exit_event = NULL; + if (o.oldversion == 1) + { + mysnprintf(o.cnn[config].exit_event_name, "openvpn_exit"); + o.cnn[config].exit_event = CreateEvent (NULL, + TRUE, + FALSE, + o.cnn[config].exit_event_name); + if (o.cnn[config].exit_event == NULL) + { + if (GetLastError() == ERROR_ACCESS_DENIED) + { + /* service mustn't be running, while using old version */ + ShowLocalizedMsg(GUI_NAME, ERR_STOP_SERV_ON_OLD_VERSION, ""); + } + else + { + /* error creating exit event */ + ShowLocalizedMsg (GUI_NAME, ERR_CREATE_EVENT, o.cnn[config].exit_event_name); + } + return(false); + } + } + else + { + mysnprintf(o.cnn[config].exit_event_name, "openvpngui_exit_event_%d",config); + o.cnn[config].exit_event = CreateEvent (NULL, + TRUE, + FALSE, + o.cnn[config].exit_event_name); + if (o.cnn[config].exit_event == NULL) + { + /* error creating exit event */ + ShowLocalizedMsg (GUI_NAME, ERR_CREATE_EVENT, o.cnn[config].exit_event_name); + return(false); + } + } + + return(true); +} + + +/* + * Set priority based on the registry or cmd-line value + */ +int SetProcessPriority(DWORD *priority) +{ + + /* set process priority */ + *priority = NORMAL_PRIORITY_CLASS; + if (!strcmp (o.priority_string, "IDLE_PRIORITY_CLASS")) + *priority = IDLE_PRIORITY_CLASS; + else if (!strcmp (o.priority_string, "BELOW_NORMAL_PRIORITY_CLASS")) + *priority = BELOW_NORMAL_PRIORITY_CLASS; + else if (!strcmp (o.priority_string, "NORMAL_PRIORITY_CLASS")) + *priority = NORMAL_PRIORITY_CLASS; + else if (!strcmp (o.priority_string, "ABOVE_NORMAL_PRIORITY_CLASS")) + *priority = ABOVE_NORMAL_PRIORITY_CLASS; + else if (!strcmp (o.priority_string, "HIGH_PRIORITY_CLASS")) + *priority = HIGH_PRIORITY_CLASS; + else + { + /* unknown priority */ + ShowLocalizedMsg (GUI_NAME, ERR_UNKNOWN_PRIORITY, o.priority_string); + return (false); + } + + return(true); +} + + +/* + * Launch an OpenVPN process + */ +int StartOpenVPN(int config) +{ + + HANDLE hOutputReadTmp = NULL; + HANDLE hOutputRead = NULL; + HANDLE hOutputWrite = NULL; + HANDLE hInputWriteTmp = NULL; + HANDLE hInputRead = NULL; + HANDLE hInputWrite = NULL; + HANDLE hErrorWrite = NULL; + + HANDLE hThread; + DWORD IDThread; + DWORD priority; + STARTUPINFO start_info; + PROCESS_INFORMATION proc_info; + SECURITY_ATTRIBUTES sa; + SECURITY_DESCRIPTOR sd; + char command_line[256]; + char proxy_string[100]; + char msg[200]; + int i, is_connected=0; + + extern HINSTANCE hInstance; + + CLEAR (start_info); + CLEAR (proc_info); + CLEAR (sa); + CLEAR (sd); + + + /* If oldversion, allow only ONE connection */ + if (o.oldversion == 1) + { + for (i=0; i < o.num_configs; i++) + { + if ((o.cnn[i].connect_status != DISCONNECTED) && + (o.cnn[i].connect_status != DISCONNECTING)) + { + is_connected=1; + break; + } + } + if (is_connected) + { + /* only one simultanious connection on old version */ + ShowLocalizedMsg(GUI_NAME, ERR_ONLY_ONE_CONN_OLD_VERSION, ""); + return(false); + } + } + + /* Warn if "log" or "log-append" option is found in config file */ + if ((ConfigFileOptionExist(config, "log ")) || + (ConfigFileOptionExist(config, "log-append "))) + { + TCHAR buf[1000]; + myLoadString(ERR_OPTION_LOG_IN_CONFIG); + if (MessageBox(NULL, buf, GUI_NAME, MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING) != IDYES) + return(false); + } + + /* Clear connection unique vars */ + o.cnn[config].failed_psw = 0; + CLEAR (o.cnn[config].ip); + + /* Create our exit event */ + if (!CreateExitEvent(config)) + return(false); + + /* set process priority */ + if (!SetProcessPriority(&priority)) + goto failed; + + /* Check that log append flag has a valid value */ + if ((o.append_string[0] != '0') && (o.append_string[0] != '1')) + { + /* append_log must be 0 or 1 */ + ShowLocalizedMsg (GUI_NAME, ERR_LOG_APPEND_BOOL, o.append_string); + goto failed; + } + + /* construct proxy string to append to command line */ + ConstructProxyCmdLine(proxy_string, sizeof(proxy_string)); + + /* construct command line */ + if (o.oldversion == 1) + { + mysnprintf (command_line, "openvpn --config \"%s\" %s", + o.cnn[config].config_file, proxy_string); + } + else + { + mysnprintf (command_line, "openvpn --service %s 0 --config \"%s\" %s", + o.cnn[config].exit_event_name, + o.cnn[config].config_file, + proxy_string); + } + + + /* Make security attributes struct for logfile handle so it can + be inherited. */ + sa.nLength = sizeof (sa); + sa.lpSecurityDescriptor = &sd; + sa.bInheritHandle = TRUE; + if (!InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION)) + { + /* Init Sec. Desc. failed */ + ShowLocalizedMsg (GUI_NAME, ERR_INIT_SEC_DESC, ""); + goto failed; + } + if (!SetSecurityDescriptorDacl (&sd, TRUE, NULL, FALSE)) + { + /* set Dacl failed */ + ShowLocalizedMsg (GUI_NAME, ERR_SET_SEC_DESC_ACL, ""); + goto failed; + } + + + /* Create the child output pipe. */ + if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0)) + { + /* CreatePipe failed. */ + ShowLocalizedMsg(GUI_NAME, ERR_CREATE_PIPE_OUTPUT, ""); + goto failed; + } + + // Create a duplicate of the output write handle for the std error + // write handle. This is necessary in case the child application + // closes one of its std output handles. + if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite, + GetCurrentProcess(),&hErrorWrite,0, + TRUE,DUPLICATE_SAME_ACCESS)) + { + /* DuplicateHandle failed. */ + ShowLocalizedMsg(GUI_NAME, ERR_DUP_HANDLE_ERR_WRITE, ""); + goto failed; + } + + // Create the child input pipe. + if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0)) + { + /* CreatePipe failed. */ + ShowLocalizedMsg(GUI_NAME, ERR_CREATE_PIPE_INPUT, ""); + goto failed; + } + + // Create new output read handle and the input write handles. Set + // the Properties to FALSE. Otherwise, the child inherits the + // properties and, as a result, non-closeable handles to the pipes + // are created. + if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp, + GetCurrentProcess(), + &hOutputRead, // Address of new handle. + 0,FALSE, // Make it uninheritable. + DUPLICATE_SAME_ACCESS)) + { + /* Duplicate Handle failed. */ + ShowLocalizedMsg(GUI_NAME, ERR_DUP_HANDLE_OUTPUT_READ, ""); + goto failed; + } + + if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp, + GetCurrentProcess(), + &hInputWrite, // Address of new handle. + 0,FALSE, // Make it uninheritable. + DUPLICATE_SAME_ACCESS)) + { + /* DuplicateHandle failed */ + ShowLocalizedMsg(GUI_NAME, ERR_DUP_HANDLE_INPUT_WRITE, ""); + goto failed; + } + + /* Close inheritable copies of the handles */ + if (!CloseHandle(hOutputReadTmp) || !CloseHandle(hInputWriteTmp)) + { + /* Close Handle failed */ + ShowLocalizedMsg(GUI_NAME, ERR_CLOSE_HANDLE_TMP, ""); + CloseHandle (o.cnn[config].exit_event); + return(0); + } + hOutputReadTmp=NULL; + hInputWriteTmp=NULL; + + /* fill in STARTUPINFO struct */ + GetStartupInfo(&start_info); + start_info.cb = sizeof(start_info); + start_info.dwFlags = STARTF_USESTDHANDLES; + start_info.hStdInput = hInputRead; + start_info.hStdOutput = hOutputWrite; + start_info.hStdError = hErrorWrite; + + /* Run Pre-connect script */ + RunPreconnectScript(config); + + /* create an OpenVPN process for one config file */ + if (!CreateProcess(o.exe_path, + command_line, + NULL, + NULL, + TRUE, + priority | CREATE_NO_WINDOW, + NULL, + o.cnn[config].config_dir, + &start_info, + &proc_info)) + { + /* CreateProcess failed */ + ShowLocalizedMsg (GUI_NAME, ERR_CREATE_PROCESS, + o.exe_path, + command_line, + o.cnn[config].config_dir); + goto failed; + } + + + /* close unneeded handles */ + Sleep (250); /* try to prevent race if we close logfile + handle before child process DUPs it */ + + if(!CloseHandle (proc_info.hThread) || + !CloseHandle (hOutputWrite) || + !CloseHandle (hInputRead) || + !CloseHandle (hErrorWrite)) + { + /* CloseHandle failed */ + ShowLocalizedMsg (GUI_NAME, ERR_CLOSE_HANDLE, ""); + CloseHandle (o.cnn[config].exit_event); + return(false); + } + hOutputWrite = NULL; + hInputRead = NULL; + hErrorWrite = NULL; + + /* Save StdIn and StdOut handles in our options struct */ + o.cnn[config].hStdIn = hInputWrite; + o.cnn[config].hStdOut = hOutputRead; + + /* Save Process Handle */ + o.cnn[config].hProcess=proc_info.hProcess; + + + /* Start Thread to show Status Dialog */ + hThread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) ThreadOpenVPNStatus, + (int *) config, // pass config nr + 0, &IDThread); + if (hThread == NULL) + { + /* CreateThread failed */ + ShowLocalizedMsg (GUI_NAME, ERR_CREATE_THREAD_STATUS, ""); + goto failed; + } + + + return(true); + +failed: + if (o.cnn[config].exit_event) CloseHandle (o.cnn[config].exit_event); + if (hOutputWrite) CloseHandle (hOutputWrite); + if (hOutputRead) CloseHandle (hOutputRead); + if (hInputWrite) CloseHandle (hInputWrite); + if (hInputRead) CloseHandle (hInputRead); + if (hErrorWrite) CloseHandle (hOutputWrite); + return(false); + +} + + +void StopOpenVPN(int config) +{ + int i; + TCHAR buf[1000]; + + o.cnn[config].connect_status = DISCONNECTING; + + if (o.cnn[config].exit_event) { + /* Run Disconnect script */ + RunDisconnectScript(config, false); + + EnableWindow(GetDlgItem(o.cnn[config].hwndStatus, ID_DISCONNECT), FALSE); + EnableWindow(GetDlgItem(o.cnn[config].hwndStatus, ID_RESTART), FALSE); + SetMenuStatus(config, DISCONNECTING); + myLoadString(INFO_STATE_WAIT_TERM); + /* UserInfo: waiting for OpenVPN termination... */ + SetDlgItemText(o.cnn[config].hwndStatus, TEXT_STATUS, buf); + SetEvent(o.cnn[config].exit_event); + } +} + +void SuspendOpenVPN(int config) +{ + int i; + TCHAR buf[1000]; + + o.cnn[config].connect_status = SUSPENDING; + o.cnn[config].restart = true; + + if (o.cnn[config].exit_event) { + EnableWindow(GetDlgItem(o.cnn[config].hwndStatus, ID_DISCONNECT), FALSE); + EnableWindow(GetDlgItem(o.cnn[config].hwndStatus, ID_RESTART), FALSE); + SetMenuStatus(config, DISCONNECTING); + myLoadString(INFO_STATE_WAIT_TERM); + SetDlgItemText(o.cnn[config].hwndStatus, TEXT_STATUS, buf); + SetEvent(o.cnn[config].exit_event); + } +} + + +void StopAllOpenVPN() +{ + int i; + + for(i=0; i < o.num_configs; i++) { + if(o.cnn[i].connect_status != DISCONNECTED) + StopOpenVPN(i); + } + + /* Wait for all connections to terminate (Max 5 sec) */ + for (i=0; i<20; i++, Sleep(250)) + if (CountConnectedState(DISCONNECTED) == o.num_configs) break; + +} + + +BOOL CALLBACK StatusDialogFunc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + BOOL Translated; + HWND hwndLogWindow; + RECT rect; + CHARFORMAT charformat; + HICON hIcon; + int config; + + switch (msg) { + + case WM_INITDIALOG: + /* Set Window Icon "DisConnected" */ + SetStatusWinIcon(hwndDlg, APP_ICON_CONNECTING); + + /* Create LogWindow */ + hwndLogWindow = CreateWindowEx (0, RICHEDIT_CLASS, NULL, + WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | \ + ES_SUNKEN | ES_LEFT | ES_MULTILINE | \ + ES_READONLY | ES_AUTOHSCROLL | ES_AUTOVSCROLL, + 20, 25, 350, 160, // Posision and Size + hwndDlg, // Parent window handle + (HMENU) EDIT_LOG, // hMenu + o.hInstance, // hInstance + NULL); // WM_CREATE lpParam + + + if (!hwndLogWindow) + { + /* Create RichEd LogWindow Failed */ + ShowLocalizedMsg(GUI_NAME, ERR_CREATE_RICHED_LOGWINDOW, ""); + return FALSE; + } + + /* Set font and fontsize of the LogWindow */ + charformat.cbSize = sizeof(CHARFORMAT); + charformat.dwMask = CFM_SIZE | CFM_FACE | CFM_BOLD | CFM_ITALIC | \ + CFM_UNDERLINE | CFM_STRIKEOUT | CFM_PROTECTED; + charformat.dwEffects = 0; + charformat.yHeight = 100; + strcpy(charformat.szFaceName, "MS Sans Serif"); + if ((SendMessage(hwndLogWindow, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &charformat) && CFM_SIZE) == 0) { + /* set size failed */ + ShowLocalizedMsg(GUI_NAME, ERR_SET_SIZE, ""); + } + + /* Set Size and Posision of controls */ + GetClientRect(hwndDlg, &rect); + MoveWindow (hwndLogWindow, 20, 25, rect.right - 40, rect.bottom - 70, TRUE); + MoveWindow (GetDlgItem(hwndDlg, TEXT_STATUS), 20, 5, rect.right - 25, 15, TRUE); + MoveWindow (GetDlgItem(hwndDlg, ID_DISCONNECT), 20, rect.bottom - 30, 90, 23, TRUE); + MoveWindow (GetDlgItem(hwndDlg, ID_RESTART), 125, rect.bottom - 30, 90, 23, TRUE); + MoveWindow (GetDlgItem(hwndDlg, ID_HIDE), rect.right - 110, rect.bottom - 30, 90, 23, TRUE); + + /* Set focus on the LogWindow so it scrolls automatically */ + SetFocus(hwndLogWindow); + + return FALSE; + + case WM_SIZE: + MoveWindow (GetDlgItem(hwndDlg, EDIT_LOG), 20, 25, LOWORD (lParam) - 40, + HIWORD (lParam) - 70, TRUE); + MoveWindow (GetDlgItem(hwndDlg, ID_DISCONNECT), 20, + HIWORD (lParam) - 30, 90, 23, TRUE); + MoveWindow (GetDlgItem(hwndDlg, ID_RESTART), 125, + HIWORD (lParam) - 30, 90, 23, TRUE); + MoveWindow (GetDlgItem(hwndDlg, ID_HIDE), LOWORD (lParam) - 110, + HIWORD (lParam) - 30, 90, 23, TRUE); + MoveWindow (GetDlgItem(hwndDlg, TEXT_STATUS), 20, 5, LOWORD (lParam) - 25, 15, TRUE); + InvalidateRect(hwndDlg, NULL, TRUE); + return TRUE; + + case WM_COMMAND: + config=GetDlgItemInt(hwndDlg, TEXT_CONFIG, &Translated, FALSE); + switch (LOWORD(wParam)) { + + case ID_DISCONNECT: + SetFocus(GetDlgItem(o.cnn[config].hwndStatus, EDIT_LOG)); + StopOpenVPN(config); + return TRUE; + + case ID_HIDE: + if (o.cnn[GetDlgItemInt(hwndDlg, TEXT_CONFIG, &Translated, FALSE)].connect_status != DISCONNECTED) + { + ShowWindow(hwndDlg, SW_HIDE); + } + else + { + DestroyWindow(hwndDlg); + } + return TRUE; + case ID_RESTART: + SetFocus(GetDlgItem(o.cnn[config].hwndStatus, EDIT_LOG)); + o.cnn[config].restart = true; + StopOpenVPN(config); + return TRUE; + } + break; + + case WM_SHOWWINDOW: + if (wParam == TRUE) + { + config=GetDlgItemInt(hwndDlg, TEXT_CONFIG, &Translated, FALSE); + if (o.cnn[config].hwndStatus) + SetFocus(GetDlgItem(o.cnn[config].hwndStatus, EDIT_LOG)); + } + return FALSE; + + case WM_CLOSE: + if (o.cnn[GetDlgItemInt(hwndDlg, TEXT_CONFIG, &Translated, FALSE)].connect_status != DISCONNECTED) + { + ShowWindow(hwndDlg, SW_HIDE); + } + else + { + DestroyWindow(hwndDlg); + } + return TRUE; + + case WM_DESTROY: + PostQuitMessage(0); + break; + } + return FALSE; +} + +void SetStatusWinIcon(HWND hwndDlg, int IconID) +{ + HICON hIcon; + + /* Set Window Icon */ + hIcon = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IconID), + IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR); + if (hIcon) { + SendMessage(hwndDlg, WM_SETICON, (WPARAM) (ICON_SMALL), (LPARAM) (hIcon)); + SendMessage(hwndDlg, WM_SETICON, (WPARAM) (ICON_BIG), (LPARAM) (hIcon)); + } +} + +int AutoStartConnections() +{ + int i; + + for (i=0; i < o.num_configs; i++) + { + if (o.cnn[i].auto_connect) + StartOpenVPN(i); + } + + return(true); +} + +int VerifyAutoConnections() +{ + int i,j; + BOOL match; + + for (i=0; (o.auto_connect[i] != 0) && (i < MAX_CONFIGS); i++) + { + match = false; + for (j=0; j < MAX_CONFIGS; j++) + { + if (strcasecmp(o.cnn[j].config_file, o.auto_connect[i]) == 0) + { + match=true; + break; + } + } + if (match == false) + { + /* autostart config not found */ + ShowLocalizedMsg(GUI_NAME, ERR_AUTOSTART_CONF_NOT_FOUND, o.auto_connect[i]); + return false; + } + } + + return true; +} + + +int CheckVersion() +{ + HANDLE hOutputReadTmp = NULL; + HANDLE hOutputRead = NULL; + HANDLE hOutputWrite = NULL; + HANDLE hInputWriteTmp = NULL; + HANDLE hInputRead = NULL; + HANDLE hInputWrite = NULL; + HANDLE exit_event; + HANDLE debug_event; + + STARTUPINFO start_info; + PROCESS_INFORMATION proc_info; + SECURITY_ATTRIBUTES sa; + SECURITY_DESCRIPTOR sd; + char command_line[256]; + char line[1024]; + char bin_path[MAX_PATH]; + char *p; + int oldversion, i; + + CLEAR (start_info); + CLEAR (proc_info); + CLEAR (sa); + CLEAR (sd); + + exit_event = CreateEvent (NULL, TRUE, FALSE, "openvpn_exit"); + if (exit_event == NULL) + { +#ifdef DEBUG + PrintErrorDebug("CreateEvent(openvpn_exit) failed."); +#endif + if (GetLastError() == ERROR_ACCESS_DENIED) + { + /* Assume we're running OpenVPN 1.5/1.6 and the service is started. */ + o.oldversion=1; + strncpy(o.connect_string, "Successful ARP Flush", sizeof(o.connect_string)); + return(true); + } + else + { + /* CreateEvent failed */ + ShowLocalizedMsg(GUI_NAME, ERR_VERSION_CREATE_EVENT, ""); + return(false); + } + } + +#ifdef DEBUG + PrintErrorDebug("CreateEvent(openvpn_exit) succeded."); +#endif + + /* construct command line */ + mysnprintf (command_line, "openvpn --version"); + + /* construct bin path */ + strncpy(bin_path, o.exe_path, sizeof(bin_path)); + for (i=strlen(bin_path) - 1; i > 0; i--) + if (bin_path[i] == '\\') break; + bin_path[i] = '\0'; + + /* Make security attributes struct for logfile handle so it can + be inherited. */ + sa.nLength = sizeof (sa); + sa.lpSecurityDescriptor = &sd; + sa.bInheritHandle = TRUE; + if (!InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION)) + { + /* Init Sec. Desc. failed */ + ShowLocalizedMsg (GUI_NAME, ERR_INIT_SEC_DESC, ""); + return(0); + } + if (!SetSecurityDescriptorDacl (&sd, TRUE, NULL, FALSE)) + { + /* Set Dacl failed */ + ShowLocalizedMsg (GUI_NAME, ERR_SET_SEC_DESC_ACL, ""); + return(0); + } + + /* Create the child input pipe. */ + if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0)) + { + /* create pipe failed */ + ShowLocalizedMsg(GUI_NAME, ERR_CREATE_PIPE_INPUT_READ, ""); + return(0); + } + + /* Create the child output pipe. */ + if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0)) + { + /* CreatePipe failed */ + ShowLocalizedMsg(GUI_NAME, ERR_CREATE_PIPE_OUTPUT, ""); + return(0); + } + + if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp, + GetCurrentProcess(), + &hOutputRead, // Address of new handle. + 0,FALSE, // Make it uninheritable. + DUPLICATE_SAME_ACCESS)) + { + /* DuplicateHandle failed */ + ShowLocalizedMsg(GUI_NAME, ERR_DUP_HANDLE_OUTPUT_READ, ""); + return(0); + } + + if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp, + GetCurrentProcess(), + &hInputWrite, // Address of new handle. + 0,FALSE, // Make it uninheritable. + DUPLICATE_SAME_ACCESS)) + { + /* DuplicateHandle failed */ + ShowLocalizedMsg(GUI_NAME, ERR_DUP_HANDLE_INPUT_WRITE, ""); + return(0); + } + + + /* Close inheritable copies of the handles */ + if (!CloseHandle(hOutputReadTmp) || !CloseHandle(hInputWriteTmp)) + { + /* CloseHandle failed */ + ShowLocalizedMsg(GUI_NAME, ERR_CLOSE_HANDLE_TMP, ""); + return(0); + } + + /* fill in STARTUPINFO struct */ + GetStartupInfo(&start_info); + start_info.cb = sizeof(start_info); + start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; + start_info.wShowWindow = SW_HIDE; + start_info.hStdInput = hInputRead; + start_info.hStdOutput = hOutputWrite; + start_info.hStdError = hOutputWrite; + + /* Start OpenVPN to check version */ + if (!CreateProcess(o.exe_path, + command_line, + NULL, + NULL, + TRUE, + CREATE_NEW_CONSOLE, + NULL, + bin_path, + &start_info, + &proc_info)) + { + /* CreateProcess failed */ + ShowLocalizedMsg (GUI_NAME, ERR_CREATE_PROCESS, + o.exe_path, + command_line, + bin_path); + return(0); + } + + /* Default value for oldversion */ + oldversion=0; + + /* Default string to look for to report "Connected". */ + strncpy(o.connect_string, "Successful ARP Flush", sizeof(o.connect_string)); + + if (ReadLineFromStdOut(hOutputRead, 0, line) == 1) + { +#ifdef DEBUG + PrintDebug("VersionString: %s", line); +#endif + if (line[8] == '2') /* Majorversion = 2 */ + { + if (line[10] == '0') /* Minorversion = 0 */ + { + p=strstr(line, "beta"); + if (p != NULL) + { + if (p[5] == ' ') /* 2.0-beta1 - 2.0-beta9 */ + { + if (p[4] >= '6') /* 2.0-beta6 - 2.0-beta9 */ + { + oldversion=0; + } + else /* < 2.0-beta6 */ + { + oldversion=1; + } + } + else /* >= 2.0-beta10 */ + { + if (strncmp(&p[6], "ms", 2) == 0) /* 2.0-betaXXms */ + strncpy(o.connect_string, "Initialization Sequence Completed", + sizeof(o.connect_string)); + if ( !((p[4] == 1) && (p[5] == 0)) ) /* >= 2.0-beta11 */ + strncpy(o.connect_string, "Initialization Sequence Completed", + sizeof(o.connect_string)); + + oldversion=0; + } + } + else /* 2.0 non-beta */ + { + strncpy(o.connect_string, "Initialization Sequence Completed", + sizeof(o.connect_string)); + oldversion=0; + } + } + else /* > 2.0 */ + { + strncpy(o.connect_string, "Initialization Sequence Completed", + sizeof(o.connect_string)); + oldversion=0; + } + } + else + { + if (line[8] == '1') /* Majorversion = 1 */ + { + oldversion=1; + } + else /* Majorversion != (1 || 2) */ + { + oldversion=0; + } + } + } + else return(0); + + o.oldversion = oldversion; + + + if(!CloseHandle (proc_info.hThread) || !CloseHandle (hOutputWrite) + || !CloseHandle (hInputRead) || !CloseHandle(exit_event)) + { + /* CloseHandle failed */ + ShowLocalizedMsg (GUI_NAME, ERR_CLOSE_HANDLE, ""); + return(0); + } + + return(1); +} + +/* Return num of connections with Status = CheckVal */ +int CountConnectedState(int CheckVal) +{ + int i; + int count=0; + + for (i=0; i < o.num_configs; i++) + { + if (o.cnn[i].connect_status == CheckVal) + count++; + } + + return (count); +} + +void CheckAndSetTrayIcon() +{ + + /* Show green icon if service is running */ + if (o.service_running == SERVICE_CONNECTED) + { + SetTrayIcon(CONNECTED); + return; + } + + /* Change tray icon if no more connections is running */ + if (CountConnectedState(CONNECTED) != 0) + SetTrayIcon(CONNECTED); + else + { + if ((CountConnectedState(CONNECTING) != 0) || + (CountConnectedState(RECONNECTING) != 0) || + (o.service_running == SERVICE_CONNECTING)) + SetTrayIcon(CONNECTING); + else + SetTrayIcon(DISCONNECTED); + } +} + +void ThreadOpenVPNStatus(int config) +{ + char conn_name[200]; + HANDLE hThread; + DWORD IDThread; + char msg[200]; + MSG messages; + + /* Cut of extention from config filename. */ + strncpy(conn_name, o.cnn[config].config_file, sizeof(conn_name)); + conn_name[strlen(conn_name) - (strlen(o.ext_string)+1)]=0; + + if (o.cnn[config].restart) + { + /* UserInfo: Connecting */ + TCHAR buf[1000]; + myLoadString(INFO_STATE_CONNECTING); + SetDlgItemText(o.cnn[config].hwndStatus, TEXT_STATUS, buf); + SetStatusWinIcon(o.cnn[config].hwndStatus, APP_ICON_CONNECTING); + EnableWindow(GetDlgItem(o.cnn[config].hwndStatus, ID_DISCONNECT), TRUE); + EnableWindow(GetDlgItem(o.cnn[config].hwndStatus, ID_RESTART), TRUE); + SetFocus(GetDlgItem(o.cnn[config].hwndStatus, EDIT_LOG)); + o.cnn[config].restart = false; + } + else + { + /* Create and Show Status Dialog */ + TCHAR buf[1000]; + if (!(o.cnn[config].hwndStatus = CreateDialog (o.hInstance, + MAKEINTRESOURCE (IDD_STATUS), + NULL, (DLGPROC) StatusDialogFunc))) + ExitThread(1); + /* UserInfo: Connecting */ + myLoadString(INFO_STATE_CONNECTING); + SetDlgItemText(o.cnn[config].hwndStatus, TEXT_STATUS, (LPCTSTR)buf); + SetDlgItemInt(o.cnn[config].hwndStatus, TEXT_CONFIG, (UINT)config, FALSE); + myLoadString(INFO_CONNECTION_XXX); + mysnprintf(msg, buf, conn_name); + SetWindowText(o.cnn[config].hwndStatus, msg); + + if (o.silent_connection[0]=='0') + ShowWindow(o.cnn[config].hwndStatus, SW_SHOW); + } + + + /* Start Thread to monitor our OpenVPN process */ + hThread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) WatchOpenVPNProcess, + (int *) config, // pass config nr + 0, &IDThread); + if (hThread == NULL) + { + /* CreateThread failed */ + ShowLocalizedMsg (GUI_NAME, ERR_CREATE_THREAD_READ_STDOUT, ""); + ExitThread(0); + } + + /* Run the message loop. It will run until GetMessage() returns 0 */ + while (GetMessage (&messages, NULL, 0, 0)) + { + if(!IsDialogMessage(o.cnn[config].hwndStatus, &messages)) + { + TranslateMessage(&messages); + DispatchMessage(&messages); + } + } + + ExitThread(0); +} + diff --git a/openvpn.h b/openvpn.h new file mode 100644 index 0000000..43ebe93 --- /dev/null +++ b/openvpn.h @@ -0,0 +1,39 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +struct process_info { + HANDLE hProcess; + int config; +}; + +int StartOpenVPN(int config); +void StopOpenVPN(int config); +void SuspendOpenVPN(int config); +void StopAllOpenVPN(); +int ReadLineFromStdOut(HANDLE hStdOut, int config, char line[1024]); +BOOL CALLBACK StatusDialogFunc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +int AutoStartConnections(); +int VerifyAutoConnections(); +int CheckVersion(); +int CountConnectedState(int CheckVal); +void CheckAndSetTrayIcon(); +void SetStatusWinIcon(HWND hwndDlg, int IconID); +void ThreadOpenVPNStatus(int status) __attribute__ ((noreturn)); diff --git a/openvpn_config.c b/openvpn_config.c new file mode 100644 index 0000000..7222f1b --- /dev/null +++ b/openvpn_config.c @@ -0,0 +1,252 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include "main.h" +#include "openvpn-gui-res.h" +#include "options.h" + +#define MATCH_FALSE 0 +#define MATCH_FILE 1 +#define MATCH_DIR 2 + +extern struct options o; + +static int +match (const WIN32_FIND_DATA *find, const char *ext) +{ + int i; + + if (find->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + return MATCH_DIR; + + if (!strlen (ext)) + return MATCH_FILE; + + i = strlen (find->cFileName) - strlen (ext) - 1; + if (i < 1) + return MATCH_FALSE; + + if (find->cFileName[i] == '.' && !strcasecmp (find->cFileName + i + 1, ext)) + return MATCH_FILE; + else + return MATCH_FALSE; +} + +/* + * Modify the extension on a filename. + */ +static bool +modext (char *dest, unsigned int size, const char *src, const char *newext) +{ + int i; + + if (size > 0 && (strlen (src) + 1) <= size) + { + strcpy (dest, src); + dest [size - 1] = '\0'; + i = strlen (dest); + while (--i >= 0) + { + if (dest[i] == '\\') + break; + if (dest[i] == '.') + { + dest[i] = '\0'; + break; + } + } + if (strlen (dest) + strlen(newext) + 2 <= size) + { + strcat (dest, "."); + strcat (dest, newext); + return true; + } + dest [0] = '\0'; + } + return false; +} + +int ConfigAlreadyExists(char newconfig[]) +{ + int i; + + for (i=0; i= MAX_CONFIGS) + { + /* too many configs */ + ShowLocalizedMsg(GUI_NAME, ERR_TO_MANY_CONFIGS, MAX_CONFIGS); + break; + } + + /* does file have the correct type and extension? */ + if (match (&find_obj, o.ext_string) == MATCH_FILE) + { + /* Add config file to list */ + AddConfigFileToList(o.num_configs, find_obj.cFileName, o.config_dir); + + o.num_configs++; + } + + if (match (&find_obj, o.ext_string) == MATCH_DIR) + { + if ((strncmp(find_obj.cFileName, ".", strlen(find_obj.cFileName)) != 0) && + (strncmp(find_obj.cFileName, "..", strlen(find_obj.cFileName)) != 0) && + (subdir < MAX_CONFIG_SUBDIRS)) + { + /* Add dir to dir_table */ + mysnprintf(subdir_table[subdir], "%s\\%s", o.config_dir, find_obj.cFileName); + subdir++; + } + } + + /* more files to process? */ + more_files = FindNextFile (find_handle, &find_obj); + } while (more_files); + + FindClose (find_handle); + + + /* + * Loop over each config file in every subdir + */ + for (subdir_counter=0; subdir_counter < subdir; subdir_counter++) + { + + mysnprintf (find_string, "%s\\*", subdir_table[subdir_counter]); + + find_handle = FindFirstFile (find_string, &find_obj); + if (find_handle == INVALID_HANDLE_VALUE) + continue; + + do + { + if (o.num_configs >= MAX_CONFIGS) + { + /* too many configs */ + ShowLocalizedMsg(GUI_NAME, ERR_TO_MANY_CONFIGS, MAX_CONFIGS); + FindClose (find_handle); + return(true); + } + + /* does file have the correct type and extension? */ + if (match (&find_obj, o.ext_string) == MATCH_FILE) + { + if (!ConfigAlreadyExists(find_obj.cFileName)) + { + /* Add config file to list */ + AddConfigFileToList(o.num_configs, find_obj.cFileName, subdir_table[subdir_counter]); + o.num_configs++; + } + else + { + /* Config filename already exists */ + ShowLocalizedMsg(GUI_NAME, ERR_CONFIG_ALREADY_EXIST, find_obj.cFileName); + } + } + + /* more files to process? */ + more_files = FindNextFile (find_handle, &find_obj); + } while (more_files); + + FindClose (find_handle); + } + + return (true); +} + diff --git a/openvpn_config.h b/openvpn_config.h new file mode 100644 index 0000000..017a882 --- /dev/null +++ b/openvpn_config.h @@ -0,0 +1,22 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +int BuildFileList(); diff --git a/openvpn_monitor_process.c b/openvpn_monitor_process.c new file mode 100644 index 0000000..190076d --- /dev/null +++ b/openvpn_monitor_process.c @@ -0,0 +1,649 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Parts of this sourcefile is taken from openvpnserv.c from the + * OpenVPN source, with approval from the author, James Yonan + * . + */ + + +#include +#include +#include +#include "main.h" +#include "options.h" +#include "openvpn.h" +#include "scripts.h" +#include "openvpn-gui-res.h" +#include "passphrase.h" +#include "tray.h" + +extern struct options o; + +/* Wait for a complete line (CR/LF) and return it. + * Return values: + * 1 - Successful. Line is available in *line. + * 0 - Broken Pipe during ReadFile. + * -1 - Other Error during ReadFile. + * + * I'm really unhappy with this code! If anyone knows of an easier + * way to convert the streaming data from ReadFile() into lines, + * please let me know! + */ +int ReadLineFromStdOut(HANDLE hStdOut, int config, char *line) +{ + #define MAX_LINELEN 1024 + + CHAR lpBuffer[MAX_LINELEN]; + static char lastline[MAX_CONFIGS][MAX_LINELEN]; + static int charsleft[MAX_CONFIGS]; + char tmpline[MAX_LINELEN]; + DWORD nBytesRead; + DWORD nCharsWritten; + char *p; + unsigned int len, i; + static int first_call = 1; + extern HINSTANCE hInstance; + + if (first_call) + { + for (i=0; i < MAX_CONFIGS; i++) + charsleft[i]=0; + first_call = 0; + } + + while (true) + { + if (charsleft[config]) + { + /* Check for Passphrase prompt */ + CheckPrivateKeyPassphrasePrompt(lastline[config], config); + + /* Check for Username/Password Auth prompt */ + CheckAuthUsernamePrompt(lastline[config], config); + CheckAuthPasswordPrompt(lastline[config]); + + p=strchr(lastline[config], '\n'); + if (p == NULL) + { + if (!ReadFile(hStdOut,lpBuffer,sizeof(lpBuffer) - strlen(lastline[config]) - 1, + &nBytesRead,NULL) || !nBytesRead) + { + if (GetLastError() == ERROR_BROKEN_PIPE) + return(0); // pipe done - normal exit path. + else + { + /* error reading from pipe */ + ShowLocalizedMsg(GUI_NAME, ERR_READ_STDOUT_PIPE, ""); + return(-1); + } + } + lpBuffer[nBytesRead] = '\0'; + p=strchr(lpBuffer, '\n'); + if (p == NULL) + { + strncat(lastline[config], lpBuffer, sizeof(lastline[config]) - strlen(lastline[config]) - 1); + if (strlen(lastline[config]) >= (MAX_LINELEN - 1)) + { + strncpy(line, lastline[config], MAX_LINELEN); + charsleft[config]=0; + return(1); + } + } + else + { + p[0] = '\0'; + strncpy(line, lastline[config], MAX_LINELEN - 1); + strncat(line, lpBuffer, MAX_LINELEN - strlen(line)); + if (line[strlen(line) - 1] == '\r') line[strlen(line) - 1] = '\0'; + if (nBytesRead > (strlen(lpBuffer) + 1)) + { + strncpy(lastline[config], p+1, sizeof(lastline[config]) - 1); + charsleft[config]=1; + return(1); + } + charsleft[config]=0; + return(1); + } + } + else + { + len = strlen(lastline[config]); + p[0] = '\0'; + strncpy(line, lastline[config], MAX_LINELEN - 1); + if (line[strlen(line) - 1] == '\r') line[strlen(line) - 1] = '\0'; + if (len > (strlen(line) + 2)) + { + strncpy(tmpline, p+1, sizeof(tmpline) - 1); + strncpy(lastline[config], tmpline, sizeof(lastline[config]) - 1); + charsleft[config]=1; + return(1); + } + charsleft[config]=0; + return(1); + } + } + else + { + if (!ReadFile(hStdOut,lpBuffer,sizeof(lpBuffer) - 1, + &nBytesRead,NULL) || !nBytesRead) + { + if (GetLastError() == ERROR_BROKEN_PIPE) + return(0); // pipe done - normal exit path. + else + { + /* error reading from pipe */ + ShowLocalizedMsg(GUI_NAME, ERR_READ_STDOUT_PIPE, ""); + return(-1); + } + } + lpBuffer[nBytesRead] = '\0'; + p=strchr(lpBuffer, '\n'); + if (p == NULL) + { + if (nBytesRead >= (MAX_LINELEN - 1)) + { + strncpy(line, lpBuffer, MAX_LINELEN); + charsleft[config]=0; + return(1); + } + else + { + strncpy(lastline[config], lpBuffer, sizeof(lastline[config]) - 1); + charsleft[config]=1; + } + } + else + { + p[0] = '\0'; + strncpy(line, lpBuffer, MAX_LINELEN - 1); + if (line[strlen(line) - 1] == '\r') line[strlen(line) - 1] = '\0'; + if (nBytesRead > strlen(line)) + { + strncpy(lastline[config], p+1, sizeof(lastline[config]) - 1); + charsleft[config]=1; + return(1); + } + } + } + } +} + +/* + * Monitor the openvpn log output while CONNECTING + */ +void monitor_openvpnlog_while_connecting(int config, char *line) +{ + TCHAR buf[1000]; + char msg[200]; + char msg2[200]; + unsigned int i; + char *linepos; + + /* Check for Connected message */ + if (strstr(line, o.connect_string) != NULL) + { + /* Run Connect Script */ + RunConnectScript(config, false); + + /* Save time when we got connected. */ + o.cnn[config].connected_since = time(NULL); + + o.cnn[config].connect_status = CONNECTED; + SetMenuStatus(config, CONNECTED); + SetTrayIcon(CONNECTED); + + /* Remove Proxy Auth file */ + DeleteFile(o.proxy_authfile); + + /* Zero psw attempt counter */ + o.cnn[config].failed_psw_attempts = 0; + + /* UserInfo: Connected */ + myLoadString(INFO_STATE_CONNECTED); + SetDlgItemText(o.cnn[config].hwndStatus, TEXT_STATUS, buf); + SetStatusWinIcon(o.cnn[config].hwndStatus, APP_ICON_CONNECTED); + + /* Show Tray Balloon msg */ + if (o.show_balloon[0] != '0') + { + myLoadString(INFO_NOW_CONNECTED); + mysnprintf(msg, buf, o.cnn[config].config_name); + if (strlen(o.cnn[config].ip) > 0) + { + myLoadString(INFO_ASSIG_IP); + mysnprintf(msg2, buf, o.cnn[config].ip); + } + else + { + mysnprintf(msg2," "); + } + ShowTrayBalloon(msg, msg2); + } + + /* Hide Status Window */ + ShowWindow(o.cnn[config].hwndStatus, SW_HIDE); + } + + /* Check for failed passphrase log message */ + if ((strstr(line, "TLS Error: Need PEM pass phrase for private key") != NULL) || + (strstr(line, "EVP_DecryptFinal:bad decrypt") != NULL) || + (strstr(line, "PKCS12_parse:mac verify failure") != NULL) || + (strstr(line, "Received AUTH_FAILED control message") != NULL) || + (strstr(line, "Auth username is empty") != NULL)) + { + o.cnn[config].failed_psw_attempts++; + o.cnn[config].failed_psw=1; + o.cnn[config].restart=true; + } + + /* Check for "certificate has expired" message */ + if ((strstr(line, "error=certificate has expired") != NULL)) + { + StopOpenVPN(config); + /* Cert expired... */ + ShowLocalizedMsg(GUI_NAME, ERR_CERT_EXPIRED, ""); + } + + /* Check for "certificate is not yet valid" message */ + if ((strstr(line, "error=certificate is not yet valid") != NULL)) + { + StopOpenVPN(config); + /* Cert not yet valid */ + ShowLocalizedMsg(GUI_NAME, ERR_CERT_NOT_YET_VALID, ""); + } + + /* Check for "Notified TAP-Win32 driver to set a DHCP IP" message */ + if (((linepos=strstr(line, "Notified TAP-Win32 driver to set a DHCP IP")) != NULL)) + { + strncpy(o.cnn[config].ip, linepos+54, 15); /* Copy IP address */ + for (i=0; i < strlen(o.cnn[config].ip); i++) + if (o.cnn[config].ip[i] == '/' || o.cnn[config].ip[i] == ' ') break; + o.cnn[config].ip[i] = '\0'; + } +} + + +/* + * Monitor the openvpn log output while CONNECTED + */ +void monitor_openvpnlog_while_connected(int config, char *line) +{ + TCHAR buf[1000]; + + /* Check for Ping-Restart message */ + if (strstr(line, "process restarting") != NULL) + { + /* Set connect_status = ReConnecting */ + o.cnn[config].connect_status = RECONNECTING; + CheckAndSetTrayIcon(); + + /* Set Status Window Controls "ReConnecting" */ + myLoadString(INFO_STATE_RECONNECTING); + SetDlgItemText(o.cnn[config].hwndStatus, TEXT_STATUS, buf); + SetStatusWinIcon(o.cnn[config].hwndStatus, APP_ICON_CONNECTING); + } +} + +/* + * Monitor the openvpn log output while RECONNECTING + */ +void monitor_openvpnlog_while_reconnecting(int config, char *line) +{ + TCHAR buf[1000]; + char msg[200]; + char msg2[200]; + unsigned int i; + char *linepos; + + /* Check for Connected message */ + if (strstr(line, o.connect_string) != NULL) + { + o.cnn[config].connect_status = CONNECTED; + SetTrayIcon(CONNECTED); + + /* Set Status Window Controls "Connected" */ + myLoadString(INFO_STATE_CONNECTED); + SetDlgItemText(o.cnn[config].hwndStatus, TEXT_STATUS, buf); + SetStatusWinIcon(o.cnn[config].hwndStatus, APP_ICON_CONNECTED); + + /* Show Tray Balloon msg */ + if (o.show_balloon[0] == '2') + { + myLoadString(INFO_NOW_CONNECTED); + mysnprintf(msg, buf, o.cnn[config].config_name); + if (strlen(o.cnn[config].ip) > 0) + { + myLoadString(INFO_ASSIG_IP); + mysnprintf(msg2, buf, o.cnn[config].ip); + } + else + { + mysnprintf(msg2," "); + } + ShowTrayBalloon(msg, msg2); + } + } + + /* Check for failed passphrase log message */ + if ((strstr(line, "TLS Error: Need PEM pass phrase for private key") != NULL) || + (strstr(line, "EVP_DecryptFinal:bad decrypt") != NULL) || + (strstr(line, "PKCS12_parse:mac verify failure") != NULL) || + (strstr(line, "Received AUTH_FAILED control message") != NULL) || + (strstr(line, "Auth username is empty") != NULL)) + { + o.cnn[config].failed_psw_attempts++; + o.cnn[config].failed_psw=1; + o.cnn[config].restart=true; + } + + /* Check for "certificate has expired" message */ + if ((strstr(line, "error=certificate has expired") != NULL)) + { + /* Cert expired */ + StopOpenVPN(config); + ShowLocalizedMsg(GUI_NAME, ERR_CERT_EXPIRED, ""); + } + + /* Check for "certificate is not yet valid" message */ + if ((strstr(line, "error=certificate is not yet valid") != NULL)) + { + StopOpenVPN(config); + /* Cert not yet valid */ + ShowLocalizedMsg(GUI_NAME, ERR_CERT_NOT_YET_VALID, ""); + } + + /* Check for "Notified TAP-Win32 driver to set a DHCP IP" message */ + if (((linepos=strstr(line, "Notified TAP-Win32 driver to set a DHCP IP")) != NULL)) + { + strncpy(o.cnn[config].ip, linepos+54, 15); /* Copy IP address */ + for (i=0; i < strlen(o.cnn[config].ip); i++) + if (o.cnn[config].ip[i] == '/' || o.cnn[config].ip[i] == ' ') break; + o.cnn[config].ip[i] = '\0'; + } +} + + +/* + * Opens a log file and monitors the started OpenVPN process. + * All output from OpenVPN is written both to the logfile and + * to the status window. + * + * The output from OpenVPN is also watch for diffrent messages + * and appropriate actions are taken. + */ +void WatchOpenVPNProcess(int config) +{ + char line[1024]; + int ret; + char filemode[2] = "w\0"; + FILE *fd; + char msg[200]; + char msg2[200]; + int i; + int iLineCount; + int LogLines = 0; + int logpos; + char *linepos; + HWND LogWindow; + TCHAR buf[1000]; + + /* set log file append/truncate filemode */ + if (o.append_string[0] == '1') + filemode[0] = 'a'; + + /* Set Connect_Status = "Connecting" */ + o.cnn[config].connect_status = CONNECTING; + + /* Set Tray Icon = "Connecting" if no other connections are running */ + CheckAndSetTrayIcon(); + + /* Set MenuStatus = "Connecting" */ + SetMenuStatus(config, CONNECTING); + + /* Clear failed_password flag */ + o.cnn[config].failed_psw = 0; + + /* Open log file */ + if ((fd=fopen(o.cnn[config].log_path, filemode)) == NULL) + ShowLocalizedMsg (GUI_NAME, ERR_OPEN_LOG_WRITE, o.cnn[config].log_path); + + LogWindow = GetDlgItem(o.cnn[config].hwndStatus, EDIT_LOG); + while(TRUE) + { + if ((ret=ReadLineFromStdOut(o.cnn[config].hStdOut, config, line)) == 1) + { + + /* Do nothing if line length = 0 */ + if (strlen(line) == 0) continue; + + /* Write line to Log file */ + if (fd != NULL) + { + fputs (line, fd); + fputc ('\n', fd); + fflush (fd); + } + + /* Remove lines from LogWindow if it is getting full */ + LogLines++; + if (LogLines > MAX_LOG_LINES) + { + logpos = SendMessage(LogWindow, EM_LINEINDEX, DEL_LOG_LINES, 0); + SendMessage(LogWindow, EM_SETSEL, 0, logpos); + SendMessage(LogWindow, EM_REPLACESEL, FALSE, (LPARAM) ""); + LogLines -= DEL_LOG_LINES; + } + + /* Write line to LogWindow */ + strcat(line, "\r\n"); + SendMessage(LogWindow, EM_SETSEL, (WPARAM) -1, (LPARAM) -1); + SendMessage(LogWindow, EM_REPLACESEL, FALSE, (LPARAM) line); + + if (o.cnn[config].connect_status == CONNECTING) /* Connecting state */ + monitor_openvpnlog_while_connecting(config, line); + + if (o.cnn[config].connect_status == CONNECTED) /* Connected state */ + monitor_openvpnlog_while_connected(config, line); + + if (o.cnn[config].connect_status == RECONNECTING) /* ReConnecting state */ + monitor_openvpnlog_while_reconnecting(config, line); + } + else break; + + } + + + /* OpenVPN has been shutdown */ + + /* Close logfile filedesc. */ + if (fd != NULL) fclose(fd); + + /* Close StdIn/StdOut handles */ + CloseHandle(o.cnn[config].hStdIn); + CloseHandle(o.cnn[config].hStdOut); + + /* Close exitevent handle */ + CloseHandle(o.cnn[config].exit_event); + o.cnn[config].exit_event = NULL; + + /* Enable/Disable menuitems for this connections */ + SetMenuStatus(config, DISCONNECTING); + + /* Remove Proxy Auth file */ + DeleteFile(o.proxy_authfile); + + /* Process died outside our control */ + if(o.cnn[config].connect_status == CONNECTED) + { + /* Zero psw attempt counter */ + o.cnn[config].failed_psw_attempts = 0; + + /* Set connect_status = "Not Connected" */ + o.cnn[config].connect_status=DISCONNECTED; + + /* Change tray icon if no more connections is running */ + CheckAndSetTrayIcon(); + + /* Show Status Window */ + myLoadString(INFO_STATE_DISCONNECTED); + SetDlgItemText(o.cnn[config].hwndStatus, TEXT_STATUS, buf); + SetStatusWinIcon(o.cnn[config].hwndStatus, APP_ICON_DISCONNECTED); + EnableWindow(GetDlgItem(o.cnn[config].hwndStatus, ID_DISCONNECT), FALSE); + EnableWindow(GetDlgItem(o.cnn[config].hwndStatus, ID_RESTART), FALSE); + SetForegroundWindow(o.cnn[config].hwndStatus); + ShowWindow(o.cnn[config].hwndStatus, SW_SHOW); + ShowLocalizedMsg(GUI_NAME, INFO_CONN_TERMINATED, o.cnn[config].config_name); + + /* Close Status Window */ + SendMessage(o.cnn[config].hwndStatus, WM_CLOSE, 0, 0); + } + + /* We have failed to connect */ + else if(o.cnn[config].connect_status == CONNECTING) + { + + /* Set connect_status = "DisConnecting" */ + o.cnn[config].connect_status=DISCONNECTING; + + /* Change tray icon if no more connections is running */ + CheckAndSetTrayIcon(); + + if ((o.cnn[config].failed_psw) && + (o.cnn[config].failed_psw_attempts < o.psw_attempts)) + { + /* Restart OpenVPN to make another attempt to connect */ + PostMessage(o.hWnd, WM_COMMAND, (WPARAM) IDM_CONNECTMENU + config, 0); + } + else + { + /* Show Status Window */ + myLoadString(INFO_STATE_FAILED); + SetDlgItemText(o.cnn[config].hwndStatus, TEXT_STATUS, buf); + SetStatusWinIcon(o.cnn[config].hwndStatus, APP_ICON_DISCONNECTED); + EnableWindow(GetDlgItem(o.cnn[config].hwndStatus, ID_DISCONNECT), FALSE); + EnableWindow(GetDlgItem(o.cnn[config].hwndStatus, ID_RESTART), FALSE); + SetForegroundWindow(o.cnn[config].hwndStatus); + ShowWindow(o.cnn[config].hwndStatus, SW_SHOW); + + /* Zero psw attempt counter */ + o.cnn[config].failed_psw_attempts = 0; + + ShowLocalizedMsg(GUI_NAME, INFO_CONN_FAILED, o.cnn[config].config_name); + + /* Set connect_status = "Not Connected" */ + o.cnn[config].connect_status=DISCONNECTED; + + /* Close Status Window */ + SendMessage(o.cnn[config].hwndStatus, WM_CLOSE, 0, 0); + + /* Reset restart flag */ + o.cnn[config].restart=false; + + } + } + + /* We have failed to reconnect */ + else if(o.cnn[config].connect_status == RECONNECTING) + { + + /* Set connect_status = "DisConnecting" */ + o.cnn[config].connect_status=DISCONNECTING; + + /* Change tray icon if no more connections is running */ + CheckAndSetTrayIcon(); + + if ((o.cnn[config].failed_psw) && + (o.cnn[config].failed_psw_attempts < o.psw_attempts)) + { + /* Restart OpenVPN to make another attempt to connect */ + PostMessage(o.hWnd, WM_COMMAND, (WPARAM) IDM_CONNECTMENU + config, 0); + } + else + { + /* Show Status Window */ + myLoadString(INFO_STATE_FAILED_RECONN); + SetDlgItemText(o.cnn[config].hwndStatus, TEXT_STATUS, buf); + SetStatusWinIcon(o.cnn[config].hwndStatus, APP_ICON_DISCONNECTED); + EnableWindow(GetDlgItem(o.cnn[config].hwndStatus, ID_DISCONNECT), FALSE); + EnableWindow(GetDlgItem(o.cnn[config].hwndStatus, ID_RESTART), FALSE); + SetForegroundWindow(o.cnn[config].hwndStatus); + ShowWindow(o.cnn[config].hwndStatus, SW_SHOW); + + /* Zero psw attempt counter */ + o.cnn[config].failed_psw_attempts = 0; + + ShowLocalizedMsg(GUI_NAME, INFO_RECONN_FAILED, o.cnn[config].config_name); + + /* Set connect_status = "Not Connected" */ + o.cnn[config].connect_status=DISCONNECTED; + + /* Close Status Window */ + SendMessage(o.cnn[config].hwndStatus, WM_CLOSE, 0, 0); + + /* Reset restart flag */ + o.cnn[config].restart=false; + } + } + + /* We have chosed to Disconnect */ + else if(o.cnn[config].connect_status == DISCONNECTING) + { + /* Zero psw attempt counter */ + o.cnn[config].failed_psw_attempts = 0; + + /* Set connect_status = "Not Connected" */ + o.cnn[config].connect_status=DISCONNECTED; + + /* Change tray icon if no more connections is running */ + CheckAndSetTrayIcon(); + + if (o.cnn[config].restart) + { + /* Restart OpenVPN */ + StartOpenVPN(config); + } + else + { + /* Close Status Window */ + SendMessage(o.cnn[config].hwndStatus, WM_CLOSE, 0, 0); + } + } + + /* We have chosed to Suspend */ + else if(o.cnn[config].connect_status == SUSPENDING) + { + /* Zero psw attempt counter */ + o.cnn[config].failed_psw_attempts = 0; + + /* Set connect_status = "SUSPENDED" */ + o.cnn[config].connect_status=SUSPENDED; + myLoadString(INFO_STATE_SUSPENDED); + SetDlgItemText(o.cnn[config].hwndStatus, TEXT_STATUS, buf); + + /* Change tray icon if no more connections is running */ + CheckAndSetTrayIcon(); + } + + /* Enable/Disable menuitems for this connections */ + SetMenuStatus(config, DISCONNECTED); + +} + diff --git a/openvpn_monitor_process.h b/openvpn_monitor_process.h new file mode 100644 index 0000000..d7105f3 --- /dev/null +++ b/openvpn_monitor_process.h @@ -0,0 +1,22 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +void WatchOpenVPNProcess(int config); diff --git a/options.c b/options.c new file mode 100644 index 0000000..cf9fe86 --- /dev/null +++ b/options.c @@ -0,0 +1,352 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "options.h" +#include "main.h" +#include +#include +#include +#include +#include "openvpn-gui-res.h" + +extern struct options o; + +void +init_options (struct options *opt) +{ + CLEAR (*opt); +} + +int Createargcargv(struct options* options, char* command_line) +{ + + int argc; + char** argv; + + char* arg; + int myindex; + int result; + + int i; + // count the arguments + + argc = 1; + arg = command_line; + + while (arg[0] != 0) { + + while (arg[0] != 0 && arg[0] == ' ') { + arg++; + } + + if (arg[0] != 0) { + + argc++; + + if (arg[0] == '\"') { + arg++; + while (arg[0] != 0 && arg[0] != '\"') { + arg++; + } + } + while (arg[0] != 0 && arg[0] != ' ') { + arg++; + } + + } + + } + + // tokenize the arguments + argv = (char**)malloc(argc * sizeof(char*)); + + arg = command_line; + myindex = 1; + + while (arg[0] != 0) { + + while (arg[0] != 0 && arg[0] == ' ') { + arg++; + } + + if (arg[0] != 0) { + + if (arg[0] == '\"') { + arg++; + argv[myindex] = arg; + myindex++; + while (arg[0] != 0 && arg[0] != '\"') { + arg++; + } + if (arg[0] != 0) { + arg[0] = 0; + arg++; + } + while (arg[0] != 0 && arg[0] != ' ') { + arg++; + } + } + else { + argv[myindex] = arg; + myindex++; + while (arg[0] != 0 && arg[0] != ' ') { + arg++; + } + if (arg[0] != 0) { + arg[0] = 0; + arg++; + } + } + + + } + + } + + // put the program name into argv[0] + char filename[_MAX_PATH]; + + GetModuleFileName(NULL, filename, _MAX_PATH); + argv[0] = filename; + + parse_argv(options, argc, argv); + + free(argv); + return(0); + +} + +void +parse_argv (struct options* options, + int argc, + char *argv[]) +{ + int i, j; + + /* parse command line */ + for (i = 1; i < argc; ++i) + { + char *p[MAX_PARMS]; + CLEAR (p); + p[0] = argv[i]; + if (strncmp(p[0], "--", 2)) + { + /* Missing -- before option. */ + ShowLocalizedMsg(GUI_NAME, ERR_BAD_PARAMETER, p[0]); + exit(0); + } + else + p[0] += 2; + + for (j = 1; j < MAX_PARMS; ++j) + { + if (i + j < argc) + { + char *arg = argv[i + j]; + if (strncmp (arg, "--", 2)) + p[j] = arg; + else + break; + } + } + i = add_option (options, i, p); + } +} + +static int +add_option (struct options *options, + int i, + char *p[]) +{ + + if (streq (p[0], "help")) + { + TCHAR usagetext[5000]; + TCHAR usagecaption[200]; + + LoadString(o.hInstance, INFO_USAGE, usagetext, sizeof(usagetext) / sizeof(TCHAR)); + LoadString(o.hInstance, INFO_USAGECAPTION, usagecaption, sizeof(usagetext) / sizeof(TCHAR)); + MessageBox(NULL, usagetext, usagecaption, MB_OK); + exit(0); + } + else if (streq (p[0], "connect") && p[1]) + { + ++i; + static int auto_connect_nr=0; + if (auto_connect_nr == MAX_CONFIGS) + { + /* Too many configs */ + ShowLocalizedMsg(GUI_NAME, ERR_TO_MANY_CONFIGS, MAX_CONFIGS); + exit(1); + } + + options->auto_connect[auto_connect_nr] = p[1]; + auto_connect_nr++; + } + else if (streq (p[0], "exe_path") && p[1]) + { + ++i; + strncpy(options->exe_path, p[1], sizeof(options->exe_path) - 1); + } + else if (streq (p[0], "config_dir") && p[1]) + { + ++i; + strncpy(options->config_dir, p[1], sizeof(options->config_dir) - 1); + } + else if (streq (p[0], "ext_string") && p[1]) + { + ++i; + strncpy(options->ext_string, p[1], sizeof(options->ext_string) - 1); + } + else if (streq (p[0], "log_dir") && p[1]) + { + ++i; + strncpy(options->log_dir, p[1], sizeof(options->log_dir) - 1); + } + else if (streq (p[0], "priority_string") && p[1]) + { + ++i; + strncpy(options->priority_string, p[1], sizeof(options->priority_string) - 1); + } + else if (streq (p[0], "append_string") && p[1]) + { + ++i; + strncpy(options->append_string, p[1], sizeof(options->append_string) - 1); + } + else if (streq (p[0], "log_viewer") && p[1]) + { + ++i; + strncpy(options->log_viewer, p[1], sizeof(options->log_viewer) - 1); + } + else if (streq (p[0], "editor") && p[1]) + { + ++i; + strncpy(options->editor, p[1], sizeof(options->editor) - 1); + } + else if (streq (p[0], "allow_edit") && p[1]) + { + ++i; + strncpy(options->allow_edit, p[1], sizeof(options->allow_edit) - 1); + } + else if (streq (p[0], "allow_service") && p[1]) + { + ++i; + strncpy(options->allow_service, p[1], sizeof(options->allow_service) - 1); + } + else if (streq (p[0], "allow_password") && p[1]) + { + ++i; + strncpy(options->allow_password, p[1], sizeof(options->allow_password) - 1); + } + else if (streq (p[0], "allow_proxy") && p[1]) + { + ++i; + strncpy(options->allow_proxy, p[1], sizeof(options->allow_proxy) - 1); + } + else if (streq (p[0], "show_balloon") && p[1]) + { + ++i; + strncpy(options->show_balloon, p[1], sizeof(options->show_balloon) - 1); + } + else if (streq (p[0], "service_only") && p[1]) + { + ++i; + strncpy(options->service_only, p[1], sizeof(options->service_only) - 1); + } + else if (streq (p[0], "show_script_window") && p[1]) + { + ++i; + strncpy(options->show_script_window, p[1], sizeof(options->show_script_window) - 1); + } + else if (streq (p[0], "silent_connection") && p[1]) + { + ++i; + strncpy(options->silent_connection, p[1], sizeof(options->silent_connection) - 1); + } + else if (streq (p[0], "passphrase_attempts") && p[1]) + { + ++i; + strncpy(options->psw_attempts_string, p[1], sizeof(options->psw_attempts_string) - 1); + } + else if (streq (p[0], "connectscript_timeout") && p[1]) + { + ++i; + strncpy(options->connectscript_timeout_string, p[1], sizeof(options->connectscript_timeout_string) - 1); + } + else if (streq (p[0], "disconnectscript_timeout") && p[1]) + { + ++i; + strncpy(options->disconnectscript_timeout_string, p[1], + sizeof(options->disconnectscript_timeout_string) - 1); + } + else if (streq (p[0], "preconnectscript_timeout") && p[1]) + { + ++i; + strncpy(options->preconnectscript_timeout_string, p[1], + sizeof(options->preconnectscript_timeout_string) - 1); + } + else + { + /* Unrecognized option or missing parameter */ + ShowLocalizedMsg(GUI_NAME, ERR_BAD_OPTION, p[0]); + exit(1); + } + return i; +} + +/* + * Returns TRUE if option exist in config file. + */ +int ConfigFileOptionExist(int config, const char *option) +{ + FILE *fp; + char line[256]; + int found_key=0; + int found_pkcs12=0; + char configfile_path[MAX_PATH]; + + strncpy(configfile_path, o.cnn[config].config_dir, sizeof(configfile_path)); + if (!(configfile_path[strlen(configfile_path)-1] == '\\')) + strcat(configfile_path, "\\"); + strncat(configfile_path, o.cnn[config].config_file, + sizeof(configfile_path) - strlen(configfile_path) - 1); + + if (!(fp=fopen(configfile_path, "r"))) + { + /* can't open config file */ + ShowLocalizedMsg(GUI_NAME, ERR_OPEN_CONFIG, configfile_path); + return(0); + } + + while (fgets(line, sizeof (line), fp)) + { + if ((strncmp(line, option, sizeof(option)) == 0)) + { + fclose(fp); + return(1); + } + } + + fclose(fp); + return(0); +} + diff --git a/options.h b/options.h new file mode 100644 index 0000000..10f94d8 --- /dev/null +++ b/options.h @@ -0,0 +1,137 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include + +/* + * Maximum number of parameters associated with an option, + * including the option name itself. + */ +#define MAX_PARMS 5 +#define MAX_CONFIGS 50 /* Max number of config-files to read. */ +#define MAX_CONFIG_SUBDIRS 50 /* Max number of subdirs to scan */ + +/* connect_status STATES */ +#define DISCONNECTED 0 +#define CONNECTING 1 +#define CONNECTED 2 +#define RECONNECTING 3 +#define DISCONNECTING 4 +#define SUSPENDING 5 +#define SUSPENDED 6 + +/* OpenVPN Service STATES */ +#define SERVICE_NOACCESS -1 +#define SERVICE_DISCONNECTED 0 +#define SERVICE_CONNECTING 1 +#define SERVICE_CONNECTED 2 + +/* Connections parameters */ +struct connections +{ + char config_file[MAX_PATH]; /* Name of the config file */ + char config_name[MAX_PATH]; /* Name of the connection */ + char config_dir[MAX_PATH]; /* Path to this configs dir */ + char log_path[MAX_PATH]; /* Path to Logfile */ + char ip[16]; /* Assigned IP address for this connection */ + char exit_event_name[50]; /* Exit Event name for this connection */ + int connect_status; /* 0=Not Connected 1=Connecting + 2=Connected 3=Reconnecting 4=Disconnecting */ + int auto_connect; /* true=AutoConnect at startup */ + int failed_psw; /* 1=OpenVPN failed because of wrong psw */ + int failed_psw_attempts; /* # of failed attempts maid to enter psw */ + int restart; /* true=Restart connection after termination */ + time_t connected_since; /* Time when the connection was established */ + + HANDLE exit_event; + HANDLE hProcess; + HANDLE hStdOut; + HANDLE hStdIn; + HWND hwndStatus; /* Handle to Status Dialog Window */ +}; + +/* All options used within OpenVPN GUI */ +struct options +{ + /* Array of configs to autostart */ + const char *auto_connect[MAX_CONFIGS]; + + /* Connection parameters */ + struct connections cnn[MAX_CONFIGS]; /* Connection structure */ + int num_configs; /* Number of configs */ + + int oldversion; /* 1=OpenVPN version below 2.0-beta6 */ + char connect_string[100]; /* String to look for to report connected */ + int psw_attempts; /* Number of psw attemps to allow */ + int connectscript_timeout; /* Connect Script execution timeout (sec) */ + int disconnectscript_timeout; /* Disconnect Script execution timeout (sec) */ + int preconnectscript_timeout; /* Preconnect Script execution timeout (sec) */ + int service_running; /* true if OpenVPN Service is started */ + HWND hWnd; /* Main Window Handle */ + HINSTANCE hInstance; + + /* Registry values */ + char exe_path[MAX_PATH]; + char config_dir[MAX_PATH]; + char ext_string[16]; + char log_dir[MAX_PATH]; + char priority_string[64]; + char append_string[2]; + char log_viewer[MAX_PATH]; + char editor[MAX_PATH]; + char allow_edit[2]; + char allow_service[2]; + char allow_password[2]; + char allow_proxy[2]; + char silent_connection[2]; + char service_only[2]; + char show_balloon[2]; + char show_script_window[2]; + char psw_attempts_string[2]; + char disconnect_on_suspend[2]; + char connectscript_timeout_string[4]; + char disconnectscript_timeout_string[4]; + char preconnectscript_timeout_string[4]; + + /* Proxy Settings */ + int proxy_source; /* 0=OpenVPN config, 1=IE, 2=Manual */ + int proxy_type; /* 0=HTTP, 1=SOCKS */ + int proxy_http_auth; /* 0=Auth Disabled, 1=Auth Enabled */ + char proxy_http_address[100]; /* HTTP Proxy Address */ + char proxy_http_port[6]; /* HTTP Proxy Port */ + char proxy_socks_address[100]; /* SOCKS Proxy Address */ + char proxy_socks_port[6]; /* SOCKS Proxy Address */ + char proxy_authfile[100]; /* Path to proxy auth file */ + + /* Debug file pointer */ +#ifdef DEBUG + FILE *debug_fp; +#endif +}; + +#define streq(x, y) (!strcmp((x), (y))) +void init_options (struct options *o); +int Createargcargv(struct options* options, char* command_line); +void parse_argv (struct options* options, int argc, char *argv[]); +static int add_option (struct options *options, int i, char *p[]); +int ConfigFileOptionExist(int config, const char *option); diff --git a/passphrase.c b/passphrase.c new file mode 100644 index 0000000..2bc40c1 --- /dev/null +++ b/passphrase.c @@ -0,0 +1,902 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "main.h" +#include "options.h" +#include "passphrase.h" +#include "openvpn.h" +#include "openvpn-gui-res.h" +#include "chartable.h" + +#ifndef DISABLE_CHANGE_PASSWORD +#include +#include +#include +#endif + +WCHAR passphrase[256]; +extern struct options o; + +int ConvertUnicode2Ascii(WCHAR str_unicode[], char str_ascii[], unsigned int str_ascii_size) +{ + unsigned int i; + unsigned int j; + int illegal_chars = false; + char *str_unicode_ptr = (char *) str_unicode; + for (i=0; (i < wcslen(str_unicode)) && (i < (str_ascii_size - 1)); i++) + { + for (j=0; j <= 256; j++) + { + if (j == 256) + { + illegal_chars = true; + j = 0x2e; + break; + } + if (str_unicode[i] == unicode_to_ascii[j]) break; + } + str_ascii[i] = (char) j; + } + str_ascii[i] = '\0'; + + if (illegal_chars) + return(false); + else + return(true); +} + +void CheckPrivateKeyPassphrasePrompt (char *line, int config) +{ + DWORD nCharsWritten; + char passphrase_ascii[256]; + + /* Check for Passphrase prompt */ + if (strncmp(line, "Enter PEM pass phrase:", 22) == 0) + { + CLEAR(passphrase); + if (DialogBox(o.hInstance, (LPCTSTR)IDD_PASSPHRASE, NULL, + (DLGPROC)PassphraseDialogFunc) == IDCANCEL) + { + StopOpenVPN(config); + } + + if (wcslen(passphrase) > 0) + { + CLEAR(passphrase_ascii); + ConvertUnicode2Ascii(passphrase, passphrase_ascii, sizeof(passphrase_ascii)); + + if (!WriteFile(o.cnn[config].hStdIn, passphrase_ascii, + strlen(passphrase_ascii), &nCharsWritten, NULL)) + { + /* PassPhrase -> stdin failed */ + ShowLocalizedMsg(GUI_NAME, ERR_PASSPHRASE2STDIN, ""); + } + } + if (!WriteFile(o.cnn[config].hStdIn, "\r\n", + 2, &nCharsWritten, NULL)) + { + /* CR -> stdin failed */ + ShowLocalizedMsg(GUI_NAME, ERR_CR2STDIN, ""); + } + /* Remove Passphrase prompt from lastline buffer */ + line[0]='\0'; + + /* Clear passphrase buffer */ + CLEAR(passphrase); + CLEAR(passphrase_ascii); + } + + /* Check for new passphrase prompt introduced with OpenVPN 2.0-beta12. */ + if (strncmp(line, "Enter Private Key Password:", 27) == 0) + { + CLEAR(passphrase); + if (DialogBox(o.hInstance, (LPCTSTR)IDD_PASSPHRASE, NULL, + (DLGPROC)PassphraseDialogFunc) == IDCANCEL) + { + StopOpenVPN(config); + } + + if (wcslen(passphrase) > 0) + { + CLEAR(passphrase_ascii); + ConvertUnicode2Ascii(passphrase, passphrase_ascii, sizeof(passphrase_ascii)); + + if (!WriteFile(o.cnn[config].hStdIn, passphrase_ascii, + strlen(passphrase_ascii), &nCharsWritten, NULL)) + { + /* PassPhrase -> stdin failed */ + ShowLocalizedMsg(GUI_NAME, ERR_PASSPHRASE2STDIN, ""); + } + } + else + { + if (!WriteFile(o.cnn[config].hStdIn, "\n", + 1, &nCharsWritten, NULL)) + { + /* CR -> stdin failed */ + ShowLocalizedMsg(GUI_NAME, ERR_CR2STDIN, ""); + } + } + /* Remove Passphrase prompt from lastline buffer */ + line[0]='\0'; + + /* Clear passphrase buffer */ + CLEAR(passphrase); + CLEAR(passphrase_ascii); + } + +} + +void CheckAuthUsernamePrompt (char *line, int config) +{ + DWORD nCharsWritten; + struct user_auth user_auth; + + /* Check for Passphrase prompt */ + if (strncmp(line, "Enter Auth Username:", 20) == 0) + { + CLEAR(user_auth); + if (DialogBoxParam(o.hInstance, + (LPCTSTR)IDD_AUTH_PASSWORD, + NULL, + (DLGPROC)AuthPasswordDialogFunc, + (LPARAM)&user_auth) == IDCANCEL) + { + StopOpenVPN(config); + } + + if (strlen(user_auth.username) > 0) + { + if (!WriteFile(o.cnn[config].hStdIn, user_auth.username, + strlen(user_auth.username), &nCharsWritten, NULL)) + { + ShowLocalizedMsg(GUI_NAME, ERR_AUTH_USERNAME2STDIN, ""); + } + } + else + { + if (!WriteFile(o.cnn[config].hStdIn, "\n", + 1, &nCharsWritten, NULL)) + { + ShowLocalizedMsg(GUI_NAME, ERR_CR2STDIN, ""); + } + } + + if (strlen(user_auth.password) > 0) + { + if (!WriteFile(o.cnn[config].hStdIn, user_auth.password, + strlen(user_auth.password), &nCharsWritten, NULL)) + { + ShowLocalizedMsg(GUI_NAME, ERR_AUTH_PASSWORD2STDIN, ""); + } + } + else + { + if (!WriteFile(o.cnn[config].hStdIn, "\n", + 1, &nCharsWritten, NULL)) + { + ShowLocalizedMsg(GUI_NAME, ERR_CR2STDIN, ""); + } + } + + /* Remove Username prompt from lastline buffer */ + line[0]='\0'; + + /* Clear user_auth buffer */ + CLEAR(user_auth); + } + +} + +void CheckAuthPasswordPrompt (char *line) +{ + + /* Check for Passphrase prompt */ + if (strncmp(line, "Enter Auth Password:", 20) == 0) + { + + /* Remove Passphrase prompt from lastline buffer */ + line[0]='\0'; + + } +} + +BOOL CALLBACK PassphraseDialogFunc (HWND hwndDlg, UINT msg, WPARAM wParam, UNUSED LPARAM lParam) +{ + static char empty_string[100]; + + switch (msg) { + + case WM_INITDIALOG: + SetForegroundWindow(hwndDlg); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + + case IDOK: // button + GetDlgItemTextW(hwndDlg, EDIT_PASSPHRASE, passphrase, sizeof(passphrase)/2 - 1); + + /* Clear buffer */ + SetDlgItemText(hwndDlg, EDIT_PASSPHRASE, empty_string); + + EndDialog(hwndDlg, LOWORD(wParam)); + return TRUE; + + case IDCANCEL: // button + EndDialog(hwndDlg, LOWORD(wParam)); + return TRUE; + } + break; + case WM_CLOSE: + EndDialog(hwndDlg, LOWORD(wParam)); + return TRUE; + + } + return FALSE; +} + +BOOL CALLBACK AuthPasswordDialogFunc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static struct user_auth *user_auth; + static char empty_string[100]; + WCHAR username_unicode[50]; + WCHAR password_unicode[50]; + + switch (msg) { + + case WM_INITDIALOG: + user_auth = (struct user_auth *) lParam; + SetForegroundWindow(hwndDlg); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + + case IDOK: // button + GetDlgItemTextW(hwndDlg, EDIT_AUTH_USERNAME, username_unicode, sizeof(username_unicode)/2 - 1); + GetDlgItemTextW(hwndDlg, EDIT_AUTH_PASSWORD, password_unicode, sizeof(password_unicode)/2 - 1); + + /* Convert username/password from Unicode to Ascii (CP850) */ + ConvertUnicode2Ascii(username_unicode, user_auth->username, sizeof(user_auth->username) - 1); + ConvertUnicode2Ascii(password_unicode, user_auth->password, sizeof(user_auth->password) - 1); + + /* Clear buffers */ + SetDlgItemText(hwndDlg, EDIT_AUTH_USERNAME, empty_string); + SetDlgItemText(hwndDlg, EDIT_AUTH_PASSWORD, empty_string); + + EndDialog(hwndDlg, LOWORD(wParam)); + return TRUE; + + case IDCANCEL: // button + EndDialog(hwndDlg, LOWORD(wParam)); + return TRUE; + } + break; + case WM_CLOSE: + EndDialog(hwndDlg, LOWORD(wParam)); + return TRUE; + + } + return FALSE; +} + + +#ifndef DISABLE_CHANGE_PASSWORD + +const int KEYFILE_FORMAT_PKCS12 = 1; +const int KEYFILE_FORMAT_PEM = 2; + +void ShowChangePassphraseDialog(int config) +{ + HANDLE hThread; + DWORD IDThread; + + /* Start a new thread to have our own message-loop for this dialog */ + hThread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) ChangePassphraseThread, + (int *) config, // pass config nr + 0, &IDThread); + if (hThread == NULL) + { + /* error creating thread */ + ShowLocalizedMsg (GUI_NAME, ERR_CREATE_PASS_THREAD, ""); + return; + } + +} + +void ChangePassphraseThread(int config) +{ + HWND hwndChangePSW; + MSG messages; + char conn_name[100]; + char msg[100]; + char keyfilename[MAX_PATH]; + int keyfile_format=0; + TCHAR buf[1000]; + + /* Cut of extention from config filename. */ + strncpy(conn_name, o.cnn[config].config_file, sizeof(conn_name)); + conn_name[strlen(conn_name) - (strlen(o.ext_string)+1)]=0; + + /* Get Key filename from config file */ + if (!GetKeyFilename(config, keyfilename, sizeof(keyfilename), &keyfile_format)) + { + ExitThread(1); + } + + /* Show ChangePassphrase Dialog */ + if (!(hwndChangePSW = CreateDialog (o.hInstance, + MAKEINTRESOURCE (IDD_CHANGEPSW), + NULL, (DLGPROC) ChangePassphraseDialogFunc))) + return; + SetDlgItemText(hwndChangePSW, TEXT_KEYFILE, keyfilename); + SetDlgItemInt(hwndChangePSW, TEXT_KEYFORMAT, (UINT) keyfile_format, FALSE); + + myLoadString(INFO_CHANGE_PWD); + mysnprintf(msg, buf, conn_name); + SetWindowText(hwndChangePSW, msg); + + ShowWindow(hwndChangePSW, SW_SHOW); + + + /* Run the message loop. It will run until GetMessage() returns 0 */ + while (GetMessage (&messages, NULL, 0, 0)) + { + if(!IsDialogMessage(hwndChangePSW, &messages)) + { + TranslateMessage(&messages); + DispatchMessage(&messages); + } + } + + ExitThread(0); +} + +BOOL CALLBACK ChangePassphraseDialogFunc (HWND hwndDlg, UINT msg, WPARAM wParam, UNUSED LPARAM lParam) +{ + HICON hIcon; + char keyfile[MAX_PATH]; + int keyfile_format; + BOOL Translated; + TCHAR buf[1000]; + + switch (msg) { + + case WM_INITDIALOG: + hIcon = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(APP_ICON), + IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR); + if (hIcon) { + SendMessage(hwndDlg, WM_SETICON, (WPARAM) (ICON_SMALL), (LPARAM) (hIcon)); + SendMessage(hwndDlg, WM_SETICON, (WPARAM) (ICON_BIG), (LPARAM) (hIcon)); + } + return FALSE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + + case IDOK: + + /* Check if the type new passwords match. */ + if (!ConfirmNewPassword (hwndDlg)) + { + /* passwords don't match */ + ShowLocalizedMsg(GUI_NAME, ERR_PWD_DONT_MATCH, ""); + break; + } + + /* Check minimum length of password */ + if (NewPasswordLengh(hwndDlg) < MIN_PASSWORD_LEN) + { + ShowLocalizedMsg(GUI_NAME, ERR_PWD_TO_SHORT, MIN_PASSWORD_LEN); + break; + } + + /* Check if the new password is empty. */ + if (NewPasswordLengh(hwndDlg) == 0) + { + myLoadString(INFO_EMPTY_PWD); + if (MessageBox(NULL, buf, GUI_NAME, MB_YESNO) != IDYES) + break; + } + + GetDlgItemText(hwndDlg, TEXT_KEYFILE, keyfile, sizeof(keyfile) - 1); + keyfile_format=GetDlgItemInt(hwndDlg, TEXT_KEYFORMAT, &Translated, FALSE); + if (keyfile_format == KEYFILE_FORMAT_PEM) + { + /* Change password of a PEM file */ + if (ChangePasswordPEM(hwndDlg) == -1) /* Wrong password */ + break; + } + else if (keyfile_format == KEYFILE_FORMAT_PKCS12) + { + /* Change password of a .P12 file */ + if (ChangePasswordPKCS12(hwndDlg) == -1) /* Wrong password */ + break; + } + else + { + /* Unknown key format */ + ShowLocalizedMsg (GUI_NAME, ERR_UNKNOWN_KEYFILE_FORMAT, ""); + } + + DestroyWindow(hwndDlg); + break; + + case IDCANCEL: + DestroyWindow(hwndDlg); + break; + } + break; + + + case WM_DESTROY: + PostQuitMessage(0); + break; + + + case WM_CLOSE: + DestroyWindow(hwndDlg); + return FALSE; + + } + return FALSE; +} + + +/* Return TRUE if new passwords match */ +int ConfirmNewPassword(HWND hwndDlg) +{ + char newpsw[50]; + char newpsw2[50]; + + GetDlgItemText(hwndDlg, EDIT_PSW_NEW, newpsw, sizeof(newpsw) - 1); + GetDlgItemText(hwndDlg, EDIT_PSW_NEW2, newpsw2, sizeof(newpsw2) - 1); + + if (strncmp(newpsw, newpsw2, sizeof(newpsw)) == 0) + return true; + else + return false; +} + +/* Return lengh of the new password */ +int NewPasswordLengh(HWND hwndDlg) +{ + char newpsw[50]; + + GetDlgItemText(hwndDlg, EDIT_PSW_NEW, newpsw, sizeof(newpsw) - 1); + + return (strlen(newpsw)); +} + +int ParseKeyFilenameLine(int config, char *keyfilename, unsigned int keyfilenamesize, char *line) +{ + const int STATE_INITIAL = 0; + const int STATE_READING_QUOTED_PARM = 1; + const int STATE_READING_UNQUOTED_PARM = 2; + int i=0; + unsigned int j=0; + int state = STATE_INITIAL; + int backslash=0; + char temp_filename[MAX_PATH]; + + while(line[i] != '\0') + { + if (state == STATE_INITIAL) + { + if (line[i] == '\"') + { + state=STATE_READING_QUOTED_PARM; + } + else if ((line[i] == 0x0A) || (line[i] == 0x0D)) + break; + else if ((line[i] == ';') || (line[i] == '#')) + break; + else if ((line[i] != ' ') && (line[i] != '\t')) + { + if (line[i] == '\\') + { + if(!backslash) + { + keyfilename[j++]=line[i]; + state=STATE_READING_UNQUOTED_PARM; + backslash=1; + } + else + { + backslash=0; + } + } + else + { + if (backslash) backslash=0; + keyfilename[j++]=line[i]; + state=STATE_READING_UNQUOTED_PARM; + } + } + } + + else if (state == STATE_READING_QUOTED_PARM) + { + if (line[i] == '\"') + break; + if ((line[i] == 0x0A) || (line[i] == 0x0D)) + break; + if (line[i] == '\\') + { + if (!backslash) + { + keyfilename[j++]=line[i]; + backslash=1; + } + else + { + backslash=0; + } + } + else + { + if (backslash) backslash=0; + keyfilename[j++]=line[i]; + } + } + + else if (state == STATE_READING_UNQUOTED_PARM) + { + if (line[i] == '\"') + break; + if ((line[i] == 0x0A) || (line[i] == 0x0D)) + break; + if ((line[i] == ';') || (line[i] == '#')) + break; + if (line[i] == ' ') + break; + if (line[i] == '\t') + break; + if (line[i] == '\\') + { + if (!backslash) + { + keyfilename[j++]=line[i]; + backslash=1; + } + else + { + backslash=0; + } + } + else + { + if (backslash) backslash=0; + keyfilename[j++]=line[i]; + } + } + + if (j >= (keyfilenamesize - 1)) + { + /* key filename to long */ + ShowLocalizedMsg(GUI_NAME, ERR_KEY_FILENAME_TO_LONG, ""); + return(0); + } + i++; + } + keyfilename[j]='\0'; + + /* Prepend filename with configdir path if needed */ + if ((keyfilename[0] != '\\') && (keyfilename[0] != '/') && (keyfilename[1] != ':')) + { + strncpy(temp_filename, o.cnn[config].config_dir, sizeof(temp_filename)); + if (temp_filename[strlen(temp_filename) - 1] != '\\') + strcat(temp_filename, "\\"); + strncat(temp_filename, keyfilename, + sizeof(temp_filename) - strlen(temp_filename) - 1); + strncpy(keyfilename, temp_filename, keyfilenamesize - 1); + } + + return(1); +} + + +/* ChangePasswordPEM() returns: + * -1 Wrong password + * 0 Changing password failed for unknown reason + * 1 Password changed successfully + */ +int ChangePasswordPEM(HWND hwndDlg) +{ + char keyfile[MAX_PATH]; + char oldpsw[50]; + char newpsw[50]; + WCHAR oldpsw_unicode[50]; + WCHAR newpsw_unicode[50]; + FILE *fp; + + EVP_PKEY *privkey; + + /* Get filename, old_psw and new_psw from Dialog */ + GetDlgItemText(hwndDlg, TEXT_KEYFILE, keyfile, sizeof(keyfile) - 1); + GetDlgItemTextW(hwndDlg, EDIT_PSW_CURRENT, oldpsw_unicode, sizeof(oldpsw_unicode)/2 - 1); + GetDlgItemTextW(hwndDlg, EDIT_PSW_NEW, newpsw_unicode, sizeof(newpsw_unicode)/2 - 1); + + /* Convert Unicode to ASCII (CP850) */ + ConvertUnicode2Ascii(oldpsw_unicode, oldpsw, sizeof(oldpsw)); + if (!ConvertUnicode2Ascii(newpsw_unicode, newpsw, sizeof(newpsw))) + { + ShowLocalizedMsg(GUI_NAME, ERR_INVALID_CHARS_IN_PSW, ""); + return(-1); + } + + privkey = EVP_PKEY_new(); + + /* Open old keyfile for reading */ + if (! (fp = fopen (keyfile, "r"))) + { + /* can't open key file */ + ShowLocalizedMsg(GUI_NAME, ERR_OPEN_PRIVATE_KEY_FILE, keyfile); + return(0); + } + + /* Import old key */ + if (! (privkey = PEM_read_PrivateKey (fp, NULL, NULL, oldpsw))) + { + /* wrong password */ + ShowLocalizedMsg(GUI_NAME, ERR_OLD_PWD_INCORRECT, ""); + fclose(fp); + return(-1); + } + + fclose(fp); + + /* Open keyfile for writing */ + if (! (fp = fopen (keyfile, "w"))) + { + /* can't open file rw */ + ShowLocalizedMsg(GUI_NAME, ERR_OPEN_WRITE_KEY, keyfile); + EVP_PKEY_free(privkey); + return(0); + } + + /* Write new key to file */ + if (strlen(newpsw) == 0) + { + /* No passphrase */ + if ( !(PEM_write_PrivateKey(fp, privkey, \ + NULL, NULL, /* Use NO encryption */ + 0, 0, NULL))) + { + /* error writing new key */ + ShowLocalizedMsg(GUI_NAME, ERR_WRITE_NEW_KEY, keyfile); + EVP_PKEY_free(privkey); + fclose(fp); + return(0); + } + } + else + { + /* Use passphrase */ + if ( !(PEM_write_PrivateKey(fp, privkey, \ + EVP_des_ede3_cbc(), /* Use 3DES encryption */ + newpsw, (int) strlen(newpsw), 0, NULL))) + { + /* can't write new key */ + ShowLocalizedMsg(GUI_NAME, ERR_WRITE_NEW_KEY, keyfile); + EVP_PKEY_free(privkey); + fclose(fp); + return(0); + } + } + + EVP_PKEY_free(privkey); + fclose(fp); + + /* signal success to user */ + ShowLocalizedMsg(GUI_NAME, INFO_PWD_CHANGED, ""); + return(1); +} + + +/* ChangePasswordPKCS12() returns: + * -1 Wrong password + * 0 Changing password failed for unknown reason + * 1 Password changed successfully + */ +int ChangePasswordPKCS12(HWND hwndDlg) +{ + char keyfile[MAX_PATH]; + char oldpsw[50]; + char newpsw[50]; + WCHAR oldpsw_unicode[50]; + WCHAR newpsw_unicode[50]; + FILE *fp; + + EVP_PKEY *privkey; + X509 *cert; + STACK_OF(X509) *ca = NULL; + PKCS12 *p12; + PKCS12 *new_p12; + char *alias; + + /* Get filename, old_psw and new_psw from Dialog */ + GetDlgItemText(hwndDlg, TEXT_KEYFILE, keyfile, sizeof(keyfile) - 1); + GetDlgItemTextW(hwndDlg, EDIT_PSW_CURRENT, oldpsw_unicode, sizeof(oldpsw_unicode)/2 - 1); + GetDlgItemTextW(hwndDlg, EDIT_PSW_NEW, newpsw_unicode, sizeof(newpsw_unicode)/2 - 1); + + /* Convert Unicode to ASCII (CP850) */ + ConvertUnicode2Ascii(oldpsw_unicode, oldpsw, sizeof(oldpsw)); + if (!ConvertUnicode2Ascii(newpsw_unicode, newpsw, sizeof(newpsw))) + { + ShowLocalizedMsg(GUI_NAME, ERR_INVALID_CHARS_IN_PSW, ""); + return(-1); + } + + /* Load the PKCS #12 file */ + if (!(fp = fopen(keyfile, "rb"))) + { + /* error opening file */ + ShowLocalizedMsg(GUI_NAME, ERR_OPEN_PRIVATE_KEY_FILE, keyfile); + return(0); + } + p12 = d2i_PKCS12_fp(fp, NULL); + fclose (fp); + if (!p12) + { + /* error reading PKCS #12 */ + ShowLocalizedMsg(GUI_NAME, ERR_READ_PKCS12, keyfile); + return(0); + } + + /* Parse the PKCS #12 file */ + if (!PKCS12_parse(p12, oldpsw, &privkey, &cert, &ca)) + { + /* old password incorrect */ + ShowLocalizedMsg(GUI_NAME, ERR_OLD_PWD_INCORRECT, ""); + PKCS12_free(p12); + return(-1); + } + + /* Free old PKCS12 object */ + PKCS12_free(p12); + + /* Get FriendlyName of old cert */ + alias = X509_alias_get0(cert, NULL); + + /* Create new PKCS12 object */ + p12 = PKCS12_create(newpsw, alias, privkey, cert, ca, 0,0,0,0,0); + if (!p12) + { + /* create failed */ + //ShowMsg(GUI_NAME, ERR_error_string(ERR_peek_last_error(), NULL)); + ShowLocalizedMsg(GUI_NAME, ERR_CREATE_PKCS12, ""); + return(0); + } + + /* Free old key, cert and ca */ + EVP_PKEY_free(privkey); + X509_free(cert); + sk_X509_pop_free(ca, X509_free); + + /* Open keyfile for writing */ + if (!(fp = fopen(keyfile, "wb"))) + { + ShowLocalizedMsg(GUI_NAME, ERR_OPEN_WRITE_KEY, keyfile); + PKCS12_free(p12); + return(0); + } + + /* Write new key to file */ + i2d_PKCS12_fp(fp, p12); + + PKCS12_free(p12); + fclose(fp); + /* signal success to user */ + ShowLocalizedMsg(GUI_NAME, INFO_PWD_CHANGED, ""); + + return(1); +} + +int LineBeginsWith(char *line, const char *keyword, const unsigned int len) +{ + if (strncmp(line, keyword, len) == 0) + { + if ((line[len] == '\t') || (line[len] == ' ')) + return true; + } + + return false; +} + +int GetKeyFilename(int config, char *keyfilename, unsigned int keyfilenamesize, int *keyfile_format) +{ + FILE *fp; + char line[256]; + int found_key=0; + int found_pkcs12=0; + char configfile_path[MAX_PATH]; + + strncpy(configfile_path, o.cnn[config].config_dir, sizeof(configfile_path)); + if (!(configfile_path[strlen(configfile_path)-1] == '\\')) + strcat(configfile_path, "\\"); + strncat(configfile_path, o.cnn[config].config_file, + sizeof(configfile_path) - strlen(configfile_path) - 1); + + if (!(fp=fopen(configfile_path, "r"))) + { + /* can't open config file */ + ShowLocalizedMsg(GUI_NAME, ERR_OPEN_CONFIG, configfile_path); + return(0); + } + + while (fgets(line, sizeof (line), fp)) + { + if (LineBeginsWith(line, "key", 3)) + { + if (found_key) + { + /* only one key option */ + ShowLocalizedMsg(GUI_NAME, ERR_ONLY_ONE_KEY_OPTION, ""); + return(0); + } + if (found_pkcs12) + { + /* key XOR pkcs12 */ + ShowLocalizedMsg(GUI_NAME, ERR_ONLY_KEY_OR_PKCS12, ""); + return(0); + } + found_key=1; + *keyfile_format = KEYFILE_FORMAT_PEM; + if (!ParseKeyFilenameLine(config, keyfilename, keyfilenamesize, &line[4])) + return(0); + } + if (LineBeginsWith(line, "pkcs12", 6)) + { + if (found_pkcs12) + { + /* only one pkcs12 option */ + ShowLocalizedMsg(GUI_NAME, ERR_ONLY_ONE_PKCS12_OPTION, ""); + return(0); + } + if (found_key) + { + /* only key XOR pkcs12 */ + ShowLocalizedMsg(GUI_NAME, ERR_ONLY_KEY_OR_PKCS12, ""); + return(0); + } + found_pkcs12=1; + *keyfile_format = KEYFILE_FORMAT_PKCS12; + if (!ParseKeyFilenameLine(config, keyfilename, keyfilenamesize, &line[7])) + return(0); + } + } + + if ((!found_key) && (!found_pkcs12)) + { + /* must have key or pkcs12 option */ + ShowLocalizedMsg(GUI_NAME, ERR_MUST_HAVE_KEY_OR_PKCS12, ""); + return(0); + } + + return(1); +} + + +#endif diff --git a/passphrase.h b/passphrase.h new file mode 100644 index 0000000..1d311b7 --- /dev/null +++ b/passphrase.h @@ -0,0 +1,43 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define MIN_PASSWORD_LEN 8 + +struct user_auth { + char username[50]; + char password[50]; +}; + +void CheckPrivateKeyPassphrasePrompt (char *line, int config); +void CheckAuthUsernamePrompt (char *line, int config); +void CheckAuthPasswordPrompt (char *line); +BOOL CALLBACK PassphraseDialogFunc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +BOOL CALLBACK AuthPasswordDialogFunc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +void ShowChangePassphraseDialog(int config); +BOOL CALLBACK ChangePassphraseDialogFunc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +void ChangePassphraseThread(int config); +int ConfirmNewPassword(HWND hwndDlg); +int NewPasswordLengh(HWND hwndDlg); +int ChangePasswordPEM(HWND hwndDlg); +int ChangePasswordPKCS12(HWND hwndDlg); +int GetKeyFilename(int config, char *keyfilename, unsigned int keyfilenamesize, int *keyfile_format); + diff --git a/proxy.c b/proxy.c new file mode 100644 index 0000000..2f93d90 --- /dev/null +++ b/proxy.c @@ -0,0 +1,569 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "main.h" +#include "options.h" +#include "registry.h" +#include "proxy.h" +#include "ieproxy.h" +#include "openvpn-gui-res.h" + +extern struct options o; + +void ShowProxySettingsDialog() +{ + + DialogBox(o.hInstance, (LPCTSTR)IDD_PROXY, NULL, (DLGPROC)ProxySettingsDialogFunc); +} + +BOOL CALLBACK ProxySettingsDialogFunc (HWND hwndDlg, UINT msg, WPARAM wParam, UNUSED LPARAM lParam) +{ + HICON hIcon; + + switch (msg) { + + case WM_INITDIALOG: + hIcon = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(APP_ICON), + IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR); + if (hIcon) { + SendMessage(hwndDlg, WM_SETICON, (WPARAM) (ICON_SMALL), (LPARAM) (hIcon)); + SendMessage(hwndDlg, WM_SETICON, (WPARAM) (ICON_BIG), (LPARAM) (hIcon)); + } + + /* Limit Port editboxs to 5 chars. */ + SendMessage(GetDlgItem(hwndDlg, EDIT_PROXY_HTTP_PORT), EM_SETLIMITTEXT, 5, 0); + SendMessage(GetDlgItem(hwndDlg, EDIT_PROXY_SOCKS_PORT), EM_SETLIMITTEXT, 5, 0); + + LoadProxySettings(hwndDlg); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + + case IDOK: + if (CheckProxySettings(hwndDlg)) + { + SaveProxySettings(hwndDlg); + EndDialog(hwndDlg, LOWORD(wParam)); + return TRUE; + } + return FALSE; + + case IDCANCEL: + EndDialog(hwndDlg, LOWORD(wParam)); + return TRUE; + + case RB_PROXY_USE_OPENVPN: + if (HIWORD(wParam) == BN_CLICKED) + { + EnableWindow(GetDlgItem(hwndDlg, RB_PROXY_HTTP), FALSE); + EnableWindow(GetDlgItem(hwndDlg, RB_PROXY_SOCKS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_HTTP_ADDRESS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_HTTP_PORT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_HTTP_ADDRESS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_HTTP_PORT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, CHECKB_PROXY_AUTH), FALSE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_SOCKS_ADDRESS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_SOCKS_PORT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_SOCKS_ADDRESS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_SOCKS_PORT), FALSE); + break; + } + + case RB_PROXY_USE_IE: + if (HIWORD(wParam) == BN_CLICKED) + { + EnableWindow(GetDlgItem(hwndDlg, RB_PROXY_HTTP), FALSE); + EnableWindow(GetDlgItem(hwndDlg, RB_PROXY_SOCKS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_HTTP_ADDRESS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_HTTP_PORT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_HTTP_ADDRESS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_HTTP_PORT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, CHECKB_PROXY_AUTH), TRUE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_SOCKS_ADDRESS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_SOCKS_PORT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_SOCKS_ADDRESS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_SOCKS_PORT), FALSE); + break; + } + + case RB_PROXY_USE_MANUAL: + if (HIWORD(wParam) == BN_CLICKED) + { + EnableWindow(GetDlgItem(hwndDlg, RB_PROXY_HTTP), TRUE); + EnableWindow(GetDlgItem(hwndDlg, RB_PROXY_SOCKS), TRUE); + + if (IsDlgButtonChecked(hwndDlg, RB_PROXY_HTTP) == BST_CHECKED) + { + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_HTTP_ADDRESS), TRUE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_HTTP_PORT), TRUE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_HTTP_ADDRESS), TRUE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_HTTP_PORT), TRUE); + EnableWindow(GetDlgItem(hwndDlg, CHECKB_PROXY_AUTH), TRUE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_SOCKS_ADDRESS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_SOCKS_PORT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_SOCKS_ADDRESS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_SOCKS_PORT), FALSE); + } + else + { + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_HTTP_ADDRESS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_HTTP_PORT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_HTTP_ADDRESS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_HTTP_PORT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, CHECKB_PROXY_AUTH), FALSE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_SOCKS_ADDRESS), TRUE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_SOCKS_PORT), TRUE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_SOCKS_ADDRESS), TRUE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_SOCKS_PORT), TRUE); + } + break; + } + + case RB_PROXY_HTTP: + if (HIWORD(wParam) == BN_CLICKED) + { + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_HTTP_ADDRESS), TRUE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_HTTP_PORT), TRUE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_HTTP_ADDRESS), TRUE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_HTTP_PORT), TRUE); + EnableWindow(GetDlgItem(hwndDlg, CHECKB_PROXY_AUTH), TRUE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_SOCKS_ADDRESS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_SOCKS_PORT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_SOCKS_ADDRESS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_SOCKS_PORT), FALSE); + break; + } + + case RB_PROXY_SOCKS: + if (HIWORD(wParam) == BN_CLICKED) + { + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_HTTP_ADDRESS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_HTTP_PORT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_HTTP_ADDRESS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_HTTP_PORT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, CHECKB_PROXY_AUTH), FALSE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_SOCKS_ADDRESS), TRUE); + EnableWindow(GetDlgItem(hwndDlg, EDIT_PROXY_SOCKS_PORT), TRUE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_SOCKS_ADDRESS), TRUE); + EnableWindow(GetDlgItem(hwndDlg, TEXT_PROXY_SOCKS_PORT), TRUE); + break; + } + } + break; + case WM_CLOSE: + EndDialog(hwndDlg, LOWORD(wParam)); + return TRUE; + + } + return FALSE; +} + +/* Check that proxy settings are valid */ +int CheckProxySettings(HWND hwndDlg) +{ + char text[100]; + long port; + + if (IsDlgButtonChecked(hwndDlg, RB_PROXY_USE_MANUAL) == BST_CHECKED) + { + if (IsDlgButtonChecked(hwndDlg, RB_PROXY_HTTP) == BST_CHECKED) + { + GetDlgItemText(hwndDlg, EDIT_PROXY_HTTP_ADDRESS, text, sizeof(text)); + if (strlen(text) == 0) + { + /* http_proxy_access not specified */ + ShowLocalizedMsg(GUI_NAME, ERR_HTTP_PROXY_ADDRESS, ""); + return(0); + } + GetDlgItemText(hwndDlg, EDIT_PROXY_HTTP_PORT, text, sizeof(text)); + if (strlen(text) == 0) + { + /* http_proxy_port not specified */ + ShowLocalizedMsg(GUI_NAME, ERR_HTTP_PROXY_PORT, ""); + return(0); + } + else + { + port=strtol(text, NULL, 10); + if ((port < 1) || (port > 65535)) + { + /* http_proxy_port range error */ + ShowLocalizedMsg(GUI_NAME, ERR_HTTP_PROXY_PORT_RANGE, ""); + return(0); + } + } + } + + if (IsDlgButtonChecked(hwndDlg, RB_PROXY_SOCKS) == BST_CHECKED) + { + GetDlgItemText(hwndDlg, EDIT_PROXY_SOCKS_ADDRESS, text, sizeof(text)); + if (strlen(text) == 0) + { + /* socks_proxy_address not specified */ + ShowLocalizedMsg(GUI_NAME, ERR_SOCKS_PROXY_ADDRESS, ""); + return(0); + } + GetDlgItemText(hwndDlg, EDIT_PROXY_SOCKS_PORT, text, sizeof(text)); + if (strlen(text) == 0) + { + /* socks_proxy_port not specified */ + ShowLocalizedMsg(GUI_NAME, ERR_SOCKS_PROXY_PORT, ""); + return(0); + } + else + { + port=strtol(text, NULL, 10); + if ((port < 1) || (port > 65535)) + { + /* socks_proxy_port range error */ + ShowLocalizedMsg(GUI_NAME, ERR_SOCKS_PROXY_PORT_RANGE, ""); + return(0); + } + } + } + } + return(1); +} + +void LoadProxySettings(HWND hwndDlg) +{ + + /* Disable IE Settings untill this is implemented */ + // EnableWindow(GetDlgItem(hwndDlg, RB_PROXY_USE_IE), FALSE); + + /* Set Proxy Type */ + if (o.proxy_type == 0) /* HTTP Proxy */ + { + CheckRadioButton(hwndDlg, + RB_PROXY_HTTP, /* First button in group */ + RB_PROXY_SOCKS, /* Last button in group */ + RB_PROXY_HTTP); /* Select this button */ + } + else /* SOCKS Proxy */ + { + CheckRadioButton(hwndDlg, + RB_PROXY_HTTP, /* First button in group */ + RB_PROXY_SOCKS, /* Last button in group */ + RB_PROXY_SOCKS); /* Select this button */ + } + + /* Set Proxy Settings Source */ + if (o.proxy_source == 0) + SendMessage(GetDlgItem(hwndDlg, RB_PROXY_USE_OPENVPN), BM_CLICK, 0, 0); + if (o.proxy_source == 1) + SendMessage(GetDlgItem(hwndDlg, RB_PROXY_USE_IE), BM_CLICK, 0, 0); + if (o.proxy_source == 2) + SendMessage(GetDlgItem(hwndDlg, RB_PROXY_USE_MANUAL), BM_CLICK, 0, 0); + + /* Set Proxy addresses and ports */ + SetDlgItemText(hwndDlg, EDIT_PROXY_HTTP_ADDRESS, o.proxy_http_address); + SetDlgItemText(hwndDlg, EDIT_PROXY_HTTP_PORT, o.proxy_http_port); + SetDlgItemText(hwndDlg, EDIT_PROXY_SOCKS_ADDRESS, o.proxy_socks_address); + SetDlgItemText(hwndDlg, EDIT_PROXY_SOCKS_PORT, o.proxy_socks_port); + if (o.proxy_http_auth) CheckDlgButton(hwndDlg, CHECKB_PROXY_AUTH, BST_CHECKED); +} + +void SaveProxySettings(HWND hwndDlg) +{ + + LONG status; + HKEY regkey; + DWORD dwDispos; + char proxy_source_string[2]="0"; + char proxy_type_string[2]="0"; + char proxy_http_auth_string[2]="0"; + + /* Save Proxy Settings Source */ + if (IsDlgButtonChecked(hwndDlg, RB_PROXY_USE_OPENVPN) == BST_CHECKED) + { + o.proxy_source = 0; + proxy_source_string[0] = '0'; + } + if (IsDlgButtonChecked(hwndDlg, RB_PROXY_USE_IE) == BST_CHECKED) + { + o.proxy_source = 1; + proxy_source_string[0] = '1'; + } + if (IsDlgButtonChecked(hwndDlg, RB_PROXY_USE_MANUAL) == BST_CHECKED) + { + o.proxy_source = 2; + proxy_source_string[0] = '2'; + } + + /* Save Proxy addresses and ports */ + GetDlgItemText(hwndDlg, EDIT_PROXY_HTTP_ADDRESS, o.proxy_http_address, + sizeof(o.proxy_http_address)); + GetDlgItemText(hwndDlg, EDIT_PROXY_HTTP_PORT, o.proxy_http_port, + sizeof(o.proxy_http_port)); + GetDlgItemText(hwndDlg, EDIT_PROXY_SOCKS_ADDRESS, o.proxy_socks_address, + sizeof(o.proxy_http_address)); + GetDlgItemText(hwndDlg, EDIT_PROXY_SOCKS_PORT, o.proxy_socks_port, + sizeof(o.proxy_socks_port)); + + if (IsDlgButtonChecked(hwndDlg, RB_PROXY_HTTP) == BST_CHECKED) + { + o.proxy_type = 0; + proxy_type_string[0] = '0'; + } + else + { + o.proxy_type = 1; + proxy_type_string[0] = '1'; + } + + if (IsDlgButtonChecked(hwndDlg, CHECKB_PROXY_AUTH) == BST_CHECKED) + { + o.proxy_http_auth = 1; + proxy_http_auth_string[0] = '1'; + } + else + { + o.proxy_http_auth = 0; + proxy_http_auth_string[0] = '0'; + } + + /* Open Registry for writing */ + if (RegCreateKeyEx(HKEY_CURRENT_USER, + GUI_REGKEY_HKCU, + 0, + (LPTSTR) "", + REG_OPTION_NON_VOLATILE, + KEY_WRITE, + NULL, + ®key, + &dwDispos) != ERROR_SUCCESS) + { + /* error creating Registry-Key */ + ShowLocalizedMsg(GUI_NAME, ERR_CREATE_REG_HKCU_KEY, GUI_REGKEY_HKCU); + return; + } + + /* Save Settings to registry */ + SetRegistryValue(regkey, "proxy_source", proxy_source_string); + SetRegistryValue(regkey, "proxy_type", proxy_type_string); + SetRegistryValue(regkey, "proxy_http_auth", proxy_http_auth_string); + SetRegistryValue(regkey, "proxy_http_address", o.proxy_http_address); + SetRegistryValue(regkey, "proxy_http_port", o.proxy_http_port); + SetRegistryValue(regkey, "proxy_socks_address", o.proxy_socks_address); + SetRegistryValue(regkey, "proxy_socks_port", o.proxy_socks_port); + + RegCloseKey(regkey); + +} + +void GetProxyRegistrySettings() +{ + LONG status; + HKEY regkey; + char proxy_source_string[2]="0"; + char proxy_type_string[2]="0"; + char proxy_http_auth_string[2]="0"; + char temp_path[100]; + + /* Construct Authfile path */ + if (!GetTempPath(sizeof(temp_path) - 1, temp_path)) + { + /* Error getting TempPath - using C:\ */ + ShowLocalizedMsg(GUI_NAME, ERR_GET_TEMP_PATH, ""); + strcpy(temp_path, "C:\\"); + } + strncat(temp_path, "openvpn_authfile.txt", + sizeof(temp_path) - strlen(temp_path) - 1); + strncpy(o.proxy_authfile, temp_path, sizeof(o.proxy_authfile)); + + /* Open Registry for reading */ + status = RegOpenKeyEx(HKEY_CURRENT_USER, + GUI_REGKEY_HKCU, + 0, + KEY_READ, + ®key); + + /* Return if can't open the registry key */ + if (status != ERROR_SUCCESS) return; + + + /* get registry settings */ + GetRegistryValue(regkey, "proxy_http_address", o.proxy_http_address, + sizeof(o.proxy_http_address)); + GetRegistryValue(regkey, "proxy_http_port", o.proxy_http_port, + sizeof(o.proxy_http_port)); + GetRegistryValue(regkey, "proxy_socks_address", o.proxy_socks_address, + sizeof(o.proxy_socks_address)); + GetRegistryValue(regkey, "proxy_socks_port", o.proxy_socks_port, + sizeof(o.proxy_socks_port)); + GetRegistryValue(regkey, "proxy_source", proxy_source_string, + sizeof(proxy_source_string)); + GetRegistryValue(regkey, "proxy_type", proxy_type_string, + sizeof(proxy_type_string)); + GetRegistryValue(regkey, "proxy_http_auth", proxy_http_auth_string, + sizeof(proxy_http_auth_string)); + + if (proxy_source_string[0] == '1') + o.proxy_source=1; + if (proxy_source_string[0] == '2') + o.proxy_source=2; + if (proxy_source_string[0] == '3') + o.proxy_source=3; + + if (proxy_type_string[0] == '1') + o.proxy_type=1; + + if (proxy_http_auth_string[0] == '1') + o.proxy_http_auth=1; + + RegCloseKey(regkey); + return; +} + +BOOL CALLBACK ProxyAuthDialogFunc (HWND hwndDlg, UINT msg, WPARAM wParam, UNUSED LPARAM lParam) +{ + char username[50]; + char password[50]; + FILE *fp; + + switch (msg) { + + case WM_INITDIALOG: + //SetForegroundWindow(hwndDlg); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + + case IDOK: + GetDlgItemText(hwndDlg, EDIT_PROXY_USERNAME, username, sizeof(username) - 1); + GetDlgItemText(hwndDlg, EDIT_PROXY_PASSWORD, password, sizeof(password) - 1); + if (!(fp = fopen(o.proxy_authfile, "w"))) + { + /* error creating AUTH file */ + ShowLocalizedMsg(GUI_NAME, ERR_CREATE_AUTH_FILE, o.proxy_authfile); + EndDialog(hwndDlg, LOWORD(wParam)); + } + fputs(username, fp); + fputs("\n", fp); + fputs(password, fp); + fputs("\n", fp); + fclose(fp); + EndDialog(hwndDlg, LOWORD(wParam)); + return TRUE; + } + break; + case WM_CLOSE: + EndDialog(hwndDlg, LOWORD(wParam)); + return TRUE; + + } + return FALSE; +} + +/* + * Construct the proxy options to append to the cmd-line. + */ +void ConstructProxyCmdLine(char *proxy_string_ptr, unsigned int size) +{ + char proxy_string[100]; + + CLEAR(proxy_string); + + if (o.proxy_source == PROXY_SOURCE_MANUAL) + { + if (o.proxy_type == PROXY_TYPE_HTTP) + { + if (o.proxy_http_auth == PROXY_HTTP_ASK_AUTH) + { + /* Ask for Proxy username/password */ + DialogBox(o.hInstance, (LPCTSTR)IDD_PROXY_AUTH, NULL, (DLGPROC)ProxyAuthDialogFunc); + mysnprintf(proxy_string, "--http-proxy %s %s %s", + o.proxy_http_address, + o.proxy_http_port, + o.proxy_authfile); + } + else + { + mysnprintf(proxy_string, "--http-proxy %s %s", + o.proxy_http_address, + o.proxy_http_port); + } + } + if (o.proxy_type == PROXY_TYPE_SOCKS) + { + mysnprintf(proxy_string, "--socks-proxy %s %s", + o.proxy_socks_address, + o.proxy_socks_port); + } + } + + if (o.proxy_source == PROXY_SOURCE_IE) + { + LPCTSTR ieproxy; + char *pos; + + ieproxy = getIeHttpProxy(); + if (!ieproxy) + { + /* can't get ie proxy settings */ + ShowLocalizedMsg(GUI_NAME, ERR_GET_IE_PROXY_SETTINGS, getIeHttpProxyError); + } + else + { + /* Don't use a proxy if IE proxy string is empty */ + if (strlen(ieproxy) > 1) + { + /* Parse the port number from the IE proxy string */ + if ((pos = strchr(ieproxy, ':'))) + { + *pos = '\0'; + if (o.proxy_http_auth == PROXY_HTTP_ASK_AUTH) + { + /* Ask for Proxy username/password */ + DialogBox(o.hInstance, (LPCTSTR)IDD_PROXY_AUTH, NULL, (DLGPROC)ProxyAuthDialogFunc); + mysnprintf(proxy_string, "--http-proxy %s %s %s", + ieproxy, pos+1, o.proxy_authfile) + } + else + { + mysnprintf(proxy_string, "--http-proxy %s %s", ieproxy, pos+1) + } + } + /* No port is specified, use 80 as default port */ + else + { + if (o.proxy_http_auth == PROXY_HTTP_ASK_AUTH) + { + /* Ask for Proxy username/password */ + DialogBox(o.hInstance, (LPCTSTR)IDD_PROXY_AUTH, NULL, (DLGPROC)ProxyAuthDialogFunc); + mysnprintf(proxy_string, "--http-proxy %s 80 %s", + ieproxy, o.proxy_authfile) + } + else + { + mysnprintf(proxy_string, "--http-proxy %s 80", ieproxy) + } + } + } + //free (ieproxy); + } + } + + strncpy(proxy_string_ptr, proxy_string, size); +} diff --git a/proxy.h b/proxy.h new file mode 100644 index 0000000..3a1e811 --- /dev/null +++ b/proxy.h @@ -0,0 +1,37 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define PROXY_SOURCE_OPENVPN 0 +#define PROXY_SOURCE_IE 1 +#define PROXY_SOURCE_MANUAL 2 +#define PROXY_TYPE_HTTP 0 +#define PROXY_TYPE_SOCKS 1 +#define PROXY_HTTP_NO_AUTH 0 +#define PROXY_HTTP_ASK_AUTH 1 + +void ShowProxySettingsDialog(); +BOOL CALLBACK ProxySettingsDialogFunc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +int CheckProxySettings(HWND hwndDlg); +void LoadProxySettings(HWND hwndDlg); +void SaveProxySettings(HWND hwndDlg); +void GetProxyRegistrySettings(); +BOOL CALLBACK ProxyAuthDialogFunc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +void ConstructProxyCmdLine(char *proxy_string_ptr, unsigned int size); diff --git a/reconnecting.ico b/reconnecting.ico new file mode 100644 index 0000000000000000000000000000000000000000..bf0f6160da4a2485e59f5373273c6f65df1d466c GIT binary patch literal 1406 zcmeH{OGs2<7=|AktuZUD%*s4vrlXc=nrUWc7t_qtyrh|zoQN<-GlU>h#D!F229c;O zx(Go~A#EbcHnz}>N+E4TG+PF(oJ~P6y=QQuAX>KaJ-p}t?*I9|!~cVio}eJ~wo>N@ zAwY~M6XBw1{}v?oR5R^)$3MQvAG# zK6f9fUov4pm2ZM06nboNWOdiVV+*(;r2!Jo!-E7ER+v=oIvl2pyb>@j!FS1z#5YO7 z3X~A2l3lm>=yWn_x6|urWI|?FS`qo~CU`9+K=u0jnHwHvYGi~DlE+(HX}{V`P8QrN zhle)E_>nI`@tvZE;c~f{pP%Q`>@3sD9UmAV`g$z(ud4e3qUxZyOtHOUhj<%irl$Bj zH^=nkBr_8ej0_I)va1W8%KuDkgLW$R? z4VRm_*w}=+He2@mD=mvyoWOscK#kREJqxw=b9Qs*coSvirz_4>R#sJ$cr5pL-iiEz z!jnbCC8eiGOy8ezAoJj%!$*v)quDu;#3$@ZOxm5i$1qY-_onS5%4V}g#~4EF_8oCM z{rpXY8Jo8l;aelNMfxrEAb4HK`VAXHH?g4mu3Qxuw0h0jU%J2l@_-e(w!D5b%l9w( y62W4z_47&%%DWpn>OK-o3LOhHWsl9Y>pJ_L-=uq}dOrd7Tab?c literal 0 HcmV?d00001 diff --git a/registry.c b/registry.c new file mode 100644 index 0000000..6af47a6 --- /dev/null +++ b/registry.c @@ -0,0 +1,272 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + +#include +#include +#include "main.h" +#include "options.h" +#include "openvpn-gui-res.h" +#include "registry.h" + +extern struct options o; + +int +GetRegistryKeys() +{ + char windows_dir[MAX_PATH]; + char temp_path[MAX_PATH]; + char openvpn_path[MAX_PATH]; + HKEY regkey; + + if (!GetWindowsDirectory(windows_dir, sizeof(windows_dir))) { + /* can't get windows dir */ + ShowLocalizedMsg(GUI_NAME, ERR_GET_WINDOWS_DIR, ""); + return(false); + } + + /* Get path to OpenVPN installation. */ + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenVPN", 0, KEY_READ, ®key) + != ERROR_SUCCESS) + { + /* registry key not found */ + ShowLocalizedMsg(GUI_NAME, ERR_OPEN_REGISTRY, ""); + return(false); + } + if (!GetRegistryValue(regkey, "", openvpn_path, sizeof(openvpn_path))) + { + /* error reading registry value */ + ShowLocalizedMsg(GUI_NAME, ERR_READING_REGISTRY, ""); + return(false); + } + if(openvpn_path[strlen(openvpn_path) - 1] != '\\') + strcat(openvpn_path, "\\"); + + + mysnprintf(temp_path, "%sconfig", openvpn_path); + if (!GetRegKey("config_dir", o.config_dir, + temp_path, sizeof(o.config_dir))) return(false); + + if (!GetRegKey("config_ext", o.ext_string, "ovpn", sizeof(o.ext_string))) return(false); + + mysnprintf(temp_path, "%sbin\\openvpn.exe", openvpn_path); + if (!GetRegKey("exe_path", o.exe_path, + temp_path, sizeof(o.exe_path))) return(false); + + mysnprintf(temp_path, "%slog", openvpn_path); + if (!GetRegKey("log_dir", o.log_dir, + temp_path, sizeof(o.log_dir))) return(false); + + if (!GetRegKey("log_append", o.append_string, "0", sizeof(o.append_string))) return(false); + + if (!GetRegKey("priority", o.priority_string, + "NORMAL_PRIORITY_CLASS", sizeof(o.priority_string))) return(false); + + mysnprintf(temp_path, "%s\\notepad.exe", windows_dir); + if (!GetRegKey("log_viewer", o.log_viewer, + temp_path, sizeof(o.log_viewer))) return(false); + + mysnprintf(temp_path, "%s\\notepad.exe", windows_dir); + if (!GetRegKey("editor", o.editor, + temp_path, sizeof(o.editor))) return(false); + + if (!GetRegKey("allow_edit", o.allow_edit, "1", sizeof(o.allow_edit))) return(false); + + if (!GetRegKey("allow_service", o.allow_service, "0", sizeof(o.allow_service))) return(false); + + if (!GetRegKey("allow_password", o.allow_password, "1", sizeof(o.allow_password))) return(false); + + if (!GetRegKey("allow_proxy", o.allow_proxy, "1", sizeof(o.allow_proxy))) return(false); + + if (!GetRegKey("service_only", o.service_only, "0", sizeof(o.service_only))) return(false); + + if (!GetRegKey("show_balloon", o.show_balloon, "1", sizeof(o.show_balloon))) return(false); + + if (!GetRegKey("silent_connection", o.silent_connection, "0", sizeof(o.silent_connection))) return(false); + + if (!GetRegKey("show_script_window", o.show_script_window, "1", sizeof(o.show_script_window))) return(false); + + if (!GetRegKey("disconnect_on_suspend", o.disconnect_on_suspend, "1", + sizeof(o.disconnect_on_suspend))) return(false); + + if (!GetRegKey("passphrase_attempts", o.psw_attempts_string, "3", + sizeof(o.psw_attempts_string))) return(false); + o.psw_attempts = atoi(o.psw_attempts_string); + if ((o.psw_attempts < 1) || (o.psw_attempts > 9)) + { + /* 0 <= passphrase_attempts <= 9 */ + ShowLocalizedMsg(GUI_NAME, ERR_PASSPHRASE_ATTEMPTS, ""); + return(false); + } + + if (!GetRegKey("connectscript_timeout", o.connectscript_timeout_string, "15", + sizeof(o.connectscript_timeout_string))) return(false); + o.connectscript_timeout = atoi(o.connectscript_timeout_string); + if ((o.connectscript_timeout < 0) || (o.connectscript_timeout > 99)) + { + /* 0 <= connectscript_timeout <= 99 */ + ShowLocalizedMsg(GUI_NAME, ERR_CONN_SCRIPT_TIMEOUT, ""); + return(false); + } + + if (!GetRegKey("disconnectscript_timeout", o.disconnectscript_timeout_string, "10", + sizeof(o.disconnectscript_timeout_string))) return(false); + o.disconnectscript_timeout = atoi(o.disconnectscript_timeout_string); + if ((o.disconnectscript_timeout <= 0) || (o.disconnectscript_timeout > 99)) + { + /* 0 < disconnectscript_timeout <= 99 */ + ShowLocalizedMsg(GUI_NAME, ERR_DISCONN_SCRIPT_TIMEOUT, ""); + return(false); + } + + if (!GetRegKey("preconnectscript_timeout", o.preconnectscript_timeout_string, "10", + sizeof(o.preconnectscript_timeout_string))) return(false); + o.preconnectscript_timeout = atoi(o.preconnectscript_timeout_string); + if ((o.preconnectscript_timeout <= 0) || (o.preconnectscript_timeout > 99)) + { + /* 0 < disconnectscript_timeout <= 99 */ + ShowLocalizedMsg(GUI_NAME, ERR_PRECONN_SCRIPT_TIMEOUT, ""); + return(false); + } + + return(true); +} + + +int GetRegKey(const char name[], char *data, const char default_data[], DWORD len) +{ + LONG status; + DWORD type; + HKEY openvpn_key; + HKEY openvpn_key_write; + DWORD dwDispos; + char expanded_string[MAX_PATH]; + DWORD max_len; + + /* Save maximum string length */ + max_len=len; + + /* If option is already set via cmd-line, return */ + if (data[0] != 0) + { + // Expand environment variables inside the string. + ExpandEnvironmentStrings(data, expanded_string, sizeof(expanded_string)); + strncpy(data, expanded_string, max_len); + return(true); + } + + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + "SOFTWARE\\OpenVPN-GUI", + 0, + KEY_READ, + &openvpn_key); + + if (status != ERROR_SUCCESS) + { + if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, + "Software\\OpenVPN-GUI", + 0, + (LPTSTR) "", + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + NULL, + &openvpn_key, + &dwDispos) != ERROR_SUCCESS) + { + /* error creating registry key */ + ShowLocalizedMsg(GUI_NAME, ERR_CREATE_REG_KEY, ""); + return(false); + } + } + + + /* get a registry string */ + status = RegQueryValueEx(openvpn_key, name, NULL, &type, (byte *) data, &len); + if (status != ERROR_SUCCESS || type != REG_SZ) + { + /* key did not exist - set default value */ + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + "SOFTWARE\\OpenVPN-GUI", + 0, + KEY_READ | KEY_WRITE, + &openvpn_key_write); + + if (status != ERROR_SUCCESS) { + /* can't open registry for writing */ + ShowLocalizedMsg(GUI_NAME, ERR_OPEN_WRITE_REG, ""); + return(false); + } + if(RegSetValueEx(openvpn_key_write, + name, + 0, + REG_SZ, + default_data, + strlen(default_data)+1)) + { + /* cant read / set reg-key */ + ShowLocalizedMsg(GUI_NAME, ERR_READ_SET_KEY, name); + return(false); + } + strncpy(data, default_data, max_len); + RegCloseKey(openvpn_key_write); + + } + + RegCloseKey(openvpn_key); + + // Expand environment variables inside the string. + ExpandEnvironmentStrings(data, expanded_string, sizeof(expanded_string)); + strncpy(data, expanded_string, max_len); + + return(true); +} + +LONG GetRegistryValue(HKEY regkey, const char *name, char *data, DWORD len) +{ + LONG status; + DWORD type; + DWORD data_len; + + data_len = len; + + /* get a registry string */ + status = RegQueryValueEx(regkey, name, NULL, &type, (byte *) data, &data_len); + if (status != ERROR_SUCCESS || type != REG_SZ) + return(0); + + return(data_len); + +} + +int SetRegistryValue(HKEY regkey, const char *name, char *data) +{ + /* set a registry string */ + if(RegSetValueEx(regkey, name, 0, REG_SZ, data, strlen(data)+1) != ERROR_SUCCESS) + { + /* Error writing registry value */ + ShowLocalizedMsg(GUI_NAME, ERR_WRITE_REGVALUE, GUI_REGKEY_HKCU, name); + return(0); + } + + return(1); + +} diff --git a/registry.h b/registry.h new file mode 100644 index 0000000..d45a64f --- /dev/null +++ b/registry.h @@ -0,0 +1,27 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +int GetRegistryKeys(); +//int SetRegistryKeys(); +int GetRegKey(const char name[], char data[], const char default_data[], DWORD len); +LONG GetRegistryValue(HKEY regkey, const char *name, char *data, DWORD len); +int SetRegistryValue(HKEY regkey, const char *name, char *data); + diff --git a/scripts.c b/scripts.c new file mode 100644 index 0000000..85fd8e4 --- /dev/null +++ b/scripts.c @@ -0,0 +1,291 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +//#include +//#include +#include +#include "main.h" +#include "openvpn-gui-res.h" +#include "options.h" + +extern struct options o; + +void RunConnectScript(int config, int run_as_service) +{ + WIN32_FIND_DATA FindFileData; + HANDLE hFind; + STARTUPINFO start_info; + PROCESS_INFORMATION proc_info; + SECURITY_ATTRIBUTES sa; + SECURITY_DESCRIPTOR sd; + char command_line[256]; + char batch_file[100]; + DWORD ExitCode; + int i, TimeOut; + TCHAR buf[1000]; + + /* Cut of extention from config filename and add "_up.bat". */ + strncpy(batch_file, o.cnn[config].config_file, sizeof(batch_file)); + batch_file[strlen(batch_file) - (strlen(o.ext_string)+1)]=0; + strncat(batch_file, "_up.bat", sizeof(batch_file) - strlen(batch_file) - 1); + mysnprintf(command_line, "%s\\%s", o.cnn[config].config_dir, batch_file); + + + /* Return if no script exists */ + hFind = FindFirstFile(command_line, &FindFileData); + if (hFind == INVALID_HANDLE_VALUE) + { + return; + } + + FindClose(hFind); + + if (!run_as_service) + { + /* UserInfo: Connect Script running */ + myLoadString(INFO_STATE_CONN_SCRIPT); + SetDlgItemText(o.cnn[config].hwndStatus, TEXT_STATUS, buf); + } + + CLEAR (start_info); + CLEAR (proc_info); + CLEAR (sa); + CLEAR (sd); + + /* fill in STARTUPINFO struct */ + GetStartupInfo(&start_info); + start_info.cb = sizeof(start_info); + start_info.dwFlags = 0; + start_info.wShowWindow = SW_SHOWDEFAULT; + start_info.hStdInput = NULL; + start_info.hStdOutput = NULL; + + if (!CreateProcess(NULL, + command_line, //commandline + NULL, + NULL, + TRUE, + ((o.show_script_window[0] == '1') ? (DWORD) CREATE_NEW_CONSOLE : + (DWORD) CREATE_NO_WINDOW), + NULL, + o.cnn[config].config_dir, //start-up dir + &start_info, + &proc_info)) + { + /* Running Script failed */ + ShowLocalizedMsg(GUI_NAME, ERR_RUN_CONN_SCRIPT, command_line); + return; + } + + TimeOut = o.connectscript_timeout; + + if (TimeOut == 0) + { + /* Don't check exist status, just return */ + return; + } + + for (i=0; i <= TimeOut; i++) + { + if (!GetExitCodeProcess(proc_info.hProcess, &ExitCode)) + { + /* failed to get ExitCode */ + ShowLocalizedMsg(GUI_NAME, ERR_GET_EXIT_CODE, command_line); + return; + } + + if (ExitCode != STILL_ACTIVE) + { + if (ExitCode != 0) + { + /* ConnectScript failed */ + ShowLocalizedMsg(GUI_NAME, ERR_CONN_SCRIPT_FAILED, ExitCode); + return; + } + return; + } + + Sleep(1000); + } + + /* UserInfo: Timeout */ + ShowLocalizedMsg(GUI_NAME, ERR_RUN_CONN_SCRIPT_TIMEOUT, TimeOut); + +} + +void RunDisconnectScript(int config, int run_as_service) +{ + WIN32_FIND_DATA FindFileData; + HANDLE hFind; + STARTUPINFO start_info; + PROCESS_INFORMATION proc_info; + SECURITY_ATTRIBUTES sa; + SECURITY_DESCRIPTOR sd; + char command_line[256]; + char batch_file[100]; + DWORD ExitCode; + int i, TimeOut; + TCHAR buf[1000]; + + /* Append "_down.bat" to config name. */ + strncpy(batch_file, o.cnn[config].config_name, sizeof(batch_file)); + strncat(batch_file, "_down.bat", sizeof(batch_file) - strlen(batch_file) - 1); + mysnprintf(command_line, "%s\\%s", o.cnn[config].config_dir, batch_file); + + + /* Return if no script exists */ + hFind = FindFirstFile(command_line, &FindFileData); + if (hFind == INVALID_HANDLE_VALUE) + { + return; + } + + FindClose(hFind); + + if (!run_as_service) + { + /* UserInfo: Disconnect Script running */ + myLoadString(INFO_STATE_DISCONN_SCRIPT); + SetDlgItemText(o.cnn[config].hwndStatus, TEXT_STATUS, buf); + } + + CLEAR (start_info); + CLEAR (proc_info); + CLEAR (sa); + CLEAR (sd); + + /* fill in STARTUPINFO struct */ + GetStartupInfo(&start_info); + start_info.cb = sizeof(start_info); + start_info.dwFlags = 0; + start_info.wShowWindow = SW_SHOWDEFAULT; + start_info.hStdInput = NULL; + start_info.hStdOutput = NULL; + + if (!CreateProcess(NULL, + command_line, //commandline + NULL, + NULL, + TRUE, + ((o.show_script_window[0] == '1') ? (DWORD) CREATE_NEW_CONSOLE : + (DWORD) CREATE_NO_WINDOW), + NULL, + o.cnn[config].config_dir, //start-up dir + &start_info, + &proc_info)) + { + return; + } + + TimeOut = o.disconnectscript_timeout; + + for (i=0; i <= TimeOut; i++) + { + if (!GetExitCodeProcess(proc_info.hProcess, &ExitCode)) + { + return; + } + + if (ExitCode != STILL_ACTIVE) + { + return; + } + + Sleep(1000); + } +} + +void RunPreconnectScript(int config) +{ + WIN32_FIND_DATA FindFileData; + HANDLE hFind; + STARTUPINFO start_info; + PROCESS_INFORMATION proc_info; + SECURITY_ATTRIBUTES sa; + SECURITY_DESCRIPTOR sd; + char command_line[256]; + char batch_file[100]; + DWORD ExitCode; + int i, TimeOut; + TCHAR buf[1000]; + + /* Append "_pre.bat" to config name. */ + strncpy(batch_file, o.cnn[config].config_name, sizeof(batch_file)); + strncat(batch_file, "_pre.bat", sizeof(batch_file) - strlen(batch_file) - 1); + mysnprintf(command_line, "%s\\%s", o.cnn[config].config_dir, batch_file); + + + /* Return if no script exists */ + hFind = FindFirstFile(command_line, &FindFileData); + if (hFind == INVALID_HANDLE_VALUE) + { + return; + } + + FindClose(hFind); + + CLEAR (start_info); + CLEAR (proc_info); + CLEAR (sa); + CLEAR (sd); + + /* fill in STARTUPINFO struct */ + GetStartupInfo(&start_info); + start_info.cb = sizeof(start_info); + start_info.dwFlags = 0; + start_info.wShowWindow = SW_SHOWDEFAULT; + start_info.hStdInput = NULL; + start_info.hStdOutput = NULL; + + if (!CreateProcess(NULL, + command_line, //commandline + NULL, + NULL, + TRUE, + ((o.show_script_window[0] == '1') ? (DWORD) CREATE_NEW_CONSOLE : + (DWORD) CREATE_NO_WINDOW), + NULL, + o.cnn[config].config_dir, //start-up dir + &start_info, + &proc_info)) + { + return; + } + + TimeOut = o.preconnectscript_timeout; + + for (i=0; i <= TimeOut; i++) + { + if (!GetExitCodeProcess(proc_info.hProcess, &ExitCode)) + { + return; + } + + if (ExitCode != STILL_ACTIVE) + { + return; + } + + Sleep(1000); + } +} + diff --git a/scripts.h b/scripts.h new file mode 100644 index 0000000..05fc2af --- /dev/null +++ b/scripts.h @@ -0,0 +1,24 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +void RunConnectScript(int config, int run_as_service); +void RunDisconnectScript(int config, int run_as_service); +void RunPreconnectScript(int config); diff --git a/service.c b/service.c new file mode 100644 index 0000000..b3cad20 --- /dev/null +++ b/service.c @@ -0,0 +1,304 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "tray.h" +#include "service.h" +#include "openvpn.h" +#include "options.h" +#include "scripts.h" +#include "main.h" +#include +#include "openvpn-gui-res.h" + +extern struct options o; + +int MyStartService() +{ + + SC_HANDLE schSCManager; + SC_HANDLE schService; + SERVICE_STATUS ssStatus; + DWORD dwOldCheckPoint; + DWORD dwStartTickCount; + DWORD dwWaitTime; + char msg[200]; + TCHAR buf[1000]; + int i; + + /* Set Service Status = Connecting */ + o.service_running = SERVICE_CONNECTING; + SetServiceMenuStatus(); + CheckAndSetTrayIcon(); + + // Open a handle to the SC Manager database. + schSCManager = OpenSCManager( + NULL, // local machine + NULL, // ServicesActive database + SC_MANAGER_CONNECT); // Connect rights + + if (NULL == schSCManager) { + /* open SC manager failed */ + ShowLocalizedMsg(GUI_NAME, ERR_OPEN_SCMGR, ""); + goto failed; + } + + schService = OpenService( + schSCManager, // SCM database + "OpenVPNService", // service name + SERVICE_START | SERVICE_QUERY_STATUS); + + if (schService == NULL) { + /* can't open VPN service */ + ShowLocalizedMsg(GUI_NAME, ERR_OPEN_VPN_SERVICE, ""); + goto failed; + } + + /* Run Pre-connect script */ + for (i=0; i 5000 ) + dwWaitTime = 5000; + + Sleep( dwWaitTime ); + + // Check the status again. + if (!QueryServiceStatus( + schService, // handle to service + &ssStatus) ) // address of structure + break; + + if ( ssStatus.dwCheckPoint > dwOldCheckPoint ) + { + // The service is making progress. + dwStartTickCount = GetTickCount(); + dwOldCheckPoint = ssStatus.dwCheckPoint; + } + else + { + if(GetTickCount()-dwStartTickCount > ssStatus.dwWaitHint) + { + // No progress made within the wait hint + break; + } + } + } + + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); + + if (ssStatus.dwCurrentState != SERVICE_RUNNING) + { + /* service hasn't started */ + ShowLocalizedMsg(GUI_NAME, ERR_SERVICE_START_FAILED, ""); + goto failed; + } + + /* Run Connect script */ + for (i=0; i + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +int MyStartService(); +int MyStopService(); +int MyReStartService(); +int CheckServiceStatus(); diff --git a/shellapi.h b/shellapi.h new file mode 100644 index 0000000..8dbd7b1 --- /dev/null +++ b/shellapi.h @@ -0,0 +1,326 @@ +#ifndef _SHELLAPI_H +#define _SHELLAPI_H +#if __GNUC__ >= 3 +#pragma GCC system_header +#endif + +#ifdef __cplusplus +extern "C" { +#endif +#define WINSHELLAPI DECLSPEC_IMPORT +#define ABE_LEFT 0 +#define ABE_TOP 1 +#define ABE_RIGHT 2 +#define ABE_BOTTOM 3 +#define ABS_AUTOHIDE 1 +#define ABS_ALWAYSONTOP 2 +#define SEE_MASK_CLASSNAME 1 +#define SEE_MASK_CLASSKEY 3 +#define SEE_MASK_IDLIST 4 +#define SEE_MASK_INVOKEIDLIST 12 +#define SEE_MASK_ICON 0x10 +#define SEE_MASK_HOTKEY 0x20 +#define SEE_MASK_NOCLOSEPROCESS 0x40 +#define SEE_MASK_CONNECTNETDRV 0x80 +#define SEE_MASK_FLAG_DDEWAIT 0x100 +#define SEE_MASK_DOENVSUBST 0x200 +#define SEE_MASK_FLAG_NO_UI 0x400 +#define SEE_MASK_NO_CONSOLE 0x8000 +#define SEE_MASK_UNICODE 0x10000 +#define SEE_MASK_ASYNCOK 0x100000 +#define SEE_MASK_HMONITOR 0x200000 +#define ABM_NEW 0 +#define ABM_REMOVE 1 +#define ABM_QUERYPOS 2 +#define ABM_SETPOS 3 +#define ABM_GETSTATE 4 +#define ABM_GETTASKBARPOS 5 +#define ABM_ACTIVATE 6 +#define ABM_GETAUTOHIDEBAR 7 +#define ABM_SETAUTOHIDEBAR 8 +#define ABM_WINDOWPOSCHANGED 9 +#define ABN_STATECHANGE 0 +#define ABN_POSCHANGED 1 +#define ABN_FULLSCREENAPP 2 +#define ABN_WINDOWARRANGE 3 +#define NIM_ADD 0 +#define NIM_MODIFY 1 +#define NIM_DELETE 2 +#if _WIN32_IE >= 0x0500 +#define NOTIFYICON_VERSION 3 +#define NIM_SETFOCUS 3 +#define NIM_SETVERSION 4 +#endif +#define NIF_MESSAGE 1 +#define NIF_ICON 2 +#define NIF_TIP 4 +#define NIF_STATE 8 +#define NIS_HIDDEN 1 +#define NIS_SHAREDICON 2 +#define SE_ERR_FNF 2 +#define SE_ERR_PNF 3 +#define SE_ERR_ACCESSDENIED 5 +#define SE_ERR_OOM 8 +#define SE_ERR_DLLNOTFOUND 32 +#define SE_ERR_SHARE 26 +#define SE_ERR_ASSOCINCOMPLETE 27 +#define SE_ERR_DDETIMEOUT 28 +#define SE_ERR_DDEFAIL 29 +#define SE_ERR_DDEBUSY 30 +#define SE_ERR_NOASSOC 31 +#define FO_MOVE 1 +#define FO_COPY 2 +#define FO_DELETE 3 +#define FO_RENAME 4 +#define FOF_MULTIDESTFILES 1 +#define FOF_CONFIRMMOUSE 2 +#define FOF_SILENT 4 +#define FOF_RENAMEONCOLLISION 8 +#define FOF_NOCONFIRMATION 16 +#define FOF_WANTMAPPINGHANDLE 32 +#define FOF_ALLOWUNDO 64 +#define FOF_FILESONLY 128 +#define FOF_SIMPLEPROGRESS 256 +#define FOF_NOCONFIRMMKDIR 512 +#define FOF_NOERRORUI 1024 +#define FOF_NOCOPYSECURITYATTRIBS 2048 +#define PO_DELETE 19 +#define PO_RENAME 20 +#define PO_PORTCHANGE 32 +#define PO_REN_PORT 52 +#define SHGFI_ICON 256 +#define SHGFI_DISPLAYNAME 512 +#define SHGFI_TYPENAME 1024 +#define SHGFI_ATTRIBUTES 2048 +#define SHGFI_ICONLOCATION 4096 +#define SHGFI_EXETYPE 8192 +#define SHGFI_SYSICONINDEX 16384 +#define SHGFI_LINKOVERLAY 32768 +#define SHGFI_SELECTED 65536 +#define SHGFI_ATTR_SPECIFIED 131072 +#define SHGFI_LARGEICON 0 +#define SHGFI_SMALLICON 1 +#define SHGFI_OPENICON 2 +#define SHGFI_SHELLICONSIZE 4 +#define SHGFI_PIDL 8 +#define SHGFI_USEFILEATTRIBUTES 16 +#define SHERB_NOCONFIRMATION 1 +#define SHERB_NOPROGRESSUI 2 +#define SHERB_NOSOUND 4 + +typedef WORD FILEOP_FLAGS; +typedef WORD PRINTEROP_FLAGS; +#include +typedef struct _AppBarData { + DWORD cbSize; + HWND hWnd; + UINT uCallbackMessage; + UINT uEdge; + RECT rc; + LPARAM lParam; +} APPBARDATA,*PAPPBARDATA; +DECLARE_HANDLE(HDROP); + +typedef struct _NOTIFYICONDATAA { + DWORD cbSize; + HWND hWnd; + UINT uID; + UINT uFlags; + UINT uCallbackMessage; + HICON hIcon; +#if _WIN32_IE >= 0x0500 + CHAR szTip[128]; + DWORD dwState; + DWORD dwStateMask; + CHAR szInfo[256]; + _ANONYMOUS_UNION union { + UINT uTimeout; + UINT uVersion; + } DUMMYUNIONNAME; + CHAR szInfoTitle[64]; + DWORD dwInfoFlags; +#else + CHAR szTip[64]; +#endif +#if _WIN32_IE >= 0x600 + GUID guidItem; +#endif +} NOTIFYICONDATAA,*PNOTIFYICONDATAA; + +typedef struct _NOTIFYICONDATAW { + DWORD cbSize; + HWND hWnd; + UINT uID; + UINT uFlags; + UINT uCallbackMessage; + HICON hIcon; +#if _WIN32_IE >= 0x0500 + WCHAR szTip[128]; + DWORD dwState; + DWORD dwStateMask; + WCHAR szInfo[256]; + _ANONYMOUS_UNION union { + UINT uTimeout; + UINT uVersion; + } DUMMYUNIONNAME; + WCHAR szInfoTitle[64]; + DWORD dwInfoFlags; +#else + WCHAR szTip[64]; +#endif +#if _WIN32_IE >= 0x600 + GUID guidItem; +#endif +} NOTIFYICONDATAW,*PNOTIFYICONDATAW; + +typedef struct _SHELLEXECUTEINFOA { + DWORD cbSize; + ULONG fMask; + HWND hwnd; + LPCSTR lpVerb; + LPCSTR lpFile; + LPCSTR lpParameters; + LPCSTR lpDirectory; + int nShow; + HINSTANCE hInstApp; + PVOID lpIDList; + LPCSTR lpClass; + HKEY hkeyClass; + DWORD dwHotKey; + HANDLE hIcon; + HANDLE hProcess; +} SHELLEXECUTEINFOA,*LPSHELLEXECUTEINFOA; +typedef struct _SHELLEXECUTEINFOW { + DWORD cbSize; + ULONG fMask; + HWND hwnd; + LPCWSTR lpVerb; + LPCWSTR lpFile; + LPCWSTR lpParameters; + LPCWSTR lpDirectory; + int nShow; + HINSTANCE hInstApp; + PVOID lpIDList; + LPCWSTR lpClass; + HKEY hkeyClass; + DWORD dwHotKey; + HANDLE hIcon; + HANDLE hProcess; +} SHELLEXECUTEINFOW,*LPSHELLEXECUTEINFOW; +typedef struct _SHFILEOPSTRUCTA { + HWND hwnd; + UINT wFunc; + LPCSTR pFrom; + LPCSTR pTo; + FILEOP_FLAGS fFlags; + BOOL fAnyOperationsAborted; + PVOID hNameMappings; + LPCSTR lpszProgressTitle; +} SHFILEOPSTRUCTA,*LPSHFILEOPSTRUCTA; +typedef struct _SHFILEOPSTRUCTW { + HWND hwnd; + UINT wFunc; + LPCWSTR pFrom; + LPCWSTR pTo; + FILEOP_FLAGS fFlags; + BOOL fAnyOperationsAborted; + PVOID hNameMappings; + LPCWSTR lpszProgressTitle; +} SHFILEOPSTRUCTW,*LPSHFILEOPSTRUCTW; +typedef struct _SHFILEINFOA { + HICON hIcon; + int iIcon; + DWORD dwAttributes; + CHAR szDisplayName[MAX_PATH]; + CHAR szTypeName[80]; +} SHFILEINFOA; +typedef struct _SHFILEINFOW { + HICON hIcon; + int iIcon; + DWORD dwAttributes; + WCHAR szDisplayName[MAX_PATH]; + WCHAR szTypeName[80]; +} SHFILEINFOW; +typedef struct _SHQUERYRBINFO { + DWORD cbSize; + __int64 i64Size; + __int64 i64NumItems; +} SHQUERYRBINFO, *LPSHQUERYRBINFO; +#include + +LPWSTR * WINAPI CommandLineToArgvW(LPCWSTR,int*); +void WINAPI DragAcceptFiles(HWND,BOOL); +void WINAPI DragFinish(HDROP); +UINT WINAPI DragQueryFileA(HDROP,UINT,LPSTR,UINT); +UINT WINAPI DragQueryFileW(HDROP,UINT,LPWSTR,UINT); +BOOL WINAPI DragQueryPoint(HDROP,LPPOINT); +HICON WINAPI DuplicateIcon(HINSTANCE,HICON); +HICON WINAPI ExtractAssociatedIconA(HINSTANCE,LPCSTR,PWORD); +HICON WINAPI ExtractAssociatedIconW(HINSTANCE,LPCWSTR,PWORD); +HICON WINAPI ExtractIconA(HINSTANCE,LPCSTR,UINT); +HICON WINAPI ExtractIconW(HINSTANCE,LPCWSTR,UINT); +UINT WINAPI ExtractIconExA(LPCSTR,int,HICON*,HICON*,UINT); +UINT WINAPI ExtractIconExW(LPCWSTR,int,HICON*,HICON*,UINT); +HINSTANCE WINAPI FindExecutableA(LPCSTR,LPCSTR,LPSTR); +HINSTANCE WINAPI FindExecutableW(LPCWSTR,LPCWSTR,LPWSTR); +UINT WINAPI SHAppBarMessage(DWORD,PAPPBARDATA); +BOOL WINAPI Shell_NotifyIconA(DWORD,PNOTIFYICONDATAA); +BOOL WINAPI Shell_NotifyIconW(DWORD,PNOTIFYICONDATAW); +int WINAPI ShellAboutA(HWND,LPCSTR,LPCSTR,HICON); +int WINAPI ShellAboutW(HWND,LPCWSTR,LPCWSTR,HICON); +HINSTANCE WINAPI ShellExecuteA(HWND,LPCSTR,LPCSTR,LPCSTR,LPCSTR,INT); +HINSTANCE WINAPI ShellExecuteW(HWND,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR,INT); +BOOL WINAPI ShellExecuteExA(LPSHELLEXECUTEINFOA); +BOOL WINAPI ShellExecuteExW(LPSHELLEXECUTEINFOW); +int WINAPI SHFileOperationA(LPSHFILEOPSTRUCTA); +int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW); +void WINAPI SHFreeNameMappings(HANDLE); +DWORD WINAPI SHGetFileInfoA(LPCSTR,DWORD,SHFILEINFOA*,UINT,UINT); +DWORD WINAPI SHGetFileInfoW(LPCWSTR,DWORD,SHFILEINFOW*,UINT,UINT); +HRESULT WINAPI SHQueryRecycleBinA(LPCSTR, LPSHQUERYRBINFO); +HRESULT WINAPI SHQueryRecycleBinW(LPCWSTR, LPSHQUERYRBINFO); +HRESULT WINAPI SHEmptyRecycleBinA(HWND,LPCSTR,DWORD); +HRESULT WINAPI SHEmptyRecycleBinW(HWND,LPCWSTR,DWORD); + +#ifdef UNICODE +typedef NOTIFYICONDATAW NOTIFYICONDATA,*PNOTIFYICONDATA; +typedef SHELLEXECUTEINFOW SHELLEXECUTEINFO,*LPSHELLEXECUTEINFO; +typedef SHFILEOPSTRUCTW SHFILEOPSTRUCT,*LPSHFILEOPSTRUCT; +typedef SHFILEINFOW SHFILEINFO; +#define DragQueryFile DragQueryFileW +#define ExtractAssociatedIcon ExtractAssociatedIconW +#define ExtractIcon ExtractIconW +#define ExtractIconEx ExtractIconExW +#define FindExecutable FindExecutableW +#define Shell_NotifyIcon Shell_NotifyIconW +#define ShellAbout ShellAboutW +#define ShellExecute ShellExecuteW +#define ShellExecuteEx ShellExecuteExW +#define SHFileOperation SHFileOperationW +#define SHGetFileInfo SHGetFileInfoW +#define SHQueryRecycleBin SHQueryRecycleBinW +#define SHEmptyRecycleBin SHEmptyRecycleBinW + +#else +typedef NOTIFYICONDATAA NOTIFYICONDATA,*PNOTIFYICONDATA; +typedef SHELLEXECUTEINFOA SHELLEXECUTEINFO,*LPSHELLEXECUTEINFO; +typedef SHFILEOPSTRUCTA SHFILEOPSTRUCT,*LPSHFILEOPSTRUCT; +typedef SHFILEINFOA SHFILEINFO; +#define DragQueryFile DragQueryFileA +#define ExtractAssociatedIcon ExtractAssociatedIconA +#define ExtractIcon ExtractIconA +#define ExtractIconEx ExtractIconExA +#define FindExecutable FindExecutableA +#define Shell_NotifyIcon Shell_NotifyIconA +#define ShellAbout ShellAboutA +#define ShellExecute ShellExecuteA +#define ShellExecuteEx ShellExecuteExA +#define SHFileOperation SHFileOperationA +#define SHGetFileInfo SHGetFileInfoA +#define SHQueryRecycleBin SHQueryRecycleBinA +#define SHEmptyRecycleBin SHEmptyRecycleBinA +#endif +#ifdef __cplusplus +} +#endif +#endif diff --git a/tray.c b/tray.c new file mode 100644 index 0000000..a3ff462 --- /dev/null +++ b/tray.c @@ -0,0 +1,591 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define _WIN32_IE 0x0500 +#define NIF_INFO 0x00000010 +// Notify Icon Infotip flags +#define NIIF_NONE 0x00000000 +// icon flags are mutually exclusive +// and take only the lowest 2 bits +#define NIIF_INFO 0x00000001 +#define NIIF_WARNING 0x00000002 +#define NIIF_ERROR 0x00000003 +#define NIIF_ICON_MASK 0x0000000F + +#include +#include +#include "tray.h" +#include "service.h" +#include "shellapi.h" +#include "main.h" +#include "options.h" +#include "openvpn.h" +#include "openvpn_config.h" +#include "openvpn-gui-res.h" + +//POPUP MENU +HMENU hMenu; +HMENU hMenuConn[MAX_CONFIGS]; +HMENU hMenuService; + +NOTIFYICONDATA ni; +extern struct options o; + +// Mouse clicks on tray +void OnNotifyTray(LPARAM lParam) +{ + POINT pt; // point structure + int connected_config; + int i; + TCHAR buf[1000]; + + // Right click, show the menu + switch(lParam) { + case WM_RBUTTONDOWN: + /* Re-read configs and re-create menus if no connection is running */ + if (CountConnectedState(DISCONNECTED) == o.num_configs) + { + DestroyPopupMenus(); + BuildFileList(); + CreatePopupMenus(); + } + + GetCursorPos(&pt); // get the cursors position + SetForegroundWindow(o.hWnd); // set the foreground window + TrackPopupMenu(hMenu,TPM_RIGHTALIGN,pt.x,pt.y,0,o.hWnd,NULL);// track the popup + break; + + case WM_LBUTTONDOWN: + break; + + case WM_LBUTTONDBLCLK: + if (o.service_only[0]=='1') + { + /* Start OpenVPN Service */ + if (o.service_running == SERVICE_DISCONNECTED) + { + MyStartService(); + } + else if (o.service_running == SERVICE_CONNECTED) + { + /* Stop OpenVPN service */ + myLoadString(IDM_TEXT_ASK_STOP_SERVICE); + if (MessageBox(NULL, buf, GUI_NAME, MB_YESNO | MB_SETFOREGROUND) == IDYES) + { + MyStopService(); + } + } + } + else + { + /* Open Status window if only one connection is running */ + connected_config = -1; + for (i=0; i < o.num_configs; i++) + { + if(o.cnn[i].connect_status != DISCONNECTED) + { + if (connected_config == -1) + { + connected_config = i; + } + else + { + connected_config = -1; + break; + } + } + } + if (connected_config != -1) + { + ShowWindow(o.cnn[connected_config].hwndStatus, SW_SHOW); + SetForegroundWindow(o.cnn[connected_config].hwndStatus); + } + + /* Re-read configs and re-create menus if no connection is running */ + if (CountConnectedState(DISCONNECTED) == o.num_configs) + { + DestroyPopupMenus(); + BuildFileList(); + CreatePopupMenus(); + + /* Start connection if only one config exist */ + if ((o.num_configs == 1) && (o.cnn[0].connect_status == DISCONNECTED)) + StartOpenVPN(0); + } + } + break; + } + PostMessage(o.hWnd,WM_NULL,0,0);// post a null message +} + + +void OnDestroyTray() +{ + //Destroy popup menu + DestroyMenu(hMenu); + + //Remove Icon from Tray + Shell_NotifyIcon(NIM_DELETE, &ni); +} + + +/* Create Popup Menus */ +void CreatePopupMenus() +{ + int i; + //extern struct options o; + + /* Create Main menu */ + hMenu=CreatePopupMenu(); + + /* Create a menu for every config */ + for (i=0; i < o.num_configs; i++) + hMenuConn[i]=CreatePopupMenu(); + + /* Create the Service Menu */ + hMenuService=CreatePopupMenu(); + + /* Put something on the menus */ + CreateItemList(hMenu); +} + +/* Destroy Popup Menus */ +void DestroyPopupMenus() +{ + int i; + + /* Destroy Main menu */ + DestroyMenu(hMenu); + + /* Destroy all config submenus */ + for (i=0; i < o.num_configs; i++) + DestroyMenu(hMenuConn[i]); + + /* Destroy the Service Menu */ + DestroyMenu(hMenuService); + +} + +void CreateItemList() +{ + extern char ext_string[]; + extern char allow_edit[2]; + extern char allow_service[2]; + int i; + TCHAR buf[1000]; + + if (o.num_configs == 1) + { + /* Create Main menu with actions */ + if (o.service_only[0]=='0') + { + myLoadString(IDM_TEXT_CONNECT); + AppendMenu(hMenu,MF_STRING, IDM_CONNECTMENU, buf); + myLoadString(IDM_TEXT_DISCONNECT); + AppendMenu(hMenu,MF_STRING, IDM_DISCONNECTMENU, buf); + myLoadString(IDM_TEXT_STATUS); + AppendMenu(hMenu,MF_STRING, IDM_STATUSMENU, buf); + AppendMenu(hMenu,MF_SEPARATOR,0,0); + } + else + { + myLoadString(IDM_TEXT_SERVICEONLY_START); + AppendMenu(hMenu,MF_STRING, IDM_SERVICE_START, buf); + myLoadString(IDM_TEXT_SERVICEONLY_STOP); + AppendMenu(hMenu,MF_STRING, IDM_SERVICE_STOP, buf); + myLoadString(IDM_TEXT_SERVICEONLY_RESTART); + AppendMenu(hMenu,MF_STRING, IDM_SERVICE_RESTART, buf); + AppendMenu(hMenu,MF_SEPARATOR,0,0); + } + + myLoadString(IDM_TEXT_VIEWLOG); + AppendMenu(hMenu,MF_STRING, IDM_VIEWLOGMENU, buf); + if (o.allow_edit[0]=='1') + { + myLoadString(IDM_TEXT_EDITCONFIG); + AppendMenu(hMenu,MF_STRING, IDM_EDITMENU, buf); + } +#ifndef DISABLE_CHANGE_PASSWORD + if (o.allow_password[0]=='1') + { + myLoadString(IDM_TEXT_PASSPHRASE); + AppendMenu(hMenu,MF_STRING, IDM_PASSPHRASEMENU, buf); + } +#endif + + AppendMenu(hMenu,MF_SEPARATOR,0,0); + if (o.allow_service[0]=='1' && o.service_only[0]=='0') + { + myLoadString(IDM_TEXT_SERVICE); + AppendMenu(hMenu,MF_POPUP,(UINT) hMenuService, buf); + AppendMenu(hMenu,MF_SEPARATOR,0,0); + } + if (o.allow_proxy[0]=='1' && o.service_only[0]=='0') + { + myLoadString(IDM_TEXT_PROXY); + AppendMenu(hMenu,MF_STRING ,IDM_PROXY, buf); + AppendMenu(hMenu,MF_SEPARATOR,0,0); + } + myLoadString(IDM_TEXT_ABOUT); + AppendMenu(hMenu,MF_STRING ,IDM_ABOUT, buf); + myLoadString(IDM_TEXT_CLOSE); + AppendMenu(hMenu,MF_STRING ,IDM_CLOSE, buf); + + SetMenuStatus(0, DISCONNECTED); + + } + else + { + /* Create Main menu with all connections */ + for (i=0; i < o.num_configs; i++) + AppendMenu(hMenu,MF_POPUP,(UINT) hMenuConn[i],o.cnn[i].config_name); + if (o.num_configs > 0) + AppendMenu(hMenu,MF_SEPARATOR,0,0); + if (o.allow_service[0]=='1' && o.service_only[0]=='0') + { + myLoadString(IDM_TEXT_SERVICE); + AppendMenu(hMenu,MF_POPUP,(UINT) hMenuService, buf); + AppendMenu(hMenu,MF_SEPARATOR,0,0); + } + if (o.service_only[0]=='1') + { + myLoadString(IDM_TEXT_SERVICEONLY_START); + AppendMenu(hMenu,MF_STRING, IDM_SERVICE_START, buf); + myLoadString(IDM_TEXT_SERVICEONLY_STOP); + AppendMenu(hMenu,MF_STRING, IDM_SERVICE_STOP, buf); + myLoadString(IDM_TEXT_SERVICEONLY_RESTART); + AppendMenu(hMenu,MF_STRING, IDM_SERVICE_RESTART, buf); + AppendMenu(hMenu,MF_SEPARATOR,0,0); + } + if (o.allow_proxy[0]=='1' && o.service_only[0]=='0') + { + myLoadString(IDM_TEXT_PROXY); + AppendMenu(hMenu,MF_STRING ,IDM_PROXY, buf); + AppendMenu(hMenu,MF_SEPARATOR,0,0); + } + myLoadString(IDM_TEXT_ABOUT); + AppendMenu(hMenu,MF_STRING ,IDM_ABOUT, buf); + myLoadString(IDM_TEXT_CLOSE); + AppendMenu(hMenu,MF_STRING ,IDM_CLOSE, buf); + + + /* Create PopUp menus for every connection */ + for (i=0; i < o.num_configs; i++) + { + if (o.service_only[0]=='0') + { + myLoadString(IDM_TEXT_CONNECT); + AppendMenu(hMenuConn[i],MF_STRING, (UINT_PTR)IDM_CONNECTMENU+i, buf); + myLoadString(IDM_TEXT_DISCONNECT); + AppendMenu(hMenuConn[i],MF_STRING, (UINT_PTR)IDM_DISCONNECTMENU+i, buf); + myLoadString(IDM_TEXT_STATUS); + AppendMenu(hMenuConn[i],MF_STRING, (UINT_PTR)IDM_STATUSMENU+i, buf); + AppendMenu(hMenuConn[i],MF_SEPARATOR,0,0); + } + myLoadString(IDM_TEXT_VIEWLOG); + AppendMenu(hMenuConn[i],MF_STRING, (UINT_PTR)IDM_VIEWLOGMENU+i, buf); + if (o.allow_edit[0]=='1') { + myLoadString(IDM_TEXT_EDITCONFIG); + AppendMenu(hMenuConn[i],MF_STRING, (UINT_PTR)IDM_EDITMENU+i, buf); + } +#ifndef DISABLE_CHANGE_PASSWORD + if (o.allow_password[0]=='1') + { + myLoadString(IDM_TEXT_PASSPHRASE); + AppendMenu(hMenuConn[i],MF_STRING, (UINT_PTR)IDM_PASSPHRASEMENU+i, buf); + } +#endif + + SetMenuStatus(i, DISCONNECTED); + } + } + + /* Create Service menu */ + if (o.allow_service[0]=='1' && o.service_only[0]=='0') + { + myLoadString(IDM_TEXT_SERVICE_START); + AppendMenu(hMenuService,MF_STRING, IDM_SERVICE_START, buf); + myLoadString(IDM_TEXT_SERVICE_STOP); + AppendMenu(hMenuService,MF_STRING, IDM_SERVICE_STOP, buf); + myLoadString(IDM_TEXT_SERVICE_RESTART); + AppendMenu(hMenuService,MF_STRING, IDM_SERVICE_RESTART, buf); + } + + SetServiceMenuStatus(); +} + + +BOOL LoadAppIcon() +{ + + // Load icon from resource + HICON hIcon = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(APP_ICON), + IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR); + if (hIcon) { + SendMessage(o.hWnd, WM_SETICON, (WPARAM) (ICON_SMALL), (LPARAM) (hIcon)); + SendMessage(o.hWnd, WM_SETICON, (WPARAM) (ICON_BIG), (LPARAM) (hIcon)); //ALT+TAB icon + return TRUE; + } + return FALSE; +} + + +void ShowTrayIcon() +{ + TCHAR buf[1000]; + + ni.cbSize = sizeof(ni); + ni.uID = 0; + myLoadString(MSG_TIP); + lstrcpyn(ni.szTip, buf, sizeof(ni.szTip)); + ni.hWnd = o.hWnd; + ni.uFlags = NIF_MESSAGE | NIF_TIP | NIF_ICON; // We want to use icon, tip, and callback message + ni.uCallbackMessage = WM_NOTIFYICONTRAY; // Our custom callback message (WM_APP + 1) + + + //Load selected icon + ni.hIcon = (HICON)LoadIcon(o.hInstance, MAKEINTRESOURCE(APP_ICON_DISCONNECTED)); + + Shell_NotifyIcon(NIM_ADD, &ni); + +} + +/* SetTrayIcon(int connected) + * connected=0 -> DisConnected + * connected=1 -> Connecting + * connected=2 -> Connected + */ +void SetTrayIcon(int connected) +{ + char msg[500]; + char msg_connected[100]; + char msg_connecting[100]; + char conn_name[200]; + char connected_since[50]; + int i, first_conn; + int config=0; + TCHAR buf[1000]; + + ni.cbSize = sizeof(ni); + ni.uID = 0; + ni.hWnd = o.hWnd; + ni.uFlags = NIF_MESSAGE | NIF_TIP | NIF_ICON; // We want to use icon, tip, and callback message + ni.uCallbackMessage = WM_NOTIFYICONTRAY; // Our custom callback message (WM_APP + 1) + + myLoadString(MSG_TIP); + strncpy(msg, buf, sizeof(ni.szTip)); + + myLoadString(MSG_TIP_CONNECTED); + strncpy(msg_connected, buf, sizeof(msg_connected)); + + myLoadString(MSG_TIP_CONNECTING); + strncpy(msg_connecting, buf, sizeof(msg_connecting)); + + first_conn=1; + for (i=0; i < o.num_configs; i++) + { + if(o.cnn[i].connect_status == CONNECTED) + { + /* Append connection name to Icon Tip Msg */ + if (first_conn) + strncat(msg, msg_connected, sizeof(msg) - strlen(msg) - 1); + else + strncat(msg, ", ", sizeof(msg) - strlen(msg) - 1); + strncat(msg, o.cnn[i].config_name, sizeof(msg) - strlen(msg) - 1); + first_conn=0; + config=i; + } + } + + first_conn=1; + for (i=0; i < o.num_configs; i++) + { + if((o.cnn[i].connect_status == CONNECTING) || + (o.cnn[i].connect_status == RECONNECTING)) + { + /* Append connection name to Icon Tip Msg */ + if (first_conn) + strncat(msg, msg_connecting, sizeof(msg) - strlen(msg) - 1); + else + strncat(msg, ", ", sizeof(msg) - strlen(msg) - 1); + strncat(msg, o.cnn[i].config_name, sizeof(msg) - strlen(msg) - 1); + first_conn=0; + } + } + + if (CountConnectedState(CONNECTED) == 1) + { + /* Append "Connected Since and Assigned IP msg" */ + time_t con_time; + con_time=time(NULL); + strftime(connected_since, sizeof(connected_since), "%b %d, %H:%M", + localtime(&o.cnn[config].connected_since)); + myLoadString(MSG_TIP_CONNECTED_SINCE); + strncat(msg, buf, sizeof(msg) - strlen(msg) - 1); + strncat(msg, connected_since, sizeof(msg) - strlen(msg) - 1); + if (strlen(o.cnn[config].ip) > 0) + { + char assigned_ip[100]; + myLoadString(MSG_TIP_ASSIGNED_IP); + mysnprintf(assigned_ip, buf, o.cnn[config].ip); + strncat(msg, assigned_ip, sizeof(msg) - strlen(msg) - 1); + } + } + + strncpy(ni.szTip, msg, sizeof(ni.szTip)); + + //Load selected icon + if (connected==2) + ni.hIcon = (HICON)LoadIcon(o.hInstance, MAKEINTRESOURCE(APP_ICON_CONNECTED)); + else if (connected==1) + ni.hIcon = (HICON)LoadIcon(o.hInstance, MAKEINTRESOURCE(APP_ICON_CONNECTING)); + else if (connected==0) + ni.hIcon = (HICON)LoadIcon(o.hInstance, MAKEINTRESOURCE(APP_ICON_DISCONNECTED)); + + Shell_NotifyIcon(NIM_MODIFY, &ni); +} + +void ShowTrayBalloon(char *infotitle_msg, char *info_msg) +{ + ni.cbSize = sizeof(ni); + ni.uID = 0; + ni.hWnd = o.hWnd; + ni.uFlags = NIF_INFO; /* We want to show a balloon */ + ni.uTimeout = 5000; + ni.dwInfoFlags = NIIF_INFO; /* Show an Info Icon */ + strncpy(ni.szInfo, info_msg, sizeof(ni.szInfo)); + strncpy(ni.szInfoTitle, infotitle_msg, sizeof(ni.szInfoTitle)); + + Shell_NotifyIcon(NIM_MODIFY, &ni); +} + + +void SetMenuStatus (int config, int bCheck) +{ + /* bCheck values: + * 0 - Not Connected + * 1 - Connecting + * 2 - Connected + * 4 - Disconnecting + */ + + + unsigned int iState; + + if (o.num_configs == 1) + { + if (bCheck == DISCONNECTED) + { + EnableMenuItem(hMenu, IDM_CONNECTMENU, MF_ENABLED); + EnableMenuItem(hMenu, IDM_DISCONNECTMENU, MF_GRAYED); + EnableMenuItem(hMenu, IDM_STATUSMENU, MF_GRAYED); + } + if (bCheck == CONNECTING) + { + EnableMenuItem(hMenu, IDM_CONNECTMENU, MF_GRAYED); + EnableMenuItem(hMenu, IDM_DISCONNECTMENU, MF_ENABLED); + EnableMenuItem(hMenu, IDM_STATUSMENU, MF_ENABLED); + } + if (bCheck == CONNECTED) + { + EnableMenuItem(hMenu, IDM_CONNECTMENU, MF_GRAYED); + EnableMenuItem(hMenu, IDM_DISCONNECTMENU, MF_ENABLED); + EnableMenuItem(hMenu, IDM_STATUSMENU, MF_ENABLED); + } + if (bCheck == DISCONNECTING) + { + EnableMenuItem(hMenu, IDM_CONNECTMENU, MF_GRAYED); + EnableMenuItem(hMenu, IDM_DISCONNECTMENU, MF_GRAYED); + EnableMenuItem(hMenu, IDM_STATUSMENU, MF_ENABLED); + } + } + else + { + iState = ((bCheck == CONNECTED) || (bCheck == DISCONNECTING)) ? + MF_CHECKED : MF_UNCHECKED ; + CheckMenuItem (hMenu, (UINT) hMenuConn[config], iState) ; + + if (bCheck == DISCONNECTED) + { + EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_CONNECTMENU + config, MF_ENABLED); + EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_DISCONNECTMENU + config, MF_GRAYED); + EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_STATUSMENU + config, MF_GRAYED); + } + if (bCheck == CONNECTING) + { + EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_CONNECTMENU + config, MF_GRAYED); + EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_DISCONNECTMENU + config, MF_ENABLED); + EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_STATUSMENU + config, MF_ENABLED); + } + if (bCheck == CONNECTED) + { + EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_CONNECTMENU + config, MF_GRAYED); + EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_DISCONNECTMENU + config, MF_ENABLED); + EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_STATUSMENU + config, MF_ENABLED); + } + if (bCheck == DISCONNECTING) + { + EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_CONNECTMENU + config, MF_GRAYED); + EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_DISCONNECTMENU + config, MF_GRAYED); + EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_STATUSMENU + config, MF_ENABLED); + } + } + +} + +void SetServiceMenuStatus() +{ + HMENU hMenuHandle; + + if (o.allow_service[0]=='0' && o.service_only[0]=='0') + return; + + if (o.service_only[0]=='1') + hMenuHandle = hMenu; + else + hMenuHandle = hMenuService; + + + if ((o.service_running == SERVICE_NOACCESS) || + (o.service_running == SERVICE_CONNECTING)) + { + /* Service is disabled */ + EnableMenuItem(hMenuHandle, IDM_SERVICE_START, MF_GRAYED); + EnableMenuItem(hMenuHandle, IDM_SERVICE_STOP, MF_GRAYED); + EnableMenuItem(hMenuHandle, IDM_SERVICE_RESTART, MF_GRAYED); + } + else if (o.service_running == SERVICE_CONNECTED) + { + /* Service is running */ + EnableMenuItem(hMenuHandle, IDM_SERVICE_START, MF_GRAYED); + EnableMenuItem(hMenuHandle, IDM_SERVICE_STOP, MF_ENABLED); + EnableMenuItem(hMenuHandle, IDM_SERVICE_RESTART, MF_ENABLED); + } + else + { + /* Service is not running */ + EnableMenuItem(hMenuHandle, IDM_SERVICE_START, MF_ENABLED); + EnableMenuItem(hMenuHandle, IDM_SERVICE_STOP, MF_GRAYED); + EnableMenuItem(hMenuHandle, IDM_SERVICE_RESTART, MF_GRAYED); + } + +} + + diff --git a/tray.h b/tray.h new file mode 100644 index 0000000..9bb98e0 --- /dev/null +++ b/tray.h @@ -0,0 +1,61 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define WM_NOTIFYICONTRAY (WM_APP + 1) + +//Popup Menu items + +#define IDM_PROXY 221 +#define IDM_ABOUT 222 + +#define IDM_CLOSE 223 + +#define IDM_TEXT_CONN1 "Office" +#define IDM_CONN1 301 +#define IDM_TEXT_CONN2 "Home" +#define IDM_CONN2 302 + +#define IDM_CONNECTMENU 300 +#define IDM_DISCONNECTMENU 400 +#define IDM_STATUSMENU 500 +#define IDM_VIEWLOGMENU 600 +#define IDM_EDITMENU 700 +#define IDM_PASSPHRASEMENU 800 + +/* Service submenu */ +#define IDM_SERVICEMENU 900 +#define IDM_SERVICE_START 901 +#define IDM_SERVICE_STOP 902 +#define IDM_SERVICE_RESTART 903 + + +void CreatePopupMenus(); //Create popup menus +void DestroyPopupMenus(); //Destroy popup menus +void OnNotifyTray(LPARAM lParam); //Tray message (mouse clicks on tray icon) +void OnDestroyTray(void); //WM_DESTROY message +void ShowTrayIcon(); //Put app icon in systray +void SetTrayIcon(int connected); //Change systray icon +BOOL LoadAppIcon(); //Application icon +void CreateItemList(); //Crate Popup menu +void SetMenuStatus (int config, int bCheck); //Mark connection as connected/disconnected +void SetServiceMenuStatus(); //Diabled Service menu items. +void ShowTrayBalloon(char *infotitle_msg, char *info_msg); + diff --git a/viewlog.c b/viewlog.c new file mode 100644 index 0000000..a556831 --- /dev/null +++ b/viewlog.c @@ -0,0 +1,121 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "tray.h" +#include "openvpn.h" +#include +#include "main.h" +#include "options.h" +#include "openvpn-gui-res.h" + +extern struct options o; + +void ViewLog(int config) +{ + char filename[200]; + + extern char log_viewer[MAX_PATH]; + extern char log_dir[MAX_PATH]; + + STARTUPINFO start_info; + PROCESS_INFORMATION proc_info; + SECURITY_ATTRIBUTES sa; + SECURITY_DESCRIPTOR sd; + char command_line[256]; + + CLEAR (start_info); + CLEAR (proc_info); + CLEAR (sa); + CLEAR (sd); + + mysnprintf(filename, "%s \"%s\"", o.log_viewer, o.cnn[config].log_path); + + /* fill in STARTUPINFO struct */ + GetStartupInfo(&start_info); + start_info.cb = sizeof(start_info); + start_info.dwFlags = 0; + start_info.wShowWindow = SW_SHOWDEFAULT; + start_info.hStdInput = NULL; + start_info.hStdOutput = NULL; + + if (!CreateProcess(NULL, + filename, //commandline + NULL, + NULL, + TRUE, + CREATE_NEW_CONSOLE, + NULL, + o.log_dir, //start-up dir + &start_info, + &proc_info)) + { + /* could not start log viewer */ + ShowLocalizedMsg(GUI_NAME, ERR_START_LOG_VIEWER, o.log_viewer); + } + +} + + +void EditConfig(int config) +{ + char filename[200]; + + extern char config_dir[MAX_PATH]; + extern char editor[MAX_PATH]; + + STARTUPINFO start_info; + PROCESS_INFORMATION proc_info; + SECURITY_ATTRIBUTES sa; + SECURITY_DESCRIPTOR sd; + char command_line[256]; + + CLEAR (start_info); + CLEAR (proc_info); + CLEAR (sa); + CLEAR (sd); + + mysnprintf(filename, "%s \"%s\\%s\"", o.editor, o.cnn[config].config_dir, o.cnn[config].config_file); + + /* fill in STARTUPINFO struct */ + GetStartupInfo(&start_info); + start_info.cb = sizeof(start_info); + start_info.dwFlags = 0; + start_info.wShowWindow = SW_SHOWDEFAULT; + start_info.hStdInput = NULL; + start_info.hStdOutput = NULL; + + if (!CreateProcess(NULL, + filename, //commandline + NULL, + NULL, + TRUE, + CREATE_NEW_CONSOLE, + NULL, + o.cnn[config].config_dir, //start-up dir + &start_info, + &proc_info)) + { + /* could not start editor */ + ShowLocalizedMsg(GUI_NAME, ERR_START_CONF_EDITOR, o.editor); + } + +} diff --git a/viewlog.h b/viewlog.h new file mode 100644 index 0000000..a656e41 --- /dev/null +++ b/viewlog.h @@ -0,0 +1,23 @@ +/* + * OpenVPN-GUI -- A Windows GUI for OpenVPN. + * + * Copyright (C) 2004 Mathias Sundman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +void ViewLog(int config); +void EditConfig(int config);