]> jfr.im git - solanum.git/blob - extensions/override.c
Add .travis.yml
[solanum.git] / extensions / override.c
1 /*
2 * oper-override for charybdis.
3 *
4 * adds usermode +p and has a timer event that is iterated over to disable
5 * usermode +p after a while...
6 *
7 * you need to have oper:override permission on the opers you want to be
8 * able to use this extension.
9 */
10
11 #include "stdinc.h"
12 #include "modules.h"
13 #include "hook.h"
14 #include "client.h"
15 #include "ircd.h"
16 #include "send.h"
17 #include "hash.h"
18 #include "s_conf.h"
19 #include "s_user.h"
20 #include "s_serv.h"
21 #include "numeric.h"
22 #include "privilege.h"
23 #include "s_newconf.h"
24
25 static void check_umode_change(void *data);
26 static void hack_channel_access(void *data);
27 static void hack_can_join(void *data);
28 static void hack_can_kick(void *data);
29 static void hack_can_send(void *data);
30 static void handle_client_exit(void *data);
31
32 mapi_hfn_list_av1 override_hfnlist[] = {
33 { "umode_changed", (hookfn) check_umode_change },
34 { "get_channel_access", (hookfn) hack_channel_access },
35 { "can_join", (hookfn) hack_can_join },
36 { "can_kick", (hookfn) hack_can_kick },
37 { "can_send", (hookfn) hack_can_send },
38 { "client_exit", (hookfn) handle_client_exit },
39 { NULL, NULL }
40 };
41
42 #define CHFL_OVERRIDE 0x0004
43 #define IsOperOverride(x) (HasPrivilege((x), "oper:override"))
44
45 struct OverrideSession {
46 rb_dlink_node node;
47
48 struct Client *client;
49 time_t deadline;
50 };
51
52 rb_dlink_list overriding_opers = { NULL, NULL, 0 };
53
54 static void
55 update_session_deadline(struct Client *source_p, struct OverrideSession *session_p)
56 {
57 if (session_p == NULL)
58 {
59 rb_dlink_node *n;
60
61 RB_DLINK_FOREACH(n, overriding_opers.head)
62 {
63 struct OverrideSession *s = n->data;
64
65 if (s->client == source_p)
66 {
67 session_p = s;
68 break;
69 }
70 }
71 }
72
73 if (session_p == NULL)
74 {
75 session_p = rb_malloc(sizeof(struct OverrideSession));
76 session_p->client = source_p;
77 }
78
79 session_p->deadline = rb_current_time() + 1800;
80
81 rb_dlinkDelete(&session_p->node, &overriding_opers);
82 rb_dlinkAdd(session_p, &session_p->node, &overriding_opers);
83 }
84
85 static void
86 expire_override_deadlines(void *unused)
87 {
88 rb_dlink_node *n, *tn;
89
90 RB_DLINK_FOREACH_SAFE(n, tn, overriding_opers.head)
91 {
92 struct OverrideSession *session_p = n->data;
93
94 if (session_p->deadline > rb_current_time())
95 break;
96 else if (session_p->deadline < rb_current_time())
97 {
98 const char *parv[4] = {session_p->client->name, session_p->client->name, "-p", NULL};
99 user_mode(session_p->client, session_p->client, 3, parv);
100 }
101 }
102 }
103
104 static void
105 check_umode_change(void *vdata)
106 {
107 hook_data_umode_changed *data = (hook_data_umode_changed *)vdata;
108 struct Client *source_p = data->client;
109
110 if (!MyClient(source_p))
111 return;
112
113 if (data->oldumodes & UMODE_OPER && !IsOper(source_p))
114 source_p->umodes &= ~user_modes['p'];
115
116 /* didn't change +p umode, we don't need to do anything */
117 if (!((data->oldumodes ^ source_p->umodes) & user_modes['p']))
118 return;
119
120 if (source_p->umodes & user_modes['p'])
121 {
122 if (!IsOperOverride(source_p))
123 {
124 sendto_one_notice(source_p, ":*** You need oper:override privilege for +p");
125 source_p->umodes &= ~user_modes['p'];
126 return;
127 }
128
129 update_session_deadline(source_p, NULL);
130
131 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s has enabled oper-override (+p)",
132 get_oper_name(source_p));
133 }
134 else if (!(source_p->umodes & user_modes['p']))
135 {
136 rb_dlink_node *n, *tn;
137
138 RB_DLINK_FOREACH_SAFE(n, tn, overriding_opers.head)
139 {
140 struct OverrideSession *session_p = n->data;
141
142 if (session_p->client != source_p)
143 continue;
144
145 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s has disabled oper-override (+p)",
146 get_oper_name(session_p->client));
147
148 rb_dlinkDelete(n, &overriding_opers);
149 rb_free(session_p);
150 }
151 }
152 }
153
154 static void
155 hack_channel_access(void *vdata)
156 {
157 hook_data_channel_approval *data = (hook_data_channel_approval *) vdata;
158
159 if (data->dir == MODE_QUERY)
160 return;
161
162 if (data->approved == CHFL_CHANOP)
163 return;
164
165 if (data->client->umodes & user_modes['p'])
166 {
167 update_session_deadline(data->client, NULL);
168 data->approved = CHFL_OVERRIDE;
169
170 /* we only want to report modehacks, which are always non-NULL */
171 if (data->modestr)
172 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s is using oper-override on %s (modehacking: %s)",
173 get_oper_name(data->client), data->chptr->chname, data->modestr);
174 }
175 }
176
177 static void
178 hack_can_join(void *vdata)
179 {
180 hook_data_channel *data = (hook_data_channel *) vdata;
181
182 if (data->approved == 0)
183 return;
184
185 if (data->client->umodes & user_modes['p'])
186 {
187 update_session_deadline(data->client, NULL);
188 data->approved = 0;
189
190 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s is using oper-override on %s (banwalking)",
191 get_oper_name(data->client), data->chptr->chname);
192 }
193 }
194
195 static void
196 hack_can_kick(void *vdata)
197 {
198 hook_data_channel_approval *data = (hook_data_channel_approval *) vdata;
199 int alevel;
200
201 alevel = get_channel_access(data->client, data->chptr, data->msptr, data->dir, NULL);
202 if (alevel != CHFL_OVERRIDE)
203 return;
204
205 if (data->client->umodes & user_modes['p'])
206 {
207 update_session_deadline(data->client, NULL);
208 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s is using oper-override on %s (KICK %s)",
209 get_oper_name(data->client), data->chptr->chname, data->target->name);
210 }
211 }
212
213 static void
214 hack_can_send(void *vdata)
215 {
216 hook_data_channel_approval *data = (hook_data_channel_approval *) vdata;
217
218 if (data->dir == MODE_QUERY)
219 return;
220
221 if (data->approved == CAN_SEND_NONOP || data->approved == CAN_SEND_OPV)
222 return;
223
224 if (data->client->umodes & user_modes['p'])
225 {
226 data->approved = CAN_SEND_NONOP;
227
228 if (MyClient(data->client))
229 {
230 update_session_deadline(data->client, NULL);
231 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s is using oper-override on %s (forcing message)",
232 get_oper_name(data->client), data->chptr->chname);
233 }
234 }
235 }
236
237 static void
238 handle_client_exit(void *vdata)
239 {
240 hook_data_client_exit *data = (hook_data_client_exit *) vdata;
241 rb_dlink_node *n, *tn;
242 struct Client *source_p = data->target;
243
244 RB_DLINK_FOREACH_SAFE(n, tn, overriding_opers.head)
245 {
246 struct OverrideSession *session_p = n->data;
247
248 if (session_p->client != source_p)
249 continue;
250
251 rb_dlinkDelete(n, &overriding_opers);
252 rb_free(session_p);
253 }
254 }
255
256 struct ev_entry *expire_override_deadlines_ev = NULL;
257
258 static int
259 _modinit(void)
260 {
261 /* add the usermode to the available slot */
262 user_modes['p'] = find_umode_slot();
263 construct_umodebuf();
264
265 expire_override_deadlines_ev = rb_event_add("expire_override_deadlines", expire_override_deadlines, NULL, 60);
266
267 return 0;
268 }
269
270 static void
271 _moddeinit(void)
272 {
273 /* disable the umode and remove it from the available list */
274 user_modes['p'] = 0;
275 construct_umodebuf();
276
277 rb_event_delete(expire_override_deadlines_ev);
278 }
279
280 DECLARE_MODULE_AV1(override, _modinit, _moddeinit, NULL, NULL,
281 override_hfnlist, "$Revision: 3526 $");