]> jfr.im git - irc/quakenet/newserv.git/blame - noperserv/noperserv.c
Added misc flag to noperserv.
[irc/quakenet/newserv.git] / noperserv / noperserv.c
CommitLineData
3e3692bf
CP
1/*
2 * NOperserv v0.01
3 *
4 * A replacement for Germania's ageing Operservice2
5 *
6 * Copyright (C) 2005 Chris Porter.
7 */
8
9#include "../localuser/localuser.h"
10#include "../lib/irc_string.h"
d7a70850 11#include "../lib/strlfunc.h"
3e3692bf
CP
12#include "noperserv.h"
13#include "noperserv_db.h"
14#include "noperserv_hooks.h"
15#include "noperserv_policy.h"
16
17#include <stdio.h>
18#include <string.h>
19#include <stdarg.h>
20
21#define FLAGBUFLEN 100
22
23#define NO_FOUND_NICKNAME 1
24#define NO_FOUND_AUTHNAME 2
25
26const flag no_commandflags[] = {
27 { 'o', __NO_OPER },
28 { 't', __NO_TRUST },
29 { 's', __NO_STAFF },
30 { 'S', __NO_SEC },
31 { 'd', __NO_DEVELOPER },
32 { 'L', __NO_LEGACY },
33 { 'O', __NO_OPERED },
34 { 'r', __NO_AUTHED },
35 { 'R', __NO_ACCOUNT },
36 { '\0', 0 }
37 };
38
39const flag no_userflags[] = {
40 { 'o', __NO_OPER },
41 { 't', __NO_TRUST },
42 { 's', __NO_STAFF },
43 { 'S', __NO_SEC },
44 { 'd', __NO_DEVELOPER },
45 { '\0', 0 }
46 };
47
48const flag no_noticeflags[] = {
49 { 'm', NL_MANAGEMENT }, /* hello, password, userflags, noticeflags */
50 { 't', NL_TRUSTS }, /* trust stuff... */
51 { 'k', NL_KICKS }, /* KICK command */
52 { 'K', NL_KILLS }, /* KILL command */
53 { 'g', NL_GLINES }, /* GLINE commands */
54 { 'h', NL_HITS }, /* Where a gline or kill is set automatically by the bot */
55 { 'c', NL_CLONING }, /* Clone detection */
56 { 'C', NL_CLEARCHAN }, /* When someone clearchans */
57 { 'f', NL_FAKEUSERS }, /* Fakeuser addition */
58 { 'b', NL_BROADCASTS }, /* Broadcast/mbroadcast/sbroadcast */
59 { 'o', NL_OPERATIONS }, /* insmod/rmmod/etc */
60 { 'O', NL_OPERING }, /* when someone opers */
61 { 'n', NL_NOTICES }, /* turn off to receive notices instead of privmsgs */
62 { 'A', NL_ALL_COMMANDS }, /* all commands sent */
cc3768c4 63 { 'I', NL_MISC }, /* misc stuff */
3e3692bf
CP
64 { '\0', 0 }
65 };
66
67int noperserv_hello(void *sender, int cargc, char **cargv);
68int noperserv_noticeflags(void *sender, int cargc, char **cargv);
69int noperserv_userflags(void *sender, int cargc, char **cargv);
70int noperserv_deluser(void *sender, int cargc, char **cargv);
71void noperserv_oper_detection(int hooknum, void *arg);
72void noperserv_reply(nick *np, char *format, ...);
73
7a32ca6e
CP
74int init = 0;
75
3e3692bf 76void _init() {
7a32ca6e
CP
77 if(!noperserv_load_db())
78 return;
3e3692bf 79
7a32ca6e 80 noperserv_ext = registernickext("noperserv");
3e3692bf
CP
81
82 noperserv_setup_hooks();
83
84 registercontrolhelpcmd("hello", NO_OPERED | NO_AUTHED, 1, &noperserv_hello, "Syntax: HELLO ?nickname|#authname?\nCreates an account on the service for the specified nick, or if one isn't supplied, your nickname.");
cc3768c4
CP
85 registercontrolhelpcmd("userflags", NO_ACCOUNT, 2, &noperserv_userflags,
86 "Syntax: USERFLAGS <nickname|#authname> ?modifications?\n"
87 " Views and modifies user permissions.\n"
88 " If no nickname or authname is supplied, you are substituted for it.\n"
89 " If no flags are supplied, flags are just displayed instead of modified."
90 " Flags:\n"
91 " +o: Operator\n"
92 " +s: Staff member\n"
93 " +S: Security team member\n"
94 " +d: NOperserv developer\n"
95 " +t: Trust queue worker\n"
96 " Additional flags may show up in SHOWCOMMANDS but are not userflags as such:\n"
97 " +r: Authed user\n"
98 " +d: Registered NOperserv user\n"
99 " +L: Legacy command\n"
100 );
3e3692bf
CP
101 registercontrolhelpcmd("noticeflags", NO_ACCOUNT, 1, &noperserv_noticeflags,
102 "Syntax: NOTICEFLAGS ?(nickname|#authname)|flags?\n"
103 " This command can view and modify your own notice flags, and view that of other users.\n"
104 " Flags:\n"
105 " +m: Management (hello, password, userflags, noticeflags)\n"
106 " +t: Trusts\n"
107 " +k: KICK command\n"
108 " +K: KILL command\n"
109 " +g: GLINE commands\n"
110 " +h: Shows when glines are played automatically (hits)\n"
111 " +c: Clone information\n"
112 " +C: CLEARCHAN command\n"
cc3768c4 113 " +f: FAKEUSER commands\n"
3e3692bf
CP
114 " +b: BROADCAST commands\n"
115 " +o: Operation commands, such as insmod, rmmod, die, etc\n"
116 " +O: /OPER\n"
cc3768c4 117 " +I: Misc commands (resync)\n"
3e3692bf 118 " +n: Sends notices instead of privmsgs\n"
cc3768c4 119 " +A: Every single command sent to the service (spammy)\n"
3e3692bf
CP
120 );
121
122 registercontrolhelpcmd("deluser", NO_OPERED | NO_ACCOUNT, 2, &noperserv_deluser, "Syntax: DELUSER <nickname|#authname>\nDeletes the specified user.");
123 registerhook(HOOK_NICK_MODEOPER, &noperserv_oper_detection);
7a32ca6e
CP
124
125 init = 1;
3e3692bf
CP
126}
127
128#ifdef BROKEN_DLCLOSE
129void __fini() {
130#else
131void _fini() {
132#endif
7a32ca6e
CP
133 if(!init)
134 return;
135
3e3692bf
CP
136 deregisterhook(HOOK_NICK_MODEOPER, &noperserv_oper_detection);
137
138 deregistercontrolcmd("noticeflags", &noperserv_noticeflags);
139 deregistercontrolcmd("userflags", &noperserv_userflags);
140 deregistercontrolcmd("noticeflags", &noperserv_noticeflags);
141
142 noperserv_cleanup_hooks();
143
144 noperserv_cleanup_db();
145
146 releasenickext(noperserv_ext);
147}
148
149/* @test */
150int noperserv_hello(void *sender, int cargc, char **cargv) {
151 char *newaccount;
152 no_autheduser *au;
153 int i;
154 nick *np = (nick *)sender, *np2, *target = NULL;
155
156 if(cargc == 0) {
157 newaccount = np->authname;
158 } else {
159 if(cargv[0][0] == '#') {
160 nick *np2;
161 for(i=0;i<NICKHASHSIZE;i++)
162 for(np2=nicktable[i];np2;np2=np2->next)
163 if(IsAccount(np2) && !ircd_strcmp(cargv[0] + 1, np2->authname)) {
164 target = np2;
165 newaccount = target->authname;
166 break;
167 }
168 if(!target) {
169 controlreply(np, "Cannot find anyone with that authname on the network.");
170 return CMD_ERROR;
171 }
172 } else {
173 target = getnickbynick(cargv[0]);
174 if(!target) {
175 controlreply(np, "Supplied nickname is not on the network.");
176 return CMD_ERROR;
177 }
178 if(!IsAccount(target)) {
179 controlreply(np, "Supplied user is not authed with the network.");
180 return CMD_ERROR;
181 }
182 newaccount = target->authname;
183 }
184 }
185 au = noperserv_get_autheduser(newaccount);
186 if(au) {
187 controlreply(np, "Authname already registered.");
188 return CMD_ERROR;
189 }
190
191 au = noperserv_new_autheduser(newaccount);
192 if(!au) {
193 controlreply(np, "Memory allocation error.");
194 return CMD_ERROR;
195 }
196
197 if(noperserv_get_autheduser_count() == 1) {
198 au->authlevel = NO_FIRST_USER_LEVEL;
199 au->noticelevel = NO_FIRST_USER_DEFAULT_NOTICELEVEL;
200 } else {
201 au->authlevel = NO_DEFAULT_LEVEL;
202 au->noticelevel = NO_DEFAULT_NOTICELEVEL;
203 }
204
205 au->id = noperserv_next_autheduser_id();
206 noperserv_update_autheduser(au);
207
208 for(i=0;i<NICKHASHSIZE;i++)
209 for(np2=nicktable[i];np2;np2=np2->next)
210 if(IsAccount(np2) && !ircd_strcmp(newaccount, np2->authname)) {
211 noperserv_add_to_autheduser(np2, au);
212 controlreply(np2, "An account has been created for you (auth %s).", au->authname->content);
213 if(NOGetAuthLevel(au))
214 controlreply(np2, "User flags: %s", printflags(NOGetAuthLevel(au), no_userflags));
215 controlreply(np2, "Notice flags: %s", printflags(NOGetNoticeLevel(au), no_noticeflags));
216 }
217
218 if(ircd_strcmp(np->authname, newaccount)) { /* send a message to the person who HELLO'ed if we haven't already been told */
219 controlreply(np, "Account created for auth %s.", au->authname->content);
220 if(NOGetAuthLevel(au))
221 controlreply(np, "User flags: %s", printflags(NOGetAuthLevel(au), no_userflags));
222 controlreply(np, "Notice flags: %s", printflags(NOGetNoticeLevel(au), no_noticeflags));
223 controlreply(np, "Instructions sent to all authed users.");
224 } else if(au->nick && au->nick->next) { /* if we have already been told, tell the user it was sent to more than themselves */
225 controlreply(np, "Instructions sent to all authed users.");
226 }
227
228 controlwall(NO_OPERED, NL_MANAGEMENT, "%s/%s just HELLO'ed: %s", np->nick, np->authname, au->authname->content);
229 return CMD_OK;
230}
231
232no_autheduser *noperserv_autheduser_from_command(nick *np, char *command, int *typefound, char **returned) {
233 no_autheduser *au;
234 if(command[0] == '#') {
235 au = noperserv_get_autheduser(command + 1);
236 if(!au) {
237 controlreply(np, "Authname not found.");
238 } else {
239 *typefound = NO_FOUND_AUTHNAME;
240 *returned = au->authname->content;
241 return au;
242 }
243 } else {
244 nick *np2 = getnickbynick(command);
245 if(!np2) {
246 controlreply(np, "Nickname not on the network.");
247 return CMD_OK;
248 }
249 if(!IsAccount(np2)) {
250 controlreply(np, "User is not authed with the network.");
251 return CMD_OK;
252 }
253 au = NOGetAuthedUser(np2);
254 if(!au) {
255 controlreply(np, "User does not have an account.");
256 } else {
257 *typefound = NO_FOUND_NICKNAME;
258 *returned = np2->nick;
259 return au;
260 }
261 }
262
263 return NULL;
264}
265
266int noperserv_noticeflags(void *sender, int cargc, char **cargv) {
267 nick *np = (nick *)sender;
268 no_autheduser *au;
269
270 if(cargc == 1) {
271 if((cargv[0][0] == '+') || (cargv[0][0] == '-')) {
272 int ret;
273 au = NOGetAuthedUser(np);
274 flag_t fwas = NOGetNoticeLevel(au), permittedchanges = noperserv_policy_permitted_noticeflags(au);
275
276 ret = setflags(&au->noticelevel, permittedchanges, cargv[0], no_noticeflags, REJECT_DISALLOWED | REJECT_UNKNOWN);
277 if(ret != REJECT_UNKNOWN) {
278 if(ret == REJECT_DISALLOWED) {
279 flag_t fnow = fwas;
280 setflags(&fnow, NL_ALL, cargv[0], no_noticeflags, REJECT_NONE);
281 if(fnow == fwas) {
282 controlreply(np, "No changes made to existing flags.");
283 } else {
284 char ourflags[FLAGBUFLEN], ournoticeflags[FLAGBUFLEN];
285 controlreply(np, "Flag alterations denied.");
286
287 strlcpy(ourflags, printflags(NOGetAuthLevel(au), no_userflags), sizeof(ourflags));
288 strlcpy(ournoticeflags, printflags(NOGetNoticeLevel(au), no_noticeflags), sizeof(ournoticeflags));
289 controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) attempted to NOTICEFLAGS (%s): %s", np->nick, np->authname, ourflags, ournoticeflags, printflagdiff(fwas, fnow, no_noticeflags));
290 return CMD_ERROR;
291 }
292 } else if(ret == REJECT_NONE) {
293 if(NOGetNoticeLevel(au) == fwas) {
294 controlreply(np, "No changes made to existing flags.");
295 } else {
296 char ourflags[FLAGBUFLEN], ournoticeflags[FLAGBUFLEN], diff[FLAGBUFLEN * 2 + 1], finalflags[FLAGBUFLEN];
297 no_nicklist *nl = au->nick;
298 noperserv_update_autheduser(au);
299 controlreply(np, "Flag alterations complete.");
300
301 strlcpy(ourflags, printflags(NOGetAuthLevel(au), no_userflags), sizeof(ourflags));
302 strlcpy(ournoticeflags, printflags(fwas, no_noticeflags), sizeof(ournoticeflags));
303 strlcpy(diff, printflagdiff(fwas, NOGetNoticeLevel(au), no_noticeflags), sizeof(diff));
304 controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) successfully used NOTICEFLAGS (%s): %s", np->nick, np->authname, ourflags, ournoticeflags, diff);
305
306 strlcpy(finalflags, printflags(NOGetNoticeLevel(au), no_noticeflags), sizeof(finalflags));
307 for(;nl;nl=nl->next)
308 if(nl->nick != np) {
309 controlreply(nl->nick, "!!! %s just used NOTICEFLAGS (%s): %s", np->nick, ournoticeflags, diff);
310 controlreply(nl->nick, "Your notice flags are %s", finalflags);
311 }
312 }
313 }
314 } else {
315 controlreply(np, "Unknown flag(s) supplied.");
316 return CMD_ERROR;
317 }
318 } else {
319 int typefound;
320 char *itemfound;
321 au = noperserv_autheduser_from_command(np, cargv[0], &typefound, &itemfound);
322 if(!au)
323 return CMD_ERROR;
324
325 if(au != NOGetAuthedUser(np)) {
326 controlreply(np, "Notice flags for %s %s are: %s", typefound==NO_FOUND_NICKNAME?"user":"authname", itemfound, printflags(NOGetNoticeLevel(au), no_noticeflags));
327 return CMD_OK;
328 }
329 }
330 } else {
331 au = NOGetAuthedUser(np);
332 }
333
334 if(!au) /* shouldn't happen */
335 return CMD_ERROR;
336
337 controlreply(np, "Your notice flags are: %s", printflags(NOGetNoticeLevel(au), no_noticeflags));
338
339 return CMD_OK;
340}
341
342/* @test */
343int noperserv_deluser(void *sender, int cargc, char **cargv) {
344 nick *np = (nick *)sender;
345 no_autheduser *target /* target user */, *au = NOGetAuthedUser(np); /* user executing command */
346 char *userreturned = NULL; /* nickname or authname of the target, pulled from the db */
347 int typefound; /* whether it was an authname or a username */
348 no_nicklist *nl;
349 char targetflags[FLAGBUFLEN], ourflags[FLAGBUFLEN], deleteduser[NOMax(ACCOUNTLEN, NICKLEN) + 1];
350
351 if(cargc != 1)
352 return CMD_USAGE;
353
354 target = noperserv_autheduser_from_command(np, cargv[0], &typefound, &userreturned);
355 if(!target)
356 return CMD_ERROR;
357
358 strlcpy(targetflags, printflags(NOGetAuthLevel(target), no_userflags), sizeof(targetflags));
359 strlcpy(ourflags, printflags(NOGetAuthLevel(au), no_userflags), sizeof(ourflags));
360
361 /* we have to copy it as it might point to an autheduser, which we're about to delete */
362 strlcpy(deleteduser, userreturned, sizeof(deleteduser));
363
364 /* we have to check if target != au, because if successful policy_modification_permitted just returns the flags we're allowed
365 to modify, if we have no flags we won't be able to delete ourselves */
366 if((target != au) && !noperserv_policy_permitted_modifications(au, target)) {
367 controlreply(np, "Deletion denied.");
368 controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) attempted to DELUSER %s (%s)", np->nick, np->authname, ourflags, target->authname->content, targetflags);
369
370 return CMD_ERROR;
371 }
372
373 for(nl=target->nick;nl;nl=nl->next)
374 if(nl->nick != np)
375 controlreply(nl->nick, "!!! %s/%s (%s) just DELUSERed you.", np->nick, np->authname, ourflags);
376
377 noperserv_delete_autheduser(target);
378
379 controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) successfully used DELUSER on %s (%s)", np->nick, np->authname, ourflags, target->authname->content, targetflags);
380
381 if(target == au) {
382 controlreply(np, "You have been deleted.");
383 } else {
384 controlreply(np, "%s %s deleted.", typefound==NO_FOUND_AUTHNAME?"Auth":"User", deleteduser);
385 }
386
387 return CMD_OK;
388}
389
390/* @test */
391/* this command needs LOTS of checking */
392int noperserv_userflags(void *sender, int cargc, char **cargv) {
393 nick *np = (nick *)sender;
394 no_autheduser *au = NOGetAuthedUser(np), *target = NULL;
395 char *flags = NULL, *nicktarget = NULL;
396 int typefound;
397
398 if(cargc == 0) {
399 target = au;
400 } else if(cargc == 1) {
401 if((cargv[0][0] == '+') || (cargv[0][0] == '-')) { /* modify our own */
402 flags = cargv[0];
403 target = au;
404 } else { /* viewing someone elses */
405 nicktarget = cargv[0];
406 }
407 } else if(cargc == 2) {
408 nicktarget = cargv[0];
409 flags = cargv[1];
410 } else {
411 return CMD_USAGE;
412 }
413
414 if(nicktarget) {
415 target = noperserv_autheduser_from_command(np, nicktarget, &typefound, &nicktarget);
416 if(!target)
417 return CMD_ERROR;
418 }
419
420 if(flags) {
421 int ret;
422 flag_t permitted = noperserv_policy_permitted_modifications(au, target), fwas = NOGetAuthLevel(target), fours = NOGetAuthLevel(au);
423
424 ret = setflags(&target->authlevel, permitted, flags, no_userflags, REJECT_DISALLOWED | REJECT_UNKNOWN);
425 if(ret != REJECT_UNKNOWN) {
426 if(ret == REJECT_DISALLOWED) {
427 flag_t fnow = fwas;
428 setflags(&fnow, NO_ALL_FLAGS, flags, no_userflags, REJECT_NONE);
429 if(fnow == fwas) {
430 controlreply(np, "No changes made to existing flags.");
431 } else {
432 char targetflags[FLAGBUFLEN], ourflags[FLAGBUFLEN];
433 controlreply(np, "Flag alterations denied.");
434
435 strlcpy(targetflags, printflags(fwas, no_userflags), sizeof(targetflags));
436 strlcpy(ourflags, printflags(fours, no_userflags), sizeof(ourflags));
437
438 controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) attempted to use USERFLAGS on %s (%s): %s", np->nick, np->authname, ourflags, target->authname->content, targetflags, printflagdiff(fwas, fnow, no_userflags));
439 return CMD_ERROR;
440 }
441 } else if(ret == REJECT_NONE) {
442 if(NOGetAuthLevel(target) == fwas) {
443 controlreply(np, "No changes made to existing flags.");
444 } else {
445 char targetflags[FLAGBUFLEN], ourflags[FLAGBUFLEN], finalflags[FLAGBUFLEN];
446 no_nicklist *nl = target->nick;
447
448 noperserv_policy_update_noticeflags(fwas, target);
449 noperserv_update_autheduser(target);
450
451 controlreply(np, "Flag alterations complete.");
452
453 strlcpy(targetflags, printflags(fwas, no_userflags), sizeof(targetflags));
454 strlcpy(ourflags, printflags(fours, no_userflags), sizeof(ourflags));
455
456 controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) successfully used USERFLAGS on %s (%s): %s", np->nick, np->authname, ourflags, target->authname->content, targetflags, printflagdiff(fwas, NOGetAuthLevel(target), no_userflags));
457
458 strlcpy(finalflags, printflags(NOGetAuthLevel(target), no_userflags), sizeof(finalflags));
459 for(;nl;nl=nl->next)
460 if(nl->nick != np) {
461 controlreply(nl->nick, "!!! %s/%s (%s) just used USERFLAGS on you (%s): %s", np->nick, np->authname, ourflags, targetflags, printflagdiff(fwas, NOGetAuthLevel(target), no_userflags));
462 controlreply(nl->nick, "Your user flags are now: %s", finalflags);
463 controlreply(nl->nick, "Your notice flags are now: %s", printflags(target->noticelevel, no_noticeflags));
464 }
465 }
466 }
467 } else {
468 controlreply(np, "Unknown flag(s) supplied.");
469 return CMD_ERROR;
470 }
471 }
472
473 if(target != au) {
474 controlreply(np, "User flags for %s %s: %s", typefound==NO_FOUND_AUTHNAME?"auth":"user", nicktarget, printflags(NOGetAuthLevel(target), no_userflags));
475 controlreply(np, "Notice flags for %s %s: %s", typefound==NO_FOUND_AUTHNAME?"auth":"user", nicktarget, printflags(target->noticelevel, no_noticeflags));
476 } else {
477 controlreply(np, "Your user flags are: %s", printflags(NOGetAuthLevel(target), no_userflags));
478 controlreply(np, "Your notice flags are: %s", printflags(target->noticelevel, no_noticeflags));
479 }
480
481 return CMD_OK;
482}
483
484void noperserv_oper_detection(int hooknum, void *arg) {
485 void **args = (void **)arg;
486 nick *np = args[0];
487 char *modestr = args[1];
488 flag_t after = np->umodes;
489
490 setflags(&after, UMODE_ALL, modestr, umodeflags, REJECT_NONE);
491 if(np->umodes & UMODE_OPER) {
492 if(!(after & UMODE_OPER))
493 controlwall(NO_OPER, NL_OPERING, "%s!%s@%s%s%s just DEOPERed", np->nick, np->ident, np->host->name->content, IsAccount(np)?"/":"", IsAccount(np)?np->authname:"");
494 } else {
495 if(after & UMODE_OPER)
496 controlwall(NO_OPER, NL_OPERING, "%s!%s@%s%s%s just OPERed", np->nick, np->ident, np->host->name->content, IsAccount(np)?"/":"", IsAccount(np)?np->authname:"");
497 }
498}