]> jfr.im git - solanum.git/blame - modules/core/m_modules.c
Merge pull request #335 from edk0/post-registration-delay
[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
7b641013 57extern void modules_do_reload(void *); /* end of ircd/modules.c */
41390bfe
AJ
58extern void modules_do_restart(void *); /* end of ircd/modules.c */
59
78946542
EM
60struct Message modload_msgtab = {
61 "MODLOAD", 0, 0, 0, 0,
62 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modload, 2}, {mo_modload, 2}}
63};
64
65struct Message modunload_msgtab = {
66 "MODUNLOAD", 0, 0, 0, 0,
67 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modunload, 2}, {mo_modunload, 2}}
68};
69
70struct Message modreload_msgtab = {
71 "MODRELOAD", 0, 0, 0, 0,
72 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modreload, 2}, {mo_modreload, 2}}
73};
74
75struct Message modlist_msgtab = {
76 "MODLIST", 0, 0, 0, 0,
77 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modlist, 0}, {mo_modlist, 0}}
78};
79
80struct Message modrestart_msgtab = {
81 "MODRESTART", 0, 0, 0, 0,
82 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modrestart, 0}, {mo_modrestart, 0}}
83};
84
85mapi_clist_av1 modules_clist[] = { &modload_msgtab, &modunload_msgtab, &modreload_msgtab, &modlist_msgtab, &modrestart_msgtab, NULL };
86
87DECLARE_MODULE_AV2(modules, NULL, NULL, modules_clist, NULL, NULL, NULL, NULL, modules_desc);
88
89/* load a module .. */
90static void
91mo_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
92{
93 if(!IsOperAdmin(source_p))
94 {
95 sendto_one(source_p, form_str(ERR_NOPRIVS),
96 me.name, source_p->name, "admin");
97 return;
98 }
99
100 if(parc > 2)
101 {
102 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
103 "ENCAP %s MODLOAD %s", parv[2], parv[1]);
104 if(match(parv[2], me.name) == 0)
105 return;
106 }
107
108 do_modload(source_p, parv[1]);
109}
110
111static void
112me_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
113{
114 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
115 {
116 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
117 "to load modules on this server.");
118 return;
119 }
120
121 do_modload(source_p, parv[1]);
122}
123
124
125/* unload a module .. */
126static void
127mo_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
128{
129 if(!IsOperAdmin(source_p))
130 {
131 sendto_one(source_p, form_str(ERR_NOPRIVS),
132 me.name, source_p->name, "admin");
133 return;
134 }
135
136 if(parc > 2)
137 {
138 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
139 "ENCAP %s MODUNLOAD %s", parv[2], parv[1]);
140 if(match(parv[2], me.name) == 0)
141 return;
142 }
143
144 do_modunload(source_p, parv[1]);
145}
146
147static void
148me_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
149{
150 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
151 {
152 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
153 "to load modules on this server.");
154 return;
155 }
156
157 do_modunload(source_p, parv[1]);
158}
159
160/* unload and load in one! */
161static void
162mo_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
163{
164 if(!IsOperAdmin(source_p))
165 {
166 sendto_one(source_p, form_str(ERR_NOPRIVS),
167 me.name, source_p->name, "admin");
168 return;
169 }
170
171 if(parc > 2)
172 {
173 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
174 "ENCAP %s MODRELOAD %s", parv[2], parv[1]);
175 if(match(parv[2], me.name) == 0)
176 return;
177 }
178
179 do_modreload(source_p, parv[1]);
180}
181
182static void
183me_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
184{
185 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
186 {
187 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
188 "to load modules on this server.");
189 return;
190 }
191
192 do_modreload(source_p, parv[1]);
193}
194
195/* list modules .. */
196static void
197mo_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
198{
199 if(!IsOperAdmin(source_p))
200 {
201 sendto_one(source_p, form_str(ERR_NOPRIVS),
202 me.name, source_p->name, "admin");
203 return;
204 }
205
206 if(parc > 2)
207 {
208 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
209 "ENCAP %s MODLIST %s", parv[2], parv[1]);
210 if(match(parv[2], me.name) == 0)
211 return;
212 }
213
214 do_modlist(source_p, parc > 1 ? parv[1] : 0);
215}
216
217static void
218me_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
219{
220 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
221 {
222 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
223 "to load modules on this server.");
224 return;
225 }
226
227 do_modlist(source_p, parv[1]);
228}
229
230/* unload and reload all modules */
231static void
232mo_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
233{
234 if(!IsOperAdmin(source_p))
235 {
236 sendto_one(source_p, form_str(ERR_NOPRIVS),
237 me.name, source_p->name, "admin");
238 return;
239 }
240
241 if(parc > 1)
242 {
243 sendto_match_servs(source_p, parv[1], CAP_ENCAP, NOCAPS,
244 "ENCAP %s MODRESTART", parv[1]);
245 if(match(parv[1], me.name) == 0)
246 return;
247 }
248
249 do_modrestart(source_p);
250}
251
252static void
253me_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
254{
255 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
256 {
257 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
258 "to load modules on this server.");
259 return;
260 }
261
262 do_modrestart(source_p);
263}
264
265static void
266do_modload(struct Client *source_p, const char *module)
267{
268 char *m_bn = rb_basename(module);
269 int origin;
270
2185c50a 271 if(findmodule_byname(m_bn) != NULL)
78946542
EM
272 {
273 sendto_one_notice(source_p, ":Module %s is already loaded", m_bn);
274 rb_free(m_bn);
275 return;
276 }
277
28cc8bb9
EK
278 mod_remember_clicaps();
279
78946542
EM
280 origin = strcmp(module, m_bn) == 0 ? MAPI_ORIGIN_CORE : MAPI_ORIGIN_EXTENSION;
281 load_one_module(module, origin, false);
282
28cc8bb9
EK
283 mod_notify_clicaps();
284
78946542
EM
285 rb_free(m_bn);
286}
287
288static void
289do_modunload(struct Client *source_p, const char *module)
290{
2185c50a 291 struct module *mod;
78946542
EM
292 char *m_bn = rb_basename(module);
293
2185c50a 294 if((mod = findmodule_byname(m_bn)) == NULL)
78946542
EM
295 {
296 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
297 rb_free(m_bn);
298 return;
299 }
300
2185c50a 301 if(mod->core)
78946542
EM
302 {
303 sendto_one_notice(source_p, ":Module %s is a core module and may not be unloaded", m_bn);
304 rb_free(m_bn);
305 return;
306 }
307
28cc8bb9
EK
308 mod_remember_clicaps();
309
78946542
EM
310 if(unload_one_module(m_bn, true) == false)
311 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
312
28cc8bb9
EK
313 mod_notify_clicaps();
314
78946542
EM
315 rb_free(m_bn);
316}
317
318static void
319do_modreload(struct Client *source_p, const char *module)
320{
7b641013
EK
321 struct modreload *info = rb_malloc(sizeof *info);
322 strcpy(info->module, module);
323 strcpy(info->id, source_p->id);
324 rb_event_addonce("modules_do_reload", modules_do_reload, info, 1);
78946542
EM
325}
326
327static void
328do_modrestart(struct Client *source_p)
329{
78946542
EM
330 sendto_one_notice(source_p, ":Reloading all modules");
331
41390bfe
AJ
332 /*
333 * If a remote MODRESTART is received, m_encap.so will be reloaded,
334 * but ms_encap is in the call stack (it indirectly calls this
335 * function). Also, this function is itself in a module.
336 *
337 * This will go horribly wrong if either module is reloaded to a
338 * different address.
339 *
340 * So, defer the restart to the event loop and return now.
341 */
342 rb_event_addonce("modules_do_restart", modules_do_restart, NULL, 1);
78946542
EM
343}
344
345static void
346do_modlist(struct Client *source_p, const char *pattern)
347{
2185c50a 348 rb_dlink_node *ptr;
78946542 349
2185c50a 350 RB_DLINK_FOREACH(ptr, module_list.head)
78946542 351 {
2185c50a 352 struct module *mod = ptr->data;
78946542 353 const char *origin;
2185c50a 354 switch (mod->origin)
78946542
EM
355 {
356 case MAPI_ORIGIN_EXTENSION:
357 origin = "extension";
358 break;
359 case MAPI_ORIGIN_CORE:
360 origin = "builtin";
361 break;
362 default:
363 origin = "unknown";
364 break;
365 }
366
367 if(pattern)
368 {
2185c50a 369 if(match(pattern, mod->name))
78946542
EM
370 {
371 sendto_one(source_p, form_str(RPL_MODLIST),
372 me.name, source_p->name,
2185c50a
AC
373 mod->name,
374 (unsigned long)(uintptr_t)mod->address, origin,
375 mod->core ? " (core)" : "", mod->version, mod->description);
78946542
EM
376 }
377 }
378 else
379 {
380 sendto_one(source_p, form_str(RPL_MODLIST),
2185c50a
AC
381 me.name, source_p->name, mod->name,
382 (unsigned long)(uintptr_t)mod->address, origin,
383 mod->core ? " (core)" : "", mod->version, mod->description);
78946542
EM
384 }
385 }
386
387 sendto_one(source_p, form_str(RPL_ENDOFMODLIST), me.name, source_p->name);
388}