]> jfr.im git - solanum.git/blob - modules/core/m_modules.c
Unify oper:{global,local}_kill
[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 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 .. */
126 static void
127 mo_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
147 static void
148 me_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! */
161 static void
162 mo_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
182 static void
183 me_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 .. */
196 static void
197 mo_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
217 static void
218 me_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 */
231 static void
232 mo_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
252 static void
253 me_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
265 static void
266 do_modload(struct Client *source_p, const char *module)
267 {
268 char *m_bn = rb_basename(module);
269 int origin;
270
271 if(findmodule_byname(m_bn) != NULL)
272 {
273 sendto_one_notice(source_p, ":Module %s is already loaded", m_bn);
274 rb_free(m_bn);
275 return;
276 }
277
278 mod_remember_clicaps();
279
280 origin = strcmp(module, m_bn) == 0 ? MAPI_ORIGIN_CORE : MAPI_ORIGIN_EXTENSION;
281 load_one_module(module, origin, false);
282
283 mod_notify_clicaps();
284
285 rb_free(m_bn);
286 }
287
288 static void
289 do_modunload(struct Client *source_p, const char *module)
290 {
291 struct module *mod;
292 char *m_bn = rb_basename(module);
293
294 if((mod = findmodule_byname(m_bn)) == NULL)
295 {
296 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
297 rb_free(m_bn);
298 return;
299 }
300
301 if(mod->core)
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
308 mod_remember_clicaps();
309
310 if(unload_one_module(m_bn, true) == false)
311 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
312
313 mod_notify_clicaps();
314
315 rb_free(m_bn);
316 }
317
318 static void
319 do_modreload(struct Client *source_p, const char *module)
320 {
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);
325 }
326
327 static void
328 do_modrestart(struct Client *source_p)
329 {
330 sendto_one_notice(source_p, ":Reloading all modules");
331
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);
343 }
344
345 static void
346 do_modlist(struct Client *source_p, const char *pattern)
347 {
348 rb_dlink_node *ptr;
349
350 RB_DLINK_FOREACH(ptr, module_list.head)
351 {
352 struct module *mod = ptr->data;
353 const char *origin;
354 switch (mod->origin)
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 {
369 if(match(pattern, mod->name))
370 {
371 sendto_one(source_p, form_str(RPL_MODLIST),
372 me.name, source_p->name,
373 mod->name,
374 (unsigned long)(uintptr_t)mod->address, origin,
375 mod->core ? " (core)" : "", mod->version, mod->description);
376 }
377 }
378 else
379 {
380 sendto_one(source_p, form_str(RPL_MODLIST),
381 me.name, source_p->name, mod->name,
382 (unsigned long)(uintptr_t)mod->address, origin,
383 mod->core ? " (core)" : "", mod->version, mod->description);
384 }
385 }
386
387 sendto_one(source_p, form_str(RPL_ENDOFMODLIST), me.name, source_p->name);
388 }