]>
Commit | Line | Data |
---|---|---|
429cf1b7 | 1 | /* |
a6f63a82 | 2 | * oper-override for solanum. |
429cf1b7 AC |
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 | ||
3fd3d7e1 EM |
25 | static const char override_desc[] = |
26 | "Adds user mode +p, an operator-only user mode that grants temporary privileges to override anything"; | |
27 | ||
429cf1b7 AC |
28 | static void check_umode_change(void *data); |
29 | static void hack_channel_access(void *data); | |
d3076881 | 30 | static void hack_can_join(void *data); |
f69d7feb | 31 | static void hack_can_kick(void *data); |
9101dbcd | 32 | static void hack_can_send(void *data); |
d24434ed | 33 | static void hack_can_invite(void *data); |
5c3014d0 | 34 | static void handle_client_exit(void *data); |
429cf1b7 AC |
35 | |
36 | mapi_hfn_list_av1 override_hfnlist[] = { | |
82436efb EM |
37 | { "umode_changed", check_umode_change }, |
38 | { "get_channel_access", hack_channel_access, HOOK_HIGHEST }, | |
39 | { "can_join", hack_can_join, HOOK_HIGHEST }, | |
40 | { "can_kick", hack_can_kick, HOOK_HIGHEST }, | |
41 | { "can_send", hack_can_send, HOOK_HIGHEST }, | |
42 | { "can_invite", hack_can_invite, HOOK_HIGHEST }, | |
43 | { "client_exit", handle_client_exit }, | |
429cf1b7 AC |
44 | { NULL, NULL } |
45 | }; | |
46 | ||
f69d7feb | 47 | #define CHFL_OVERRIDE 0x0004 |
429cf1b7 AC |
48 | #define IsOperOverride(x) (HasPrivilege((x), "oper:override")) |
49 | ||
50 | struct OverrideSession { | |
51 | rb_dlink_node node; | |
52 | ||
53 | struct Client *client; | |
54 | time_t deadline; | |
55 | }; | |
56 | ||
57 | rb_dlink_list overriding_opers = { NULL, NULL, 0 }; | |
58 | ||
59 | static void | |
d58de35b | 60 | update_session_deadline(struct Client *source_p) |
429cf1b7 | 61 | { |
d58de35b EK |
62 | struct OverrideSession *session_p = NULL; |
63 | rb_dlink_node *n; | |
64 | ||
65 | RB_DLINK_FOREACH(n, overriding_opers.head) | |
429cf1b7 | 66 | { |
d58de35b | 67 | struct OverrideSession *s = n->data; |
429cf1b7 | 68 | |
d58de35b | 69 | if (s->client == source_p) |
429cf1b7 | 70 | { |
d58de35b EK |
71 | session_p = s; |
72 | break; | |
429cf1b7 AC |
73 | } |
74 | } | |
75 | ||
0abb79b7 EK |
76 | if (session_p != NULL) |
77 | { | |
78 | rb_dlinkDelete(&session_p->node, &overriding_opers); | |
79 | } | |
80 | else | |
429cf1b7 AC |
81 | { |
82 | session_p = rb_malloc(sizeof(struct OverrideSession)); | |
83 | session_p->client = source_p; | |
84 | } | |
85 | ||
86 | session_p->deadline = rb_current_time() + 1800; | |
87 | ||
0abb79b7 | 88 | rb_dlinkAddTail(session_p, &session_p->node, &overriding_opers); |
429cf1b7 AC |
89 | } |
90 | ||
91 | static void | |
92 | expire_override_deadlines(void *unused) | |
93 | { | |
94 | rb_dlink_node *n, *tn; | |
95 | ||
96 | RB_DLINK_FOREACH_SAFE(n, tn, overriding_opers.head) | |
97 | { | |
98 | struct OverrideSession *session_p = n->data; | |
99 | ||
0abb79b7 EK |
100 | if (session_p->deadline >= rb_current_time()) |
101 | { | |
429cf1b7 | 102 | break; |
0abb79b7 EK |
103 | } |
104 | else | |
429cf1b7 | 105 | { |
bd2c29f7 | 106 | const char *parv[4] = {session_p->client->name, session_p->client->name, "-p", NULL}; |
429cf1b7 AC |
107 | user_mode(session_p->client, session_p->client, 3, parv); |
108 | } | |
109 | } | |
110 | } | |
111 | ||
112 | static void | |
113 | check_umode_change(void *vdata) | |
114 | { | |
115 | hook_data_umode_changed *data = (hook_data_umode_changed *)vdata; | |
dbeda234 | 116 | bool changed = false; |
429cf1b7 AC |
117 | struct Client *source_p = data->client; |
118 | ||
119 | if (!MyClient(source_p)) | |
120 | return; | |
121 | ||
e5c254d7 JT |
122 | if (data->oldumodes & UMODE_OPER && !IsOper(source_p)) |
123 | source_p->umodes &= ~user_modes['p']; | |
124 | ||
dbeda234 | 125 | changed = ((data->oldumodes ^ source_p->umodes) & user_modes['p']); |
429cf1b7 | 126 | |
429cf1b7 AC |
127 | if (source_p->umodes & user_modes['p']) |
128 | { | |
e5c254d7 JT |
129 | if (!IsOperOverride(source_p)) |
130 | { | |
131 | sendto_one_notice(source_p, ":*** You need oper:override privilege for +p"); | |
132 | source_p->umodes &= ~user_modes['p']; | |
133 | return; | |
134 | } | |
135 | ||
dbeda234 EK |
136 | if (changed) |
137 | { | |
d58de35b | 138 | update_session_deadline(source_p); |
dbeda234 | 139 | } |
429cf1b7 | 140 | } |
dbeda234 | 141 | else if (changed && !(source_p->umodes & user_modes['p'])) |
429cf1b7 AC |
142 | { |
143 | rb_dlink_node *n, *tn; | |
144 | ||
145 | RB_DLINK_FOREACH_SAFE(n, tn, overriding_opers.head) | |
146 | { | |
147 | struct OverrideSession *session_p = n->data; | |
148 | ||
149 | if (session_p->client != source_p) | |
150 | continue; | |
151 | ||
429cf1b7 AC |
152 | rb_dlinkDelete(n, &overriding_opers); |
153 | rb_free(session_p); | |
154 | } | |
155 | } | |
156 | } | |
157 | ||
158 | static void | |
159 | hack_channel_access(void *vdata) | |
160 | { | |
161 | hook_data_channel_approval *data = (hook_data_channel_approval *) vdata; | |
162 | ||
202d4966 AC |
163 | if (data->dir == MODE_QUERY) |
164 | return; | |
165 | ||
429cf1b7 AC |
166 | if (data->approved == CHFL_CHANOP) |
167 | return; | |
168 | ||
169 | if (data->client->umodes & user_modes['p']) | |
170 | { | |
d58de35b | 171 | update_session_deadline(data->client); |
f69d7feb | 172 | data->approved = CHFL_OVERRIDE; |
429cf1b7 | 173 | |
b870a5f8 AC |
174 | /* we only want to report modehacks, which are always non-NULL */ |
175 | if (data->modestr) | |
176 | sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s is using oper-override on %s (modehacking: %s)", | |
177 | get_oper_name(data->client), data->chptr->chname, data->modestr); | |
429cf1b7 AC |
178 | } |
179 | } | |
180 | ||
d3076881 AC |
181 | static void |
182 | hack_can_join(void *vdata) | |
183 | { | |
184 | hook_data_channel *data = (hook_data_channel *) vdata; | |
185 | ||
186 | if (data->approved == 0) | |
187 | return; | |
188 | ||
189 | if (data->client->umodes & user_modes['p']) | |
190 | { | |
d58de35b | 191 | update_session_deadline(data->client); |
d3076881 AC |
192 | data->approved = 0; |
193 | ||
194 | sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s is using oper-override on %s (banwalking)", | |
195 | get_oper_name(data->client), data->chptr->chname); | |
196 | } | |
197 | } | |
198 | ||
f69d7feb AC |
199 | static void |
200 | hack_can_kick(void *vdata) | |
201 | { | |
202 | hook_data_channel_approval *data = (hook_data_channel_approval *) vdata; | |
203 | int alevel; | |
204 | ||
103a1bfd | 205 | alevel = get_channel_access(data->client, data->chptr, data->msptr, data->dir, NULL); |
f69d7feb AC |
206 | if (alevel != CHFL_OVERRIDE) |
207 | return; | |
208 | ||
209 | if (data->client->umodes & user_modes['p']) | |
210 | { | |
d58de35b | 211 | update_session_deadline(data->client); |
f69d7feb AC |
212 | sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s is using oper-override on %s (KICK %s)", |
213 | get_oper_name(data->client), data->chptr->chname, data->target->name); | |
214 | } | |
215 | } | |
216 | ||
9101dbcd AC |
217 | static void |
218 | hack_can_send(void *vdata) | |
219 | { | |
220 | hook_data_channel_approval *data = (hook_data_channel_approval *) vdata; | |
221 | ||
202d4966 AC |
222 | if (data->dir == MODE_QUERY) |
223 | return; | |
224 | ||
9101dbcd AC |
225 | if (data->approved == CAN_SEND_NONOP || data->approved == CAN_SEND_OPV) |
226 | return; | |
227 | ||
228 | if (data->client->umodes & user_modes['p']) | |
229 | { | |
0d165b52 | 230 | data->approved = CAN_SEND_NONOP; |
9101dbcd | 231 | |
b4cdedaa JT |
232 | if (MyClient(data->client)) |
233 | { | |
d58de35b | 234 | update_session_deadline(data->client); |
b4cdedaa JT |
235 | sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s is using oper-override on %s (forcing message)", |
236 | get_oper_name(data->client), data->chptr->chname); | |
237 | } | |
9101dbcd AC |
238 | } |
239 | } | |
240 | ||
d24434ed | 241 | static void |
242 | hack_can_invite(void *vdata) | |
243 | { | |
244 | hook_data_channel_approval *data = vdata; | |
245 | ||
246 | if (data->approved == 0) | |
247 | return; | |
248 | ||
249 | if (data->client->umodes & user_modes['p']) | |
250 | { | |
251 | data->approved = 0; | |
252 | update_session_deadline(data->client); | |
253 | sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s is using oper-override on %s (invite: %s)", | |
254 | get_oper_name(data->client), data->chptr->chname, data->target->name); | |
255 | } | |
256 | } | |
257 | ||
5c3014d0 AC |
258 | static void |
259 | handle_client_exit(void *vdata) | |
260 | { | |
261 | hook_data_client_exit *data = (hook_data_client_exit *) vdata; | |
262 | rb_dlink_node *n, *tn; | |
263 | struct Client *source_p = data->target; | |
264 | ||
265 | RB_DLINK_FOREACH_SAFE(n, tn, overriding_opers.head) | |
266 | { | |
267 | struct OverrideSession *session_p = n->data; | |
268 | ||
269 | if (session_p->client != source_p) | |
270 | continue; | |
271 | ||
272 | rb_dlinkDelete(n, &overriding_opers); | |
273 | rb_free(session_p); | |
55abcbb2 | 274 | } |
5c3014d0 AC |
275 | } |
276 | ||
429cf1b7 AC |
277 | struct ev_entry *expire_override_deadlines_ev = NULL; |
278 | ||
279 | static int | |
280 | _modinit(void) | |
281 | { | |
cc75db3f EK |
282 | rb_dlink_node *ptr; |
283 | ||
429cf1b7 AC |
284 | /* add the usermode to the available slot */ |
285 | user_modes['p'] = find_umode_slot(); | |
286 | construct_umodebuf(); | |
287 | ||
cc75db3f EK |
288 | RB_DLINK_FOREACH(ptr, lclient_list.head) |
289 | { | |
290 | struct Client *client_p = ptr->data; | |
291 | if (IsPerson(client_p) && (client_p->umodes & user_modes['p'])) | |
d58de35b | 292 | update_session_deadline(client_p); |
cc75db3f EK |
293 | } |
294 | ||
bd2c29f7 | 295 | expire_override_deadlines_ev = rb_event_add("expire_override_deadlines", expire_override_deadlines, NULL, 60); |
429cf1b7 AC |
296 | |
297 | return 0; | |
298 | } | |
299 | ||
300 | static void | |
301 | _moddeinit(void) | |
302 | { | |
6637a547 EK |
303 | rb_dlink_node *n, *tn; |
304 | ||
429cf1b7 AC |
305 | /* disable the umode and remove it from the available list */ |
306 | user_modes['p'] = 0; | |
307 | construct_umodebuf(); | |
308 | ||
6637a547 EK |
309 | RB_DLINK_FOREACH_SAFE(n, tn, overriding_opers.head) |
310 | { | |
311 | rb_dlinkDelete(n, &overriding_opers); | |
312 | rb_free(n->data); | |
313 | } | |
314 | ||
429cf1b7 AC |
315 | rb_event_delete(expire_override_deadlines_ev); |
316 | } | |
317 | ||
3fd3d7e1 EM |
318 | DECLARE_MODULE_AV2(override, _modinit, _moddeinit, NULL, NULL, |
319 | override_hfnlist, NULL, NULL, override_desc); |