]> jfr.im git - solanum.git/blob - modules/core/m_modules.c
51f453a09e345aabbda59410c71740645b9cd9c5
[solanum.git] / modules / core / m_modules.c
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
37 static const char modules_desc[] = "Provides module management commands";
38
39 static void mo_modload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
40 static void mo_modlist(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
41 static void mo_modreload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
42 static void mo_modunload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
43 static void mo_modrestart(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
44
45 static void me_modload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
46 static void me_modlist(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
47 static void me_modreload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
48 static void me_modunload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
49 static void me_modrestart(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
50
51 static void do_modload(struct Client *, const char *);
52 static void do_modunload(struct Client *, const char *);
53 static void do_modreload(struct Client *, const char *);
54 static void do_modlist(struct Client *, const char *);
55 static void do_modrestart(struct Client *);
56
57 extern void modules_do_reload(void *); /* end of ircd/modules.c */
58 extern void modules_do_restart(void *); /* end of ircd/modules.c */
59
60 struct 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
65 struct 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
70 struct 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
75 struct 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
80 struct 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
85 mapi_clist_av1 modules_clist[] = { &modload_msgtab, &modunload_msgtab, &modreload_msgtab, &modlist_msgtab, &modrestart_msgtab, NULL };
86
87 DECLARE_MODULE_AV2(modules, NULL, NULL, modules_clist, NULL, NULL, NULL, NULL, modules_desc);
88
89 /* load a module .. */
90 static void
91 mo_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
111 static void
112 me_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
113 {
114 do_modload(source_p, parv[1]);
115 }
116
117
118 /* unload a module .. */
119 static void
120 mo_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
121 {
122 if(!IsOperAdmin(source_p))
123 {
124 sendto_one(source_p, form_str(ERR_NOPRIVS),
125 me.name, source_p->name, "admin");
126 return;
127 }
128
129 if(parc > 2)
130 {
131 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
132 "ENCAP %s MODUNLOAD %s", parv[2], parv[1]);
133 if(match(parv[2], me.name) == 0)
134 return;
135 }
136
137 do_modunload(source_p, parv[1]);
138 }
139
140 static void
141 me_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
142 {
143 do_modunload(source_p, parv[1]);
144 }
145
146 /* unload and load in one! */
147 static void
148 mo_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
149 {
150 if(!IsOperAdmin(source_p))
151 {
152 sendto_one(source_p, form_str(ERR_NOPRIVS),
153 me.name, source_p->name, "admin");
154 return;
155 }
156
157 if(parc > 2)
158 {
159 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
160 "ENCAP %s MODRELOAD %s", parv[2], parv[1]);
161 if(match(parv[2], me.name) == 0)
162 return;
163 }
164
165 do_modreload(source_p, parv[1]);
166 }
167
168 static void
169 me_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
170 {
171 do_modreload(source_p, parv[1]);
172 }
173
174 /* list modules .. */
175 static void
176 mo_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
177 {
178 if(!IsOperAdmin(source_p))
179 {
180 sendto_one(source_p, form_str(ERR_NOPRIVS),
181 me.name, source_p->name, "admin");
182 return;
183 }
184
185 if(parc > 2)
186 {
187 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
188 "ENCAP %s MODLIST %s", parv[2], parv[1]);
189 if(match(parv[2], me.name) == 0)
190 return;
191 }
192
193 do_modlist(source_p, parc > 1 ? parv[1] : 0);
194 }
195
196 static void
197 me_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
198 {
199 do_modlist(source_p, parv[1]);
200 }
201
202 /* unload and reload all modules */
203 static void
204 mo_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
205 {
206 if(!IsOperAdmin(source_p))
207 {
208 sendto_one(source_p, form_str(ERR_NOPRIVS),
209 me.name, source_p->name, "admin");
210 return;
211 }
212
213 if(parc > 1)
214 {
215 sendto_match_servs(source_p, parv[1], CAP_ENCAP, NOCAPS,
216 "ENCAP %s MODRESTART", parv[1]);
217 if(match(parv[1], me.name) == 0)
218 return;
219 }
220
221 do_modrestart(source_p);
222 }
223
224 static void
225 me_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
226 {
227 do_modrestart(source_p);
228 }
229
230 static void
231 do_modload(struct Client *source_p, const char *module)
232 {
233 char *m_bn = rb_basename(module);
234 int origin;
235
236 if(findmodule_byname(m_bn) != NULL)
237 {
238 sendto_one_notice(source_p, ":Module %s is already loaded", m_bn);
239 rb_free(m_bn);
240 return;
241 }
242
243 mod_remember_clicaps();
244
245 origin = strcmp(module, m_bn) == 0 ? MAPI_ORIGIN_CORE : MAPI_ORIGIN_EXTENSION;
246 load_one_module(module, origin, false);
247
248 mod_notify_clicaps();
249
250 rb_free(m_bn);
251 }
252
253 static void
254 do_modunload(struct Client *source_p, const char *module)
255 {
256 struct module *mod;
257 char *m_bn = rb_basename(module);
258
259 if((mod = findmodule_byname(m_bn)) == NULL)
260 {
261 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
262 rb_free(m_bn);
263 return;
264 }
265
266 if(mod->core)
267 {
268 sendto_one_notice(source_p, ":Module %s is a core module and may not be unloaded", m_bn);
269 rb_free(m_bn);
270 return;
271 }
272
273 mod_remember_clicaps();
274
275 if(unload_one_module(m_bn, true) == false)
276 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
277
278 mod_notify_clicaps();
279
280 rb_free(m_bn);
281 }
282
283 static void
284 do_modreload(struct Client *source_p, const char *module)
285 {
286 struct modreload *info = rb_malloc(sizeof *info);
287 strcpy(info->module, module);
288 strcpy(info->id, source_p->id);
289 rb_event_addonce("modules_do_reload", modules_do_reload, info, 1);
290 }
291
292 static void
293 do_modrestart(struct Client *source_p)
294 {
295 sendto_one_notice(source_p, ":Reloading all modules");
296
297 /*
298 * If a remote MODRESTART is received, m_encap.so will be reloaded,
299 * but ms_encap is in the call stack (it indirectly calls this
300 * function). Also, this function is itself in a module.
301 *
302 * This will go horribly wrong if either module is reloaded to a
303 * different address.
304 *
305 * So, defer the restart to the event loop and return now.
306 */
307 rb_event_addonce("modules_do_restart", modules_do_restart, NULL, 1);
308 }
309
310 static void
311 do_modlist(struct Client *source_p, const char *pattern)
312 {
313 rb_dlink_node *ptr;
314
315 RB_DLINK_FOREACH(ptr, module_list.head)
316 {
317 struct module *mod = ptr->data;
318 const char *origin;
319 switch (mod->origin)
320 {
321 case MAPI_ORIGIN_EXTENSION:
322 origin = "extension";
323 break;
324 case MAPI_ORIGIN_CORE:
325 origin = "builtin";
326 break;
327 default:
328 origin = "unknown";
329 break;
330 }
331
332 if(pattern)
333 {
334 if(match(pattern, mod->name))
335 {
336 sendto_one(source_p, form_str(RPL_MODLIST),
337 me.name, source_p->name,
338 mod->name,
339 (unsigned long)(uintptr_t)mod->address, origin,
340 mod->core ? " (core)" : "", mod->version, mod->description);
341 }
342 }
343 else
344 {
345 sendto_one(source_p, form_str(RPL_MODLIST),
346 me.name, source_p->name, mod->name,
347 (unsigned long)(uintptr_t)mod->address, origin,
348 mod->core ? " (core)" : "", mod->version, mod->description);
349 }
350 }
351
352 sendto_one(source_p, form_str(RPL_ENDOFMODLIST), me.name, source_p->name);
353 }