4 * A replacement for Germania's ageing Operservice2
6 * Copyright (C) 2005 Chris Porter.
9 #include "../localuser/localuser.h"
10 #include "../lib/irc_string.h"
11 #include "../lib/strlfunc.h"
12 #include "../lib/version.h"
13 #include "../authext/authext.h"
14 #include "noperserv.h"
15 #include "noperserv_db.h"
16 #include "noperserv_hooks.h"
17 #include "noperserv_policy.h"
25 #define FLAGBUFLEN 100
27 #define NO_FOUND_NICKNAME 1
28 #define NO_FOUND_AUTHNAME 2
32 const flag no_commandflags
[] = {
37 { 'd', __NO_DEVELOPER
},
41 { 'R', __NO_ACCOUNT
},
46 const flag no_userflags
[] = {
51 { 'd', __NO_DEVELOPER
},
56 const flag no_noticeflags
[] = {
57 { 'm', NL_MANAGEMENT
}, /* hello, password, userflags, noticeflags */
58 { 't', NL_TRUSTS
}, /* trust stuff... */
59 { 'k', NL_KICKKILLS
}, /* KICK/KILL commands */
60 { 'I', NL_MISC
}, /* misc commands */
61 { 'g', NL_GLINES
}, /* GLINE commands */
62 { 'G', NL_GLINES_AUTO
}, /* automated gline messages */
63 { 'h', NL_HITS
}, /* Where a gline or kill is set automatically by the bot */
64 { 'c', NL_CLONING
}, /* Clone detection */
65 { 'C', NL_CLEARCHAN
}, /* When someone clearchans */
66 { 'f', NL_FAKEUSERS
}, /* Fakeuser addition */
67 { 'b', NL_BROADCASTS
}, /* Broadcast/mbroadcast/sbroadcast */
68 { 'o', NL_OPERATIONS
}, /* insmod/rmmod/etc */
69 { 'O', NL_OPERING
}, /* when someone opers */
70 { 'n', NL_NOTICES
}, /* turn off to receive notices instead of privmsgs */
71 { 'A', NL_ALL_COMMANDS
}, /* all commands sent */
75 int noperserv_hello(void *sender
, int cargc
, char **cargv
);
76 int noperserv_noticeflags(void *sender
, int cargc
, char **cargv
);
77 int noperserv_userflags(void *sender
, int cargc
, char **cargv
);
78 int noperserv_deluser(void *sender
, int cargc
, char **cargv
);
79 void noperserv_oper_detection(int hooknum
, void *arg
);
80 void noperserv_reply(nick
*np
, char *format
, ...) __attribute__ ((format (printf
, 2, 3)));
85 if(!noperserv_load_db())
88 noperserv_ext
= registernickext("noperserv");
90 noperserv_setup_hooks();
92 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.");
93 registercontrolhelpcmd("userflags", NO_ACCOUNT
, 2, &noperserv_userflags
,
94 "Syntax: USERFLAGS <nickname|#authname> ?modifications?\n"
95 " Views and modifies user permissions.\n"
96 " If no nickname or authname is supplied, you are substituted for it.\n"
97 " If no flags are supplied, flags are just displayed instead of modified."
100 " +s: Staff member\n"
101 " +S: Security team member\n"
102 " +d: NOperserv developer\n"
103 " +t: Trust queue worker\n"
105 " Additional flags may show up in SHOWCOMMANDS but are not userflags as such:\n"
107 " +R: Registered NOperserv user\n"
108 " +O: Must be /OPER'ed\n"
109 " +L: Legacy command\n"
111 registercontrolhelpcmd("noticeflags", NO_ACCOUNT
, 1, &noperserv_noticeflags
,
112 "Syntax: NOTICEFLAGS ?(nickname|#authname)|flags?\n"
113 " This command can view and modify your own notice flags, and view that of other users.\n"
115 " +m: Management (hello, password, userflags, noticeflags)\n"
117 " +k: KICK/KILL commands\n"
118 " +g: GLINE commands\n"
119 " +G: automated gline messages\n"
120 " +h: Shows when glines are set by code (hits)\n"
121 " +c: Clone information\n"
122 " +C: CLEARCHAN command\n"
123 " +f: FAKEUSER commands\n"
124 " +b: BROADCAST commands\n"
125 " +o: Operation commands, such as insmod, rmmod, die, etc\n"
127 " +I: Misc commands (resync, etc)\n"
128 " +n: Sends notices instead of privmsgs\n"
129 " +A: Every single command sent to the service (spammy)\n"
132 registercontrolhelpcmd("deluser", NO_OPERED
| NO_ACCOUNT
, 2, &noperserv_deluser
, "Syntax: DELUSER <nickname|#authname>\nDeletes the specified user.");
133 registerhook(HOOK_NICK_MODEOPER
, &noperserv_oper_detection
);
138 #ifdef BROKEN_DLCLOSE
146 deregisterhook(HOOK_NICK_MODEOPER
, &noperserv_oper_detection
);
148 deregistercontrolcmd("noticeflags", &noperserv_noticeflags
);
149 deregistercontrolcmd("userflags", &noperserv_userflags
);
150 deregistercontrolcmd("noticeflags", &noperserv_noticeflags
);
151 deregistercontrolcmd("hello", &noperserv_hello
);
152 deregistercontrolcmd("deluser", &noperserv_deluser
);
154 noperserv_cleanup_hooks();
156 noperserv_cleanup_db();
158 releasenickext(noperserv_ext
);
162 int noperserv_hello(void *sender
, int cargc
, char **cargv
) {
163 char *newaccount
= NULL
;
166 nick
*np
= (nick
*)sender
, *np2
, *target
= NULL
;
169 newaccount
= np
->authname
;
171 if(cargv
[0][0] == '#') {
172 authname
*a
= getauthbyname(cargv
[0] + 1);
174 controlreply(np
, "Cannot find anyone with that authname on the network.");
177 newaccount
= a
->name
;
179 target
= getnickbynick(cargv
[0]);
181 controlreply(np
, "Supplied nickname is not on the network.");
184 if(!IsAccount(target
)) {
185 controlreply(np
, "Supplied user is not authed with the network.");
188 newaccount
= target
->authname
;
191 au
= noperserv_get_autheduser(newaccount
);
193 controlreply(np
, "Authname already registered.");
197 au
= noperserv_new_autheduser(newaccount
);
199 controlreply(np
, "Memory allocation error.");
203 if(noperserv_get_autheduser_count() == 1) {
204 au
->authlevel
= NO_FIRST_USER_LEVEL
;
205 au
->noticelevel
= NO_FIRST_USER_DEFAULT_NOTICELEVEL
;
207 au
->authlevel
= NO_DEFAULT_LEVEL
;
208 au
->noticelevel
= NO_DEFAULT_NOTICELEVEL
;
211 au
->id
= noperserv_next_autheduser_id();
212 noperserv_update_autheduser(au
);
214 for(i
=0;i
<NICKHASHSIZE
;i
++)
215 for(np2
=nicktable
[i
];np2
;np2
=np2
->next
)
216 if(IsAccount(np2
) && !ircd_strcmp(newaccount
, np2
->authname
)) {
217 noperserv_add_to_autheduser(np2
, au
);
218 controlreply(np2
, "An account has been created for you (auth %s).", au
->authname
->content
);
219 if(NOGetAuthLevel(au
))
220 controlreply(np2
, "User flags: %s", printflags(NOGetAuthLevel(au
), no_userflags
));
221 controlreply(np2
, "Notice flags: %s", printflags(NOGetNoticeLevel(au
), no_noticeflags
));
224 if(ircd_strcmp(np
->authname
, newaccount
)) { /* send a message to the person who HELLO'ed if we haven't already been told */
225 controlreply(np
, "Account created for auth %s.", au
->authname
->content
);
226 if(NOGetAuthLevel(au
))
227 controlreply(np
, "User flags: %s", printflags(NOGetAuthLevel(au
), no_userflags
));
228 controlreply(np
, "Notice flags: %s", printflags(NOGetNoticeLevel(au
), no_noticeflags
));
229 controlreply(np
, "Instructions sent to all authed users.");
230 } else if(au
->nick
&& au
->nick
->next
) { /* if we have already been told, tell the user it was sent to more than themselves */
231 controlreply(np
, "Instructions sent to all authed users.");
234 controlwall(NO_OPERED
, NL_MANAGEMENT
, "%s/%s just HELLO'ed: %s", np
->nick
, np
->authname
, au
->authname
->content
);
238 no_autheduser
*noperserv_autheduser_from_command(nick
*np
, char *command
, int *typefound
, char **returned
) {
240 if(command
[0] == '#') {
241 au
= noperserv_get_autheduser(command
+ 1);
243 controlreply(np
, "Authname not found.");
245 *typefound
= NO_FOUND_AUTHNAME
;
246 *returned
= au
->authname
->content
;
250 nick
*np2
= getnickbynick(command
);
252 controlreply(np
, "Nickname not on the network.");
255 if(!IsAccount(np2
)) {
256 controlreply(np
, "User is not authed with the network.");
259 au
= NOGetAuthedUser(np2
);
261 controlreply(np
, "User does not have an account.");
263 *typefound
= NO_FOUND_NICKNAME
;
264 *returned
= np2
->nick
;
272 int noperserv_noticeflags(void *sender
, int cargc
, char **cargv
) {
273 nick
*np
= (nick
*)sender
;
277 if((cargv
[0][0] == '+') || (cargv
[0][0] == '-')) {
279 au
= NOGetAuthedUser(np
);
280 flag_t fwas
= NOGetNoticeLevel(au
), permittedchanges
= noperserv_policy_permitted_noticeflags(au
);
282 ret
= setflags(&au
->noticelevel
, permittedchanges
, cargv
[0], no_noticeflags
, REJECT_DISALLOWED
| REJECT_UNKNOWN
);
283 if(ret
!= REJECT_UNKNOWN
) {
284 if(ret
== REJECT_DISALLOWED
) {
286 setflags(&fnow
, NL_ALL
, cargv
[0], no_noticeflags
, REJECT_NONE
);
288 controlreply(np
, "No changes made to existing flags.");
290 char ourflags
[FLAGBUFLEN
], ournoticeflags
[FLAGBUFLEN
];
291 controlreply(np
, "Flag alterations denied.");
293 strlcpy(ourflags
, printflags(NOGetAuthLevel(au
), no_userflags
), sizeof(ourflags
));
294 strlcpy(ournoticeflags
, printflags(NOGetNoticeLevel(au
), no_noticeflags
), sizeof(ournoticeflags
));
295 controlwall(NO_OPER
, NL_MANAGEMENT
, "%s/%s (%s) attempted to NOTICEFLAGS (%s): %s", np
->nick
, np
->authname
, ourflags
, ournoticeflags
, printflagdiff(fwas
, fnow
, no_noticeflags
));
298 } else if(ret
== REJECT_NONE
) {
299 if(NOGetNoticeLevel(au
) == fwas
) {
300 controlreply(np
, "No changes made to existing flags.");
302 char ourflags
[FLAGBUFLEN
], ournoticeflags
[FLAGBUFLEN
], diff
[FLAGBUFLEN
* 2 + 1], finalflags
[FLAGBUFLEN
];
303 no_nicklist
*nl
= au
->nick
;
304 noperserv_update_autheduser(au
);
305 controlreply(np
, "Flag alterations complete.");
307 strlcpy(ourflags
, printflags(NOGetAuthLevel(au
), no_userflags
), sizeof(ourflags
));
308 strlcpy(ournoticeflags
, printflags(fwas
, no_noticeflags
), sizeof(ournoticeflags
));
309 strlcpy(diff
, printflagdiff(fwas
, NOGetNoticeLevel(au
), no_noticeflags
), sizeof(diff
));
310 controlwall(NO_OPER
, NL_MANAGEMENT
, "%s/%s (%s) successfully used NOTICEFLAGS (%s): %s", np
->nick
, np
->authname
, ourflags
, ournoticeflags
, diff
);
312 strlcpy(finalflags
, printflags(NOGetNoticeLevel(au
), no_noticeflags
), sizeof(finalflags
));
315 controlreply(nl
->nick
, "!!! %s just used NOTICEFLAGS (%s): %s", np
->nick
, ournoticeflags
, diff
);
316 controlreply(nl
->nick
, "Your notice flags are %s", finalflags
);
321 controlreply(np
, "Unknown flag(s) supplied.");
327 au
= noperserv_autheduser_from_command(np
, cargv
[0], &typefound
, &itemfound
);
331 if(au
!= NOGetAuthedUser(np
)) {
332 controlreply(np
, "Notice flags for %s %s are: %s", typefound
==NO_FOUND_NICKNAME
?"user":"authname", itemfound
, printflags(NOGetNoticeLevel(au
), no_noticeflags
));
337 au
= NOGetAuthedUser(np
);
340 if(!au
) /* shouldn't happen */
343 controlreply(np
, "Your notice flags are: %s", printflags(NOGetNoticeLevel(au
), no_noticeflags
));
349 int noperserv_deluser(void *sender
, int cargc
, char **cargv
) {
350 nick
*np
= (nick
*)sender
;
351 no_autheduser
*target
/* target user */, *au
= NOGetAuthedUser(np
); /* user executing command */
352 char *userreturned
= NULL
; /* nickname or authname of the target, pulled from the db */
353 int typefound
; /* whether it was an authname or a username */
355 char targetflags
[FLAGBUFLEN
], ourflags
[FLAGBUFLEN
], deleteduser
[NOMax(ACCOUNTLEN
, NICKLEN
) + 1];
360 target
= noperserv_autheduser_from_command(np
, cargv
[0], &typefound
, &userreturned
);
364 strlcpy(targetflags
, printflags(NOGetAuthLevel(target
), no_userflags
), sizeof(targetflags
));
365 strlcpy(ourflags
, printflags(NOGetAuthLevel(au
), no_userflags
), sizeof(ourflags
));
367 /* we have to copy it as it might point to an autheduser, which we're about to delete */
368 strlcpy(deleteduser
, userreturned
, sizeof(deleteduser
));
370 /* we have to check if target != au, because if successful policy_modification_permitted just returns the flags we're allowed
371 to modify, if we have no flags we won't be able to delete ourselves */
372 if((target
!= au
) && !noperserv_policy_permitted_modifications(au
, target
)) {
373 controlreply(np
, "Deletion denied.");
374 controlwall(NO_OPER
, NL_MANAGEMENT
, "%s/%s (%s) attempted to DELUSER %s (%s)", np
->nick
, np
->authname
, ourflags
, target
->authname
->content
, targetflags
);
379 for(nl
=target
->nick
;nl
;nl
=nl
->next
)
381 controlreply(nl
->nick
, "!!! %s/%s (%s) just DELUSERed you.", np
->nick
, np
->authname
, ourflags
);
383 noperserv_delete_autheduser(target
);
385 controlwall(NO_OPER
, NL_MANAGEMENT
, "%s/%s (%s) successfully used DELUSER on %s (%s)", np
->nick
, np
->authname
, ourflags
, target
->authname
->content
, targetflags
);
388 controlreply(np
, "You have been deleted.");
390 controlreply(np
, "%s %s deleted.", typefound
==NO_FOUND_AUTHNAME
?"Auth":"User", deleteduser
);
397 /* this command needs LOTS of checking */
398 int noperserv_userflags(void *sender
, int cargc
, char **cargv
) {
399 nick
*np
= (nick
*)sender
;
400 no_autheduser
*au
= NOGetAuthedUser(np
), *target
= NULL
;
401 char *flags
= NULL
, *nicktarget
= NULL
;
406 } else if(cargc
== 1) {
407 if((cargv
[0][0] == '+') || (cargv
[0][0] == '-')) { /* modify our own */
410 } else { /* viewing someone elses */
411 nicktarget
= cargv
[0];
413 } else if(cargc
== 2) {
414 nicktarget
= cargv
[0];
421 target
= noperserv_autheduser_from_command(np
, nicktarget
, &typefound
, &nicktarget
);
428 flag_t permitted
= noperserv_policy_permitted_modifications(au
, target
), fwas
= NOGetAuthLevel(target
), fours
= NOGetAuthLevel(au
);
430 ret
= setflags(&target
->authlevel
, permitted
, flags
, no_userflags
, REJECT_DISALLOWED
| REJECT_UNKNOWN
);
431 if(ret
!= REJECT_UNKNOWN
) {
432 if(ret
== REJECT_DISALLOWED
) {
434 setflags(&fnow
, NO_ALL_FLAGS
, flags
, no_userflags
, REJECT_NONE
);
436 controlreply(np
, "No changes made to existing flags.");
438 char targetflags
[FLAGBUFLEN
], ourflags
[FLAGBUFLEN
];
439 controlreply(np
, "Flag alterations denied.");
441 strlcpy(targetflags
, printflags(fwas
, no_userflags
), sizeof(targetflags
));
442 strlcpy(ourflags
, printflags(fours
, no_userflags
), sizeof(ourflags
));
444 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
));
447 } else if(ret
== REJECT_NONE
) {
448 if(NOGetAuthLevel(target
) == fwas
) {
449 controlreply(np
, "No changes made to existing flags.");
451 char targetflags
[FLAGBUFLEN
], ourflags
[FLAGBUFLEN
], finalflags
[FLAGBUFLEN
];
452 no_nicklist
*nl
= target
->nick
;
454 noperserv_policy_update_noticeflags(fwas
, target
);
455 noperserv_update_autheduser(target
);
457 controlreply(np
, "Flag alterations complete.");
459 strlcpy(targetflags
, printflags(fwas
, no_userflags
), sizeof(targetflags
));
460 strlcpy(ourflags
, printflags(fours
, no_userflags
), sizeof(ourflags
));
462 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
));
464 strlcpy(finalflags
, printflags(NOGetAuthLevel(target
), no_userflags
), sizeof(finalflags
));
467 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
));
468 controlreply(nl
->nick
, "Your user flags are now: %s", finalflags
);
469 controlreply(nl
->nick
, "Your notice flags are now: %s", printflags(target
->noticelevel
, no_noticeflags
));
474 controlreply(np
, "Unknown flag(s) supplied.");
480 controlreply(np
, "User flags for %s %s: %s", typefound
==NO_FOUND_AUTHNAME
?"auth":"user", nicktarget
, printflags(NOGetAuthLevel(target
), no_userflags
));
481 controlreply(np
, "Notice flags for %s %s: %s", typefound
==NO_FOUND_AUTHNAME
?"auth":"user", nicktarget
, printflags(target
->noticelevel
, no_noticeflags
));
483 controlreply(np
, "Your user flags are: %s", printflags(NOGetAuthLevel(target
), no_userflags
));
484 controlreply(np
, "Your notice flags are: %s", printflags(target
->noticelevel
, no_noticeflags
));
490 void noperserv_oper_detection(int hooknum
, void *arg
) {
491 nick
*np
= (nick
*)arg
;
493 if(np
->umodes
& UMODE_OPER
) {
494 if(np
->opername
&& strcmp(np
->opername
->content
, "-")) {
495 controlwall(NO_OPER
, NL_OPERING
, "%s!%s@%s%s%s just OPERed as %s", np
->nick
, np
->ident
, np
->host
->name
->content
, IsAccount(np
)?"/":"", IsAccount(np
)?np
->authname
:"", np
->opername
->content
);
497 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
:"");
500 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
:"");