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