~ubuntu-branches/ubuntu/hardy/openvpn/hardy-security

« back to all changes in this revision

Viewing changes to plugin.c

  • Committer: Bazaar Package Importer
  • Author(s): Alberto Gonzalez Iniesta
  • Date: 2005-01-05 19:03:11 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050105190311-mvqzpuhmlvobg9nh
Tags: 1.99+2.rc6-1
* The 'Three Wise Men' release.
* New upstream release.
* Update README.Debian with comments on changed string remapping.
  Thanks ron@debian.org for noting this first. (Closes: #288669)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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-2004 James Yonan <jim@yonan.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 as published by
 
12
 *  the Free Software Foundation; either version 2 of the License, or
 
13
 *  (at your option) any later version.
 
14
 *
 
15
 *  This program is distributed in the hope that it will be useful,
 
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
 *  GNU General Public License for more details.
 
19
 *
 
20
 *  You should have received a copy of the GNU General Public License
 
21
 *  along with this program (see the file COPYING included with this
 
22
 *  distribution); if not, write to the Free Software Foundation, Inc.,
 
23
 *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
24
 */
 
25
 
 
26
#ifdef WIN32
 
27
#include "config-win32.h"
 
28
#else
 
29
#include "config.h"
 
30
#endif
 
31
 
 
32
#include "syshead.h"
 
33
 
 
34
#ifdef ENABLE_PLUGIN
 
35
 
 
36
#include "buffer.h"
 
37
#include "error.h"
 
38
#include "misc.h"
 
39
#include "plugin.h"
 
40
 
 
41
#include "memdbg.h"
 
42
 
 
43
static void
 
44
plugin_show_string_array (int msglevel, const char *name, const char *array[])
 
45
{
 
46
  int i;
 
47
  for (i = 0; array[i]; ++i)
 
48
    msg (msglevel, "%s[%d] = '%s'", name, i, array[i]);
 
49
}
 
50
 
 
51
static void
 
52
plugin_show_args_env (int msglevel, const char *argv[], const char *envp[])
 
53
{
 
54
  if (check_debug_level (msglevel))
 
55
    {
 
56
      plugin_show_string_array (msglevel, "ARGV", argv);
 
57
      plugin_show_string_array (msglevel, "ENVP", envp);
 
58
    }
 
59
}
 
60
 
 
61
static const char *
 
62
plugin_type_name (const int type)
 
63
{
 
64
  switch (type)
 
65
    {
 
66
    case OPENVPN_PLUGIN_UP:
 
67
      return "PLUGIN_UP";
 
68
    case OPENVPN_PLUGIN_DOWN:
 
69
      return "PLUGIN_DOWN";
 
70
    case OPENVPN_PLUGIN_ROUTE_UP:
 
71
      return "PLUGIN_ROUTE_UP";
 
72
    case OPENVPN_PLUGIN_IPCHANGE:
 
73
      return "PLUGIN_IPCHANGE";
 
74
    case OPENVPN_PLUGIN_TLS_VERIFY:
 
75
      return "PLUGIN_TLS_VERIFY";
 
76
    case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
 
77
      return "PLUGIN_AUTH_USER_PASS_VERIFY";
 
78
    case OPENVPN_PLUGIN_CLIENT_CONNECT:
 
79
      return "PLUGIN_CLIENT_CONNECT";
 
80
    case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
 
81
      return "PLUGIN_CLIENT_DISCONNECT";
 
82
    case OPENVPN_PLUGIN_LEARN_ADDRESS:
 
83
      return "PLUGIN_LEARN_ADDRESS";
 
84
    default:
 
85
      return "PLUGIN_???";
 
86
    }
 
87
}
 
88
 
 
89
static const char *
 
90
plugin_mask_string (const unsigned int type_mask, struct gc_arena *gc)
 
91
{
 
92
  struct buffer out = alloc_buf_gc (256, gc);
 
93
  bool first = true;
 
94
  int i;
 
95
 
 
96
  for (i = 0; i < OPENVPN_PLUGIN_N; ++i)
 
97
    {
 
98
      if (OPENVPN_PLUGIN_MASK (i) & type_mask)
 
99
        {
 
100
          if (!first)
 
101
            buf_printf (&out, "|");
 
102
          buf_printf (&out, "%s", plugin_type_name (i));
 
103
          first = false;
 
104
        }
 
105
    }
 
106
  return BSTR (&out);
 
107
}
 
108
 
 
109
static inline unsigned int
 
110
plugin_supported_types (void)
 
111
{
 
112
  return ((1<<OPENVPN_PLUGIN_N)-1);
 
113
}
 
114
 
 
115
struct plugin_option_list *
 
116
plugin_option_list_new (struct gc_arena *gc)
 
117
{
 
118
  struct plugin_option_list *ret;
 
119
  ALLOC_OBJ_CLEAR_GC (ret, struct plugin_option_list, gc);
 
120
  return ret;
 
121
}
 
122
 
 
123
bool
 
124
plugin_option_list_add (struct plugin_option_list *list, const char *so_pathname, const char *args)
 
125
{
 
126
  if (list->n < MAX_PLUGINS)
 
127
    {
 
128
      struct plugin_option *o = &list->plugins[list->n++];
 
129
      o->so_pathname = so_pathname;
 
130
      o->args = args;
 
131
      return true;
 
132
    }
 
133
  else
 
134
    return false;
 
135
}
 
136
 
 
137
#ifdef ENABLE_DEBUG
 
138
void
 
139
plugin_option_list_print (const struct plugin_option_list *list, int msglevel)
 
140
{
 
141
  int i;
 
142
  for (i = 0; i < list->n; ++i)
 
143
    {
 
144
      const struct plugin_option *o = &list->plugins[i];
 
145
      msg (msglevel, "  plugin[%d] %s '%s'", i, o->so_pathname, o->args);
 
146
    }
 
147
}
 
148
#endif
 
149
 
 
150
#if defined(USE_LIBDL)
 
151
 
 
152
static void
 
153
libdl_resolve_symbol (void *handle, void **dest, const char *symbol, const char *plugin_name)
 
154
{
 
155
  *dest = dlsym (handle, symbol);
 
156
  if (!*dest)
 
157
    msg (M_FATAL, "PLUGIN: could not find symbol '%s' in plugin shared object %s: %s", symbol, plugin_name, dlerror());
 
158
}
 
159
 
 
160
#elif defined(USE_LOAD_LIBRARY)
 
161
 
 
162
static void
 
163
dll_resolve_symbol (HMODULE module, void **dest, const char *symbol, const char *plugin_name)
 
164
{
 
165
  *dest = GetProcAddress (module, symbol);
 
166
  if (!*dest)
 
167
    msg (M_FATAL, "PLUGIN: could not find symbol '%s' in plugin DLL %s", symbol, plugin_name);
 
168
}
 
169
 
 
170
#endif
 
171
 
 
172
static void
 
173
plugin_init_item (struct plugin *p, const struct plugin_option *o, const char **envp)
 
174
{
 
175
  struct gc_arena gc = gc_new ();
 
176
  const char **argv = make_arg_array (o->so_pathname, o->args, &gc);
 
177
  p->so_pathname = o->so_pathname;
 
178
  p->plugin_type_mask = plugin_supported_types ();
 
179
 
 
180
#if defined(USE_LIBDL)
 
181
  p->handle = dlopen (p->so_pathname, RTLD_NOW);
 
182
  if (!p->handle)
 
183
    msg (M_ERR, "PLUGIN_INIT: could not load plugin shared object %s: %s", p->so_pathname, dlerror());
 
184
  libdl_resolve_symbol (p->handle, (void*)&p->open,  "openvpn_plugin_open_v1", p->so_pathname);
 
185
  libdl_resolve_symbol (p->handle, (void*)&p->func,  "openvpn_plugin_func_v1", p->so_pathname);
 
186
  libdl_resolve_symbol (p->handle, (void*)&p->close, "openvpn_plugin_close_v1", p->so_pathname);
 
187
#elif defined(USE_LOAD_LIBRARY)
 
188
  p->module = LoadLibrary (p->so_pathname);
 
189
  if (!p->module)
 
190
    msg (M_ERR, "PLUGIN_INIT: could not load plugin DLL: %s", p->so_pathname);
 
191
  dll_resolve_symbol (p->module, (void*)&p->open,  "openvpn_plugin_open_v1", p->so_pathname);
 
192
  dll_resolve_symbol (p->module, (void*)&p->func,  "openvpn_plugin_func_v1", p->so_pathname);
 
193
  dll_resolve_symbol (p->module, (void*)&p->close, "openvpn_plugin_close_v1", p->so_pathname);
 
194
#endif
 
195
 
 
196
  dmsg (D_PLUGIN_DEBUG, "PLUGIN_INIT: PRE");
 
197
  plugin_show_args_env (D_PLUGIN_DEBUG, argv, envp);
 
198
 
 
199
  /*
 
200
   * Call the plugin initialization
 
201
   */
 
202
  p->plugin_handle = (*p->open)(&p->plugin_type_mask, argv, envp);
 
203
 
 
204
  msg (D_PLUGIN, "PLUGIN_INIT: POST %s '%s' intercepted=%s",
 
205
       p->so_pathname,
 
206
       o->args ? o->args : "[NULL]",
 
207
       plugin_mask_string (p->plugin_type_mask, &gc));
 
208
 
 
209
  if ((p->plugin_type_mask | plugin_supported_types()) != plugin_supported_types())
 
210
    msg (M_FATAL, "PLUGIN_INIT: plugin %s expressed interest in unsupported plugin types: [want=0x%08x, have=0x%08x]",
 
211
         p->so_pathname,
 
212
         p->plugin_type_mask,
 
213
         plugin_supported_types());
 
214
 
 
215
  if (p->plugin_handle == NULL)
 
216
    msg (M_FATAL, "PLUGIN_INIT: plugin initialization function failed: %s",
 
217
         p->so_pathname);
 
218
 
 
219
  gc_free (&gc);
 
220
}
 
221
 
 
222
static bool
 
223
plugin_call_item (const struct plugin *p, const int type, const char *args, const char **envp)
 
224
{
 
225
  int status = OPENVPN_PLUGIN_FUNC_SUCCESS;
 
226
 
 
227
  if (p->plugin_type_mask & OPENVPN_PLUGIN_MASK (type))
 
228
    {
 
229
      struct gc_arena gc = gc_new ();
 
230
      const char **argv = make_arg_array (p->so_pathname, args, &gc);
 
231
 
 
232
      dmsg (D_PLUGIN_DEBUG, "PLUGIN_CALL: PRE type=%s", plugin_type_name (type));
 
233
      plugin_show_args_env (D_PLUGIN_DEBUG, argv, envp);
 
234
 
 
235
      /*
 
236
       * Call the plugin work function
 
237
       */
 
238
      status = (*p->func)(p->plugin_handle, type, argv, envp);
 
239
 
 
240
      msg (D_PLUGIN, "PLUGIN_CALL: POST %s/%s status=%d",
 
241
           p->so_pathname,
 
242
           plugin_type_name (type),
 
243
           status);
 
244
 
 
245
      if (status != OPENVPN_PLUGIN_FUNC_SUCCESS)
 
246
        msg (M_WARN, "PLUGIN_CALL: plugin function %s failed with status %d: %s",
 
247
             plugin_type_name (type),
 
248
             status,
 
249
             p->so_pathname);
 
250
 
 
251
      gc_free (&gc);
 
252
    }
 
253
  return status;
 
254
}
 
255
 
 
256
static void
 
257
plugin_close_item (const struct plugin *p)
 
258
{
 
259
  msg (D_PLUGIN, "PLUGIN_CLOSE: %s", p->so_pathname);
 
260
 
 
261
  /*
 
262
   * Call the plugin close function
 
263
   */
 
264
  (*p->close)(p->plugin_handle);
 
265
 
 
266
#if defined(USE_LIBDL)
 
267
  if (dlclose (p->handle))
 
268
    msg (M_WARN, "PLUGIN_CLOSE: dlclose() failed on plugin: %s", p->so_pathname);
 
269
#elif defined(USE_LOAD_LIBRARY)
 
270
  if (!FreeLibrary (p->module))
 
271
    msg (M_WARN, "PLUGIN_CLOSE: FreeLibrary() failed on plugin: %s", p->so_pathname);
 
272
#endif
 
273
}
 
274
 
 
275
struct plugin_list *
 
276
plugin_list_open (const struct plugin_option_list *list, const struct env_set *es)
 
277
{
 
278
  struct gc_arena gc = gc_new ();
 
279
  int i;
 
280
  struct plugin_list *pl;
 
281
  const char **envp;
 
282
 
 
283
  ALLOC_OBJ_CLEAR (pl, struct plugin_list);
 
284
 
 
285
  envp = make_env_array (es, &gc);
 
286
 
 
287
  for (i = 0; i < list->n; ++i)
 
288
    plugin_init_item (&pl->plugins[i], &list->plugins[i], envp);
 
289
 
 
290
  pl->n = list->n;
 
291
 
 
292
  gc_free (&gc);
 
293
  return pl;
 
294
}
 
295
 
 
296
int
 
297
plugin_call (const struct plugin_list *pl, const int type, const char *args, struct env_set *es)
 
298
{
 
299
  int ret = false;
 
300
 
 
301
  if (plugin_defined (pl, type))
 
302
    {
 
303
      struct gc_arena gc = gc_new ();
 
304
      int i;
 
305
      const char **envp;
 
306
      
 
307
      mutex_lock_static (L_PLUGIN);
 
308
 
 
309
      setenv_del (es, "script_type");
 
310
      envp = make_env_array (es, &gc);
 
311
 
 
312
      for (i = 0; i < pl->n; ++i)
 
313
        {
 
314
          if (plugin_call_item (&pl->plugins[i], type, args, envp)) /* if any one plugin in the chain fails, return failure */
 
315
            {
 
316
              ret = true;
 
317
              break;
 
318
            }
 
319
        }
 
320
 
 
321
      mutex_unlock_static (L_PLUGIN);
 
322
 
 
323
      gc_free (&gc);
 
324
    }
 
325
 
 
326
  return ret;
 
327
}
 
328
 
 
329
void
 
330
plugin_list_close (struct plugin_list *pl)
 
331
{
 
332
  if (pl)
 
333
    {
 
334
      int i;
 
335
 
 
336
      for (i = 0; i < pl->n; ++i)
 
337
        plugin_close_item (&pl->plugins[i]);
 
338
      free (pl);
 
339
    }
 
340
}
 
341
 
 
342
bool
 
343
plugin_defined (const struct plugin_list *pl, const int type)
 
344
{
 
345
  int ret = false;
 
346
  if (pl)
 
347
    {
 
348
      int i;
 
349
      const unsigned int mask = OPENVPN_PLUGIN_MASK (type);
 
350
      for (i = 0; i < pl->n; ++i)
 
351
        {
 
352
          if (pl->plugins[i].plugin_type_mask & mask)
 
353
            {
 
354
              ret = true;
 
355
              break;
 
356
            }
 
357
        }
 
358
    }
 
359
  return ret;
 
360
}
 
361
 
 
362
#else
 
363
static void dummy(void) {}
 
364
#endif /* ENABLE_PLUGIN */