nmsg  0.9.0
msgmodset.c
1 /*
2  * Copyright (c) 2008-2010, 2012, 2013 by Farsight Security, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /* Import. */
18 
19 #include <dirent.h>
20 #include <dlfcn.h>
21 
22 #include "private.h"
23 
24 /* Forward. */
25 
26 static nmsg_res msgmodset_load_module(struct nmsg_msgmodset *,
27  struct nmsg_msgmod_plugin *,
28  const char *fname);
29 
30 static void msgmodset_insert_module(struct nmsg_msgmodset *, struct nmsg_msgmod *);
31 
32 /* Internal functions. */
33 
34 /* XXX: factor out the non-msgmod functionality of nmsg_msgmodset_init() and
35  * nmsg_msgmodset_destroy() */
36 
37 struct nmsg_msgmodset *
38 _nmsg_msgmodset_init(const char *plugin_path) {
40  DIR *dir = NULL;
41  struct dirent *de = NULL;
42  struct nmsg_msgmodset *msgmodset = NULL;
43  ubuf *fname;
44 
45  assert(plugin_path != NULL);
46 
47  _nmsg_dprintf(2, "%s: loading modules from %s\n", __func__, plugin_path);
48 
49  fname = ubuf_init(128);
50  msgmodset = calloc(1, sizeof(*msgmodset));
51  assert(msgmodset != NULL);
52  msgmodset->vendors = calloc(1, sizeof(void *));
53  assert(msgmodset->vendors != NULL);
54 
55  dir = opendir(plugin_path);
56  if (dir == NULL) {
57  _nmsg_dprintf(1, "%s: unable to opendir %s: %s\n",
58  __func__, plugin_path, strerror(errno));
59  goto out;
60  }
61  while ((de = readdir(dir)) != NULL) {
62  char *fn;
63  size_t fnlen;
64  struct nmsg_dlmod *dlmod;
65  struct nmsg_msgmod_plugin *plugin;
66  struct nmsg_msgmod_plugin **plugin_array;
67  struct stat statbuf;
68 
69  ubuf_clip(fname, 0);
70  ubuf_add_fmt(fname, "%s/%s", plugin_path, de->d_name);
71 
72  if (stat(ubuf_cstr(fname), &statbuf) == -1)
73  continue;
74  if (!S_ISREG(statbuf.st_mode))
75  continue;
76  fn = de->d_name;
77  fnlen = strlen(fn);
78  if (fnlen > 3 &&
79  !(fn[fnlen - 3] == '.' &&
80  fn[fnlen - 2] == 's' &&
81  fn[fnlen - 1] == 'o'))
82  {
83  /* XXX: platforms that don't use ".so" */
84 
85  /* not a module, skip */
86  continue;
87  }
88  if (strstr(fn, NMSG_MSG_MODULE_PREFIX "_isc.") == fn) {
89  /* XXX: if the base msgmodset plugin is present under its
90  * old "ISC" name, silently skip it */
91  continue;
92  }
93  if (strstr(fn, NMSG_MSG_MODULE_PREFIX "_") == fn) {
94  _nmsg_dprintf(4, "%s: trying %s\n", __func__, ubuf_cstr(fname));
95  dlmod = _nmsg_dlmod_init(ubuf_cstr(fname));
96  if (dlmod == NULL)
97  goto out;
98  _nmsg_dprintf(4, "%s: loading nmsg message module %s\n",
99  __func__, ubuf_cstr(fname));
100 
101  plugin = (struct nmsg_msgmod_plugin *)
102  dlsym(dlmod->handle, "nmsg_msgmod_ctx");
103  if (plugin == NULL)
104  dlerror();
105 
106  plugin_array = (struct nmsg_msgmod_plugin **)
107  dlsym(dlmod->handle, "nmsg_msgmod_ctx_array");
108  if (plugin_array == NULL)
109  dlerror();
110 
111  if (plugin == NULL && plugin_array == NULL) {
112  _nmsg_dprintf(1, "%s: WARNING: no modules found,"
113  " not loading %s\n", __func__, ubuf_cstr(fname));
114  _nmsg_dlmod_destroy(&dlmod);
115  continue;
116  }
117 
118  dlmod->type = nmsg_modtype_msgmod;
119  ISC_LIST_APPEND(msgmodset->dlmods, dlmod, link);
120 
121  if (plugin != NULL) {
122  res = msgmodset_load_module(msgmodset, plugin, fn);
123  if (res != nmsg_res_success)
124  goto out;
125  }
126 
127  if (plugin_array != NULL) {
128  unsigned i = 0;
129 
130  for (i = 0, plugin = plugin_array[i];
131  plugin != NULL;
132  i++, plugin = plugin_array[i])
133  {
134  res = msgmodset_load_module(msgmodset,
135  plugin,
136  fn);
137  if (res != nmsg_res_success)
138  goto out;
139  }
140  }
141  }
142  }
143  res = nmsg_res_success;
144 out:
145  ubuf_destroy(&fname);
146  if (res != nmsg_res_success && msgmodset != NULL)
147  _nmsg_msgmodset_destroy(&msgmodset);
148  if (dir != NULL)
149  (void) closedir(dir);
150  return (msgmodset);
151 }
152 
153 void
154 _nmsg_msgmodset_destroy(struct nmsg_msgmodset **pms) {
155  struct nmsg_dlmod *dlmod, *dlmod_next;
156  struct nmsg_msgmod *mod;
157  struct nmsg_msgmodset *ms;
158  struct nmsg_msgvendor *msgv;
159  unsigned vid, msgtype;
160 
161  ms = *pms;
162  if (ms == NULL)
163  return;
164 
165  dlmod = ISC_LIST_HEAD(ms->dlmods);
166  while (dlmod != NULL) {
167  dlmod_next = ISC_LIST_NEXT(dlmod, link);
168  _nmsg_dlmod_destroy(&dlmod);
169  dlmod = dlmod_next;
170  }
171  for (vid = 0; vid <= ms->nv; vid++) {
172  msgv = ms->vendors[vid];
173  if (msgv == NULL)
174  continue;
175 
176  for (msgtype = 0; msgtype <= msgv->nm; msgtype++) {
177  mod = msgv->msgtypes[msgtype];
178  if (mod != NULL)
179  _nmsg_msgmod_stop(&mod);
180  }
181  free(msgv->msgtypes);
182  free(msgv);
183  }
184  free(ms->vendors);
185  free(ms);
186  *pms = NULL;
187 }
188 
189 /* Private functions. */
190 
191 static nmsg_res
192 msgmodset_load_module(struct nmsg_msgmodset *ms, struct nmsg_msgmod_plugin *plugin,
193  const char *fname)
194 {
195  struct nmsg_msgmod *msgmod;
196 
197  if (plugin->msgver != NMSG_MSGMOD_VERSION) {
198  _nmsg_dprintf(1, "%s: WARNING: version mismatch, not loading %s\n",
199  __func__, fname);
200  return (nmsg_res_failure);
201  }
202 
203  if (plugin->type == nmsg_msgmod_type_transparent) {
221  uint32_t nmsg_protobuf_c_major =
222  PROTOBUF_C_VERSION_NUMBER / 1000000;
223  uint32_t plugin_protobuf_c_major =
224  plugin->protobuf_c_version_number / 1000000;
225 
226  if (nmsg_protobuf_c_major != plugin_protobuf_c_major) {
227  _nmsg_dprintf(1, "%s: WARNING: protobuf-c major version mismatch "
228  "(%u != %u), not loading %s\n",
229  __func__,
230  nmsg_protobuf_c_major,
231  plugin_protobuf_c_major,
232  fname);
233  return (nmsg_res_failure);
234  }
235  }
236 
237  msgmod = _nmsg_msgmod_start(plugin);
238  if (msgmod == NULL) {
239  _nmsg_dprintf(1, "%s: unable to load message type %s/%s from %s\n",
240  __func__, plugin->vendor.name, plugin->msgtype.name,
241  fname);
242  return (nmsg_res_failure);
243  }
244  msgmodset_insert_module(ms, msgmod);
245  if (_nmsg_global_debug >= 3) {
246  _nmsg_dprintf(3, "%s: loaded message schema %s/%s from %s "
247  "@ %p\n", __func__,
248  plugin->vendor.name, plugin->msgtype.name,
249  fname, plugin);
250  } else if (_nmsg_global_debug == 2) {
251  _nmsg_dprintf(2, "%s: loaded message schema %s/%s\n",
252  __func__, plugin->vendor.name, plugin->msgtype.name);
253  }
254 
255  return (nmsg_res_success);
256 }
257 
258 static void
259 msgmodset_insert_module(struct nmsg_msgmodset *ms, struct nmsg_msgmod *mod) {
260  struct nmsg_msgvendor *msgv;
261  unsigned i, vid, max_msgtype;
262 
263  vid = mod->plugin->vendor.id;
264  max_msgtype = mod->plugin->msgtype.id;
265 
266  if (ms->nv < vid) {
267  /* resize vendor array */
268  size_t vsz = sizeof(void *) * (vid + 1);
269  ms->vendors = realloc(ms->vendors, vsz);
270  assert(ms->vendors != NULL);
271  for (i = ms->nv + 1; i <= vid; i++)
272  ms->vendors[i] = NULL;
273  ms->nv = vid;
274  }
275  if (ms->vendors[vid] == NULL) {
276  /* previously unseen vendor id */
277  ms->vendors[vid] = calloc(1, sizeof(struct nmsg_msgvendor));
278  assert(ms->vendors[vid] != NULL);
279  ms->vendors[vid]->msgtypes = calloc(1, sizeof(void *));
280  assert(ms->vendors[vid]->msgtypes != NULL);
281  }
282  msgv = ms->vendors[vid];
283  if (msgv->nm < max_msgtype) {
284  /* resize msgtype array */
285  size_t msz = sizeof(void *) * (max_msgtype + 1);
286  msgv->msgtypes = realloc(msgv->msgtypes, msz);
287  assert(msgv->msgtypes != NULL);
288  for (i = msgv->nm + 1; i <= max_msgtype; i++)
289  msgv->msgtypes[i] = NULL;
290  msgv->nm = max_msgtype;
291  }
292  if (msgv->msgtypes[mod->plugin->msgtype.id] != NULL)
293  _nmsg_dprintf(1, "%s: WARNING: already loaded module for "
294  "vendor id %u, message type %u\n", __func__,
295  mod->plugin->vendor.id, mod->plugin->msgtype.id);
296  msgv->msgtypes[mod->plugin->msgtype.id] = mod;
297 }
Structure exported by message modules to implement a new message type.
nmsg_res
nmsg result code
Definition: res.h:25
success
Definition: res.h:26
const char * name
Human readable name.
Definition: nmsg.h:56
an nmsg_message MUST always have a non-NULL ->np member.
Definition: private.h:365
nmsg_msgmod_type type
Module type.
uint32_t protobuf_c_version_number
protobuf-c version number.
struct nmsg_idname msgtype
Message type and name.
struct nmsg_idname vendor
Vendor ID and name.
generic failure
Definition: res.h:27
int msgver
Module interface version.
unsigned id
ID number.
Definition: nmsg.h:55