]> jfr.im git - solanum.git/blame - modules/core/m_modules.c
Version 4.1.3-dev
[solanum.git] / modules / core / m_modules.c
CommitLineData
78946542
EM
1/* modules/m_modules.c - module for module loading
2 * Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice is present in all copies.
7 *
8 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
9 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
11 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
12 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
13 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
14 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
15 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
16 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
17 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
18 * POSSIBILITY OF SUCH DAMAGE.
19 */
20
21#include "stdinc.h"
22#include "client.h"
23#include "parse.h"
24#include "msg.h"
25#include "modules.h"
26#include "s_newconf.h"
27#include "s_conf.h"
28#include "s_serv.h"
29#include "hash.h"
30#include "ircd.h"
31#include "match.h"
32#include "numeric.h"
33#include "send.h"
34#include "packet.h"
35#include "logger.h"
36
37static const char modules_desc[] = "Provides module management commands";
38
39static void mo_modload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
40static void mo_modlist(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
41static void mo_modreload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
42static void mo_modunload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
43static void mo_modrestart(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
44
45static void me_modload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
46static void me_modlist(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
47static void me_modreload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
48static void me_modunload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
49static void me_modrestart(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
50
51static void do_modload(struct Client *, const char *);
52static void do_modunload(struct Client *, const char *);
53static void do_modreload(struct Client *, const char *);
54static void do_modlist(struct Client *, const char *);
55static void do_modrestart(struct Client *);
56
41390bfe
AJ
57extern void modules_do_restart(void *); /* end of ircd/modules.c */
58
78946542
EM
59struct Message modload_msgtab = {
60 "MODLOAD", 0, 0, 0, 0,
61 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modload, 2}, {mo_modload, 2}}
62};
63
64struct Message modunload_msgtab = {
65 "MODUNLOAD", 0, 0, 0, 0,
66 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modunload, 2}, {mo_modunload, 2}}
67};
68
69struct Message modreload_msgtab = {
70 "MODRELOAD", 0, 0, 0, 0,
71 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modreload, 2}, {mo_modreload, 2}}
72};
73
74struct Message modlist_msgtab = {
75 "MODLIST", 0, 0, 0, 0,
76 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modlist, 0}, {mo_modlist, 0}}
77};
78
79struct Message modrestart_msgtab = {
80 "MODRESTART", 0, 0, 0, 0,
81 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modrestart, 0}, {mo_modrestart, 0}}
82};
83
84mapi_clist_av1 modules_clist[] = { &modload_msgtab, &modunload_msgtab, &modreload_msgtab, &modlist_msgtab, &modrestart_msgtab, NULL };
85
86DECLARE_MODULE_AV2(modules, NULL, NULL, modules_clist, NULL, NULL, NULL, NULL, modules_desc);
87
88/* load a module .. */
89static void
90mo_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
91{
92 if(!IsOperAdmin(source_p))
93 {
94 sendto_one(source_p, form_str(ERR_NOPRIVS),
95 me.name, source_p->name, "admin");
96 return;
97 }
98
99 if(parc > 2)
100 {
101 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
102 "ENCAP %s MODLOAD %s", parv[2], parv[1]);
103 if(match(parv[2], me.name) == 0)
104 return;
105 }
106
107 do_modload(source_p, parv[1]);
108}
109
110static void
111me_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
112{
113 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
114 {
115 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
116 "to load modules on this server.");
117 return;
118 }
119
120 do_modload(source_p, parv[1]);
121}
122
123
124/* unload a module .. */
125static void
126mo_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
127{
128 if(!IsOperAdmin(source_p))
129 {
130 sendto_one(source_p, form_str(ERR_NOPRIVS),
131 me.name, source_p->name, "admin");
132 return;
133 }
134
135 if(parc > 2)
136 {
137 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
138 "ENCAP %s MODUNLOAD %s", parv[2], parv[1]);
139 if(match(parv[2], me.name) == 0)
140 return;
141 }
142
143 do_modunload(source_p, parv[1]);
144}
145
146static void
147me_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
148{
149 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
150 {
151 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
152 "to load modules on this server.");
153 return;
154 }
155
156 do_modunload(source_p, parv[1]);
157}
158
159/* unload and load in one! */
160static void
161mo_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
162{
163 if(!IsOperAdmin(source_p))
164 {
165 sendto_one(source_p, form_str(ERR_NOPRIVS),
166 me.name, source_p->name, "admin");
167 return;
168 }
169
170 if(parc > 2)
171 {
172 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
173 "ENCAP %s MODRELOAD %s", parv[2], parv[1]);
174 if(match(parv[2], me.name) == 0)
175 return;
176 }
177
178 do_modreload(source_p, parv[1]);
179}
180
181static void
182me_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
183{
184 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
185 {
186 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
187 "to load modules on this server.");
188 return;
189 }
190
191 do_modreload(source_p, parv[1]);
192}
193
194/* list modules .. */
195static void
196mo_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
197{
198 if(!IsOperAdmin(source_p))
199 {
200 sendto_one(source_p, form_str(ERR_NOPRIVS),
201 me.name, source_p->name, "admin");
202 return;
203 }
204
205 if(parc > 2)
206 {
207 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
208 "ENCAP %s MODLIST %s", parv[2], parv[1]);
209 if(match(parv[2], me.name) == 0)
210 return;
211 }
212
213 do_modlist(source_p, parc > 1 ? parv[1] : 0);
214}
215
216static void
217me_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
218{
219 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
220 {
221 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
222 "to load modules on this server.");
223 return;
224 }
225
226 do_modlist(source_p, parv[1]);
227}
228
229/* unload and reload all modules */
230static void
231mo_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
232{
233 if(!IsOperAdmin(source_p))
234 {
235 sendto_one(source_p, form_str(ERR_NOPRIVS),
236 me.name, source_p->name, "admin");
237 return;
238 }
239
240 if(parc > 1)
241 {
242 sendto_match_servs(source_p, parv[1], CAP_ENCAP, NOCAPS,
243 "ENCAP %s MODRESTART", parv[1]);
244 if(match(parv[1], me.name) == 0)
245 return;
246 }
247
248 do_modrestart(source_p);
249}
250
251static void
252me_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
253{
254 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
255 {
256 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
257 "to load modules on this server.");
258 return;
259 }
260
261 do_modrestart(source_p);
262}
263
264static void
265do_modload(struct Client *source_p, const char *module)
266{
267 char *m_bn = rb_basename(module);
268 int origin;
269
2185c50a 270 if(findmodule_byname(m_bn) != NULL)
78946542
EM
271 {
272 sendto_one_notice(source_p, ":Module %s is already loaded", m_bn);
273 rb_free(m_bn);
274 return;
275 }
276
277 origin = strcmp(module, m_bn) == 0 ? MAPI_ORIGIN_CORE : MAPI_ORIGIN_EXTENSION;
278 load_one_module(module, origin, false);
279
280 rb_free(m_bn);
281}
282
283static void
284do_modunload(struct Client *source_p, const char *module)
285{
2185c50a 286 struct module *mod;
78946542
EM
287 char *m_bn = rb_basename(module);
288
2185c50a 289 if((mod = findmodule_byname(m_bn)) == NULL)
78946542
EM
290 {
291 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
292 rb_free(m_bn);
293 return;
294 }
295
2185c50a 296 if(mod->core)
78946542
EM
297 {
298 sendto_one_notice(source_p, ":Module %s is a core module and may not be unloaded", m_bn);
299 rb_free(m_bn);
300 return;
301 }
302
303 if(unload_one_module(m_bn, true) == false)
304 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
305
306 rb_free(m_bn);
307}
308
309static void
310do_modreload(struct Client *source_p, const char *module)
311{
2185c50a 312 struct module *mod;
78946542
EM
313 int check_core;
314 char *m_bn = rb_basename(module);
315
2185c50a 316 if((mod = findmodule_byname(m_bn)) == NULL)
78946542
EM
317 {
318 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
319 rb_free(m_bn);
320 return;
321 }
322
2185c50a 323 check_core = mod->core;
78946542
EM
324
325 if(unload_one_module(m_bn, true) == false)
326 {
327 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
328 rb_free(m_bn);
329 return;
330 }
331
2185c50a 332 if((load_one_module(m_bn, mod->origin, check_core) == false) && check_core)
78946542
EM
333 {
334 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
335 "Error reloading core module: %s: terminating ircd", m_bn);
336 ilog(L_MAIN, "Error loading core module %s: terminating ircd", m_bn);
337 exit(0);
338 }
339
340 rb_free(m_bn);
341}
342
343static void
344do_modrestart(struct Client *source_p)
345{
78946542
EM
346 sendto_one_notice(source_p, ":Reloading all modules");
347
41390bfe
AJ
348 /*
349 * If a remote MODRESTART is received, m_encap.so will be reloaded,
350 * but ms_encap is in the call stack (it indirectly calls this
351 * function). Also, this function is itself in a module.
352 *
353 * This will go horribly wrong if either module is reloaded to a
354 * different address.
355 *
356 * So, defer the restart to the event loop and return now.
357 */
358 rb_event_addonce("modules_do_restart", modules_do_restart, NULL, 1);
78946542
EM
359}
360
361static void
362do_modlist(struct Client *source_p, const char *pattern)
363{
2185c50a 364 rb_dlink_node *ptr;
78946542 365
2185c50a 366 RB_DLINK_FOREACH(ptr, module_list.head)
78946542 367 {
2185c50a 368 struct module *mod = ptr->data;
78946542 369 const char *origin;
2185c50a 370 switch (mod->origin)
78946542
EM
371 {
372 case MAPI_ORIGIN_EXTENSION:
373 origin = "extension";
374 break;
375 case MAPI_ORIGIN_CORE:
376 origin = "builtin";
377 break;
378 default:
379 origin = "unknown";
380 break;
381 }
382
383 if(pattern)
384 {
2185c50a 385 if(match(pattern, mod->name))
78946542
EM
386 {
387 sendto_one(source_p, form_str(RPL_MODLIST),
388 me.name, source_p->name,
2185c50a
AC
389 mod->name,
390 (unsigned long)(uintptr_t)mod->address, origin,
391 mod->core ? " (core)" : "", mod->version, mod->description);
78946542
EM
392 }
393 }
394 else
395 {
396 sendto_one(source_p, form_str(RPL_MODLIST),
2185c50a
AC
397 me.name, source_p->name, mod->name,
398 (unsigned long)(uintptr_t)mod->address, origin,
399 mod->core ? " (core)" : "", mod->version, mod->description);
78946542
EM
400 }
401 }
402
403 sendto_one(source_p, form_str(RPL_ENDOFMODLIST), me.name, source_p->name);
404}