1 /*
2  *  OpenVPN -- An application to securely tunnel IP networks
3  *             over a single TCP/UDP port, with support for SSL/TLS-based
4  *             session authentication and key exchange,
5  *             packet encryption, packet authentication, and
6  *             packet compression.
7  *
8  *  Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License version 2
12  *  as published by the Free Software Foundation.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License along
20  *  with this program; if not, write to the Free Software Foundation, Inc.,
21  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23 
24 /*
25  * This plugin is similar to simple.c, except it also logs extra information
26  * to stdout for every plugin method called by OpenVPN.
27  *
28  * See the README file for build instructions.
29  */
30 
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 
35 #include "openvpn-plugin.h"
36 
37 /*
38  * Our context, where we keep our state.
39  */
40 struct plugin_context {
41     const char *username;
42     const char *password;
43 };
44 
45 /*
46  * Given an environmental variable name, search
47  * the envp array for its value, returning it
48  * if found or NULL otherwise.
49  */
50 static const char *
get_env(const char * name,const char * envp[])51 get_env(const char *name, const char *envp[])
52 {
53     if (envp)
54     {
55         int i;
56         const int namelen = strlen(name);
57         for (i = 0; envp[i]; ++i)
58         {
59             if (!strncmp(envp[i], name, namelen))
60             {
61                 const char *cp = envp[i] + namelen;
62                 if (*cp == '=')
63                 {
64                     return cp + 1;
65                 }
66             }
67         }
68     }
69     return NULL;
70 }
71 
72 OPENVPN_EXPORT openvpn_plugin_handle_t
openvpn_plugin_open_v1(unsigned int * type_mask,const char * argv[],const char * envp[])73 openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char *envp[])
74 {
75     struct plugin_context *context;
76 
77     /*
78      * Allocate our context
79      */
80     context = (struct plugin_context *) calloc(1, sizeof(struct plugin_context));
81     if (context == NULL)
82     {
83         printf("PLUGIN: allocating memory for context failed\n");
84         return NULL;
85     }
86 
87     /*
88      * Set the username/password we will require.
89      */
90     context->username = "foo";
91     context->password = "bar";
92 
93     /*
94      * Which callbacks to intercept.
95      */
96     *type_mask =
97         OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_UP)
98         |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_DOWN)
99         |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_ROUTE_UP)
100         |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_IPCHANGE)
101         |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY)
102         |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
103         |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT_V2)
104         |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_DISCONNECT)
105         |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_LEARN_ADDRESS)
106         |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_FINAL);
107 
108     return (openvpn_plugin_handle_t) context;
109 }
110 
111 void
show(const int type,const char * argv[],const char * envp[])112 show(const int type, const char *argv[], const char *envp[])
113 {
114     size_t i;
115     switch (type)
116     {
117         case OPENVPN_PLUGIN_UP:
118             printf("OPENVPN_PLUGIN_UP\n");
119             break;
120 
121         case OPENVPN_PLUGIN_DOWN:
122             printf("OPENVPN_PLUGIN_DOWN\n");
123             break;
124 
125         case OPENVPN_PLUGIN_ROUTE_UP:
126             printf("OPENVPN_PLUGIN_ROUTE_UP\n");
127             break;
128 
129         case OPENVPN_PLUGIN_IPCHANGE:
130             printf("OPENVPN_PLUGIN_IPCHANGE\n");
131             break;
132 
133         case OPENVPN_PLUGIN_TLS_VERIFY:
134             printf("OPENVPN_PLUGIN_TLS_VERIFY\n");
135             break;
136 
137         case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
138             printf("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n");
139             break;
140 
141         case OPENVPN_PLUGIN_CLIENT_CONNECT_V2:
142             printf("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n");
143             break;
144 
145         case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
146             printf("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n");
147             break;
148 
149         case OPENVPN_PLUGIN_LEARN_ADDRESS:
150             printf("OPENVPN_PLUGIN_LEARN_ADDRESS\n");
151             break;
152 
153         case OPENVPN_PLUGIN_TLS_FINAL:
154             printf("OPENVPN_PLUGIN_TLS_FINAL\n");
155             break;
156 
157         default:
158             printf("OPENVPN_PLUGIN_?\n");
159             break;
160     }
161 
162     printf("ARGV\n");
163     for (i = 0; argv[i] != NULL; ++i)
164     {
165         printf("%d '%s'\n", (int)i, argv[i]);
166     }
167 
168     printf("ENVP\n");
169     for (i = 0; envp[i] != NULL; ++i)
170     {
171         printf("%d '%s'\n", (int)i, envp[i]);
172     }
173 }
174 
175 OPENVPN_EXPORT int
openvpn_plugin_func_v1(openvpn_plugin_handle_t handle,const int type,const char * argv[],const char * envp[])176 openvpn_plugin_func_v1(openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[])
177 {
178     struct plugin_context *context = (struct plugin_context *) handle;
179 
180     show(type, argv, envp);
181 
182     /* check entered username/password against what we require */
183     if (type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
184     {
185         /* get username/password from envp string array */
186         const char *username = get_env("username", envp);
187         const char *password = get_env("password", envp);
188 
189         if (username && !strcmp(username, context->username)
190             && password && !strcmp(password, context->password))
191         {
192             return OPENVPN_PLUGIN_FUNC_SUCCESS;
193         }
194         else
195         {
196             return OPENVPN_PLUGIN_FUNC_ERROR;
197         }
198     }
199     else
200     {
201         return OPENVPN_PLUGIN_FUNC_SUCCESS;
202     }
203 }
204 
205 OPENVPN_EXPORT void
openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)206 openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
207 {
208     struct plugin_context *context = (struct plugin_context *) handle;
209     free(context);
210 }
211