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